libntpq.c revision 1.1.1.1.6.1 1 /* $NetBSD: libntpq.c,v 1.1.1.1.6.1 2012/04/17 00:03:49 yamt Exp $ */
2
3 /*****************************************************************************
4 *
5 * libntpq.c
6 *
7 * This is the wrapper library for ntpq, the NTP query utility.
8 * This library reuses the sourcecode from ntpq and exports a number
9 * of useful functions in a library that can be linked against applications
10 * that need to query the status of a running ntpd. The whole
11 * communcation is based on mode 6 packets.
12 *
13 ****************************************************************************/
14 #define LIBNTPQ_C
15 #define NO_MAIN_ALLOWED 1
16 /* #define BUILD_AS_LIB Already provided by the Makefile */
17
18 #include "ntpq.c"
19 #include "libntpq.h"
20
21 /* Function Prototypes */
22
23
24 const char *Version = "libntpq 0.3beta";
25
26 /* global variables used for holding snapshots of data */
27 char peervars[NTPQ_BUFLEN];
28 int peervarlen = 0;
29 associd_t peervar_assoc = 0;
30 char clockvars[NTPQ_BUFLEN];
31 int clockvarlen = 0;
32 int clockvar_assoc = 0;
33 char sysvars[NTPQ_BUFLEN];
34 int sysvarlen = 0;
35 char *ntpq_resultbuffer[NTPQ_BUFLEN];
36 unsigned short ntpq_associations[MAXASSOC];
37 struct ntpq_varlist ntpq_varlist[MAXLIST];
38
39 /*****************************************************************************
40 *
41 * ntpq_stripquotes
42 *
43 * Parses a given character buffer srcbuf and removes all quoted
44 * characters. The resulting string is copied to the specified
45 * resultbuf character buffer. E.g. \" will be translated into "
46 *
47 ****************************************************************************
48 * Parameters:
49 * resultbuf char* The resulting string without quoted
50 * characters
51 * srcbuf char* The buffer holding the original string
52 * datalen int The number of bytes stored in srcbuf
53 * maxlen int Max. number of bytes for resultbuf
54 *
55 * Returns:
56 * int number of chars that have been copied to
57 * resultbuf
58 ****************************************************************************/
59
60 int ntpq_stripquotes ( char *resultbuf, char *srcbuf, int datalen, int maxlen )
61 {
62 char* tmpbuf = srcbuf;
63
64 while ( *tmpbuf != 0 )
65 {
66 if ( *tmpbuf == '\"' )
67 {
68 tmpbuf++;
69 continue;
70 }
71
72 if ( *tmpbuf == '\\' )
73 {
74 tmpbuf++;
75 switch ( *tmpbuf )
76 {
77 /* ignore if end of string */
78 case 0:
79 continue;
80 /* skip and do not copy */
81 case '\"': /* quotes */
82 case 'n': /*newline*/
83 case 'r': /*carriage return*/
84 case 'g': /*bell*/
85 case 't': /*tab*/
86 tmpbuf++;
87 continue;
88 }
89 }
90
91 *resultbuf++ = *tmpbuf++;
92
93 }
94
95 *resultbuf = 0;
96 return strlen(resultbuf);
97 }
98
99
100 /*****************************************************************************
101 *
102 * ntpq_getvar
103 *
104 * This function parses a given buffer for a variable/value pair and
105 * copies the value of the requested variable into the specified
106 * varvalue buffer.
107 *
108 * It returns the number of bytes copied or zero for an empty result
109 * (=no matching variable found or empty value)
110 *
111 ****************************************************************************
112 * Parameters:
113 * resultbuf char* The resulting string without quoted
114 * characters
115 * datalen size_t The number of bytes stored in
116 * resultbuf
117 * varname char* Name of the required variable
118 * varvalue char* Where the value of the variable should
119 * be stored
120 * maxlen size_t Max. number of bytes for varvalue
121 *
122 * Returns:
123 * size_t number of chars that have been copied to
124 * varvalue
125 ****************************************************************************/
126
127 size_t
128 ntpq_getvar(
129 const char * resultbuf,
130 size_t datalen,
131 const char * varname,
132 char * varvalue,
133 size_t maxlen)
134 {
135 char * name;
136 char * value;
137 int idatalen;
138
139 value = NULL;
140 idatalen = (int)datalen;
141
142 while (nextvar(&idatalen, &resultbuf, &name, &value)) {
143 if (strcmp(varname, name) == 0) {
144 ntpq_stripquotes(varvalue, value, strlen(value), maxlen);
145
146 return strlen(varvalue);
147 }
148 }
149
150 return 0;
151 }
152
153
154 /*****************************************************************************
155 *
156 * ntpq_queryhost
157 *
158 * Sends a mode 6 query packet to the current open host (see
159 * ntpq_openhost) and stores the requested variable set in the specified
160 * character buffer.
161 * It returns the number of bytes read or zero for an empty result
162 * (=no answer or empty value)
163 *
164 ****************************************************************************
165 * Parameters:
166 * VARSET u_short Which variable set should be
167 * read (PEERVARS or CLOCKVARS)
168 * association int The association ID that should be read
169 * 0 represents the ntpd instance itself
170 * resultbuf char* The resulting string without quoted
171 * characters
172 * maxlen int Max. number of bytes for varvalue
173 *
174 * Returns:
175 * int number of bytes that have been copied to
176 * resultbuf
177 * - OR -
178 * 0 (zero) if no reply has been received or
179 * another failure occured
180 ****************************************************************************/
181
182 int ntpq_queryhost(unsigned short VARSET, unsigned short association, char *resultbuf, int maxlen)
183 {
184 const char *datap;
185 int res;
186 int dsize;
187 u_short rstatus;
188
189 if ( numhosts > 0 )
190 res = doquery(VARSET,association,0,0, (char *)0, &rstatus, &dsize, &datap);
191 else
192 return 0;
193
194 if ( ( res != 0) || ( dsize == 0 ) ) /* no data */
195 return 0;
196
197 if ( dsize > maxlen)
198 dsize = maxlen;
199
200
201 /* fill result resultbuf */
202 memcpy(resultbuf, datap, dsize);
203
204 return dsize;
205 }
206
207
208
209 /*****************************************************************************
210 *
211 * ntpq_openhost
212 *
213 * Sets up a connection to the ntpd instance of a specified host. Note:
214 * There is no real "connection" established because NTP solely works
215 * based on UDP.
216 *
217 ****************************************************************************
218 * Parameters:
219 * hostname char* Hostname/IP of the host running ntpd
220 *
221 * Returns:
222 * int 1 if the host connection could be set up, i.e.
223 * name resolution was succesful and/or IP address
224 * has been validated
225 * - OR -
226 * 0 (zero) if a failure occured
227 ****************************************************************************/
228
229 int ntpq_openhost(char *hostname)
230 {
231 if ( openhost(hostname) )
232 {
233 numhosts = 1;
234 } else {
235 numhosts = 0;
236 }
237
238 return numhosts;
239
240 }
241
242
243 /*****************************************************************************
244 *
245 * ntpq_closehost
246 *
247 * Cleans up a connection by closing the used socket. Should be called
248 * when no further queries are required for the currently used host.
249 *
250 ****************************************************************************
251 * Parameters:
252 * - none -
253 *
254 * Returns:
255 * int 0 (zero) if no host has been opened before
256 * - OR -
257 * the resultcode from the closesocket function call
258 ****************************************************************************/
259
260 int ntpq_closehost(void)
261 {
262 if ( numhosts )
263 return closesocket(sockfd);
264
265 return 0;
266 }
267
268
269 /*****************************************************************************
270 *
271 * ntpq_read_associations
272 *
273 * This function queries the ntp host for its associations and returns the
274 * number of associations found.
275 *
276 * It takes an u_short array as its first parameter, this array holds the
277 * IDs of the associations,
278 * the function will not write more entries than specified with the
279 * max_entries parameter.
280 *
281 * However, if more than max_entries associations were found, the return
282 * value of this function will reflect the real number, even if not all
283 * associations have been stored in the array.
284 *
285 ****************************************************************************
286 * Parameters:
287 * resultbuf u_short*Array that should hold the list of
288 * association IDs
289 * maxentries int maximum number of association IDs that can
290 * be stored in resultbuf
291 *
292 * Returns:
293 * int number of association IDs stored in resultbuf
294 * - OR -
295 * 0 (zero) if a failure occured or no association has
296 * been returned.
297 ****************************************************************************/
298
299 int ntpq_read_associations ( u_short resultbuf[], int max_entries )
300 {
301 int i = 0;
302
303 if (ntpq_dogetassoc()) {
304
305 if(numassoc < max_entries)
306 max_entries = numassoc;
307
308 for (i=0;i<max_entries;i++)
309 resultbuf[i] = assoc_cache[i].assid;
310
311 return numassoc;
312 }
313
314 return 0;
315 }
316
317
318
319
320 /*****************************************************************************
321 *
322 * ntpq_get_assocs
323 *
324 * This function reads the associations of a previously selected (with
325 * ntpq_openhost) NTP host into its own (global) array and returns the
326 * number of associations found.
327 *
328 * The obtained association IDs can be read by using the ntpq_get_assoc_id
329 * function.
330 *
331 ****************************************************************************
332 * Parameters:
333 * - none -
334 *
335 * Returns:
336 * int number of association IDs stored in resultbuf
337 * - OR -
338 * 0 (zero) if a failure occured or no association has
339 * been returned.
340 ****************************************************************************/
341
342 int ntpq_get_assocs ( void )
343 {
344 return ntpq_read_associations( ntpq_associations, MAXASSOC );
345 }
346
347
348 /*****************************************************************************
349 *
350 * ntpq_get_assoc_number
351 *
352 * This function returns for a given Association ID the association number
353 * in the internal association array, which is filled by the ntpq_get_assocs
354 * function.
355 *
356 ****************************************************************************
357 * Parameters:
358 * associd int requested associaton ID
359 *
360 * Returns:
361 * int the number of the association array element that is
362 * representing the given association ID
363 * - OR -
364 * -1 if a failure occured or no matching association
365 * ID has been found
366 ****************************************************************************/
367
368 int ntpq_get_assoc_number ( associd_t associd )
369 {
370 int i;
371
372 for (i=0;i<numassoc;i++) {
373 if (assoc_cache[i].assid == associd)
374 return i;
375 }
376
377 return -1;
378
379 }
380
381
382 /*****************************************************************************
383 *
384 * ntpq_read_assoc_peervars
385 *
386 * This function reads the peervars variable-set of a specified association
387 * from a NTP host and writes it to the result buffer specified, honoring
388 * the maxsize limit.
389 *
390 * It returns the number of bytes written or 0 when the variable-set is
391 * empty or failed to read.
392 *
393 ****************************************************************************
394 * Parameters:
395 * associd int requested associaton ID
396 * resultbuf char* character buffer where the variable set
397 * should be stored
398 * maxsize int the maximum number of bytes that can be
399 * written to resultbuf
400 *
401 * Returns:
402 * int number of chars that have been copied to
403 * resultbuf
404 * - OR -
405 * 0 (zero) if an error occured
406 ****************************************************************************/
407
408 int
409 ntpq_read_assoc_peervars(
410 associd_t associd,
411 char * resultbuf,
412 int maxsize
413 )
414 {
415 const char * datap;
416 int res;
417 int dsize;
418 u_short rstatus;
419
420 res = doquery(CTL_OP_READVAR, associd, 0, 0, NULL, &rstatus,
421 &dsize, &datap);
422 if (res != 0)
423 return 0;
424 if (dsize <= 0) {
425 if (numhosts > 1)
426 fprintf(stderr, "server=%s ", currenthost);
427 fprintf(stderr,
428 "***No information returned for association %d\n",
429 associd);
430
431 return 0;
432 }
433 if (dsize > maxsize)
434 dsize = maxsize;
435 memcpy(resultbuf, datap, dsize);
436
437 return dsize;
438 }
439
440
441
442
443 /*****************************************************************************
444 *
445 * ntpq_read_sysvars
446 *
447 * This function reads the sysvars variable-set from a NTP host and writes it
448 * to the result buffer specified, honoring the maxsize limit.
449 *
450 * It returns the number of bytes written or 0 when the variable-set is empty
451 * or could not be read.
452 *
453 ****************************************************************************
454 * Parameters:
455 * resultbuf char* character buffer where the variable set
456 * should be stored
457 * maxsize int the maximum number of bytes that can be
458 * written to resultbuf
459 *
460 * Returns:
461 * int number of chars that have been copied to
462 * resultbuf
463 * - OR -
464 * 0 (zero) if an error occured
465 ****************************************************************************/
466 size_t
467 ntpq_read_sysvars(
468 char * resultbuf,
469 size_t maxsize
470 )
471 {
472 const char * datap;
473 int res;
474 int i_dsize;
475 size_t dsize;
476 u_short rstatus;
477
478 res = doquery(CTL_OP_READVAR, 0, 0, 0, NULL, &rstatus,
479 &i_dsize, &datap);
480
481 if (res != 0)
482 return 0;
483
484 if (i_dsize == 0) {
485 if (numhosts > 1)
486 fprintf(stderr, "server=%s ", currenthost);
487 fprintf(stderr, "***No sysvar information returned\n");
488
489 return 0;
490 } else {
491 dsize = max(0, i_dsize);
492 dsize = min(dsize, maxsize);
493 memcpy(resultbuf, datap, dsize);
494 }
495
496 return dsize;
497 }
498
499
500 /*****************************************************************************
501 * ntpq_get_assoc_allvars
502 *
503 * With this function all association variables for the specified association
504 * ID can be requested from a NTP host. They are stored internally and can be
505 * read by using the ntpq_get_peervar or ntpq_get_clockvar functions.
506 *
507 * Basically this is only a combination of the ntpq_get_assoc_peervars and
508 * ntpq_get_assoc_clockvars functions.
509 *
510 * It returns 1 if both variable-sets (peervars and clockvars) were
511 * received successfully. If one variable-set or both of them weren't
512 * received,
513 *
514 ****************************************************************************
515 * Parameters:
516 * associd int requested associaton ID
517 *
518 * Returns:
519 * int nonzero if at least one variable set could be read
520 * - OR -
521 * 0 (zero) if an error occured and both variable sets
522 * could not be read
523 ****************************************************************************/
524 int ntpq_get_assoc_allvars( associd_t associd )
525 {
526 return ntpq_get_assoc_peervars ( associd ) &
527 ntpq_get_assoc_clockvars( associd );
528 }
529
530
531
532
533 /*****************************************************************************
534 *
535 * ntpq_get_sysvars
536 *
537 * The system variables of a NTP host can be requested by using this function
538 * and afterwards using ntpq_get_sysvar to read the single variable values.
539 *
540 ****************************************************************************
541 * Parameters:
542 * - none -
543 *
544 * Returns:
545 * int nonzero if the variable set could be read
546 * - OR -
547 * 0 (zero) if an error occured and the sysvars
548 * could not be read
549 ****************************************************************************/
550 int
551 ntpq_get_sysvars(void)
552 {
553 sysvarlen = ntpq_read_sysvars(sysvars, sizeof(sysvars));
554 if (sysvarlen <= 0)
555 return 0;
556 else
557 return 1;
558 }
559
560
561 /*****************************************************************************
562 *
563 * ntp_get_peervar
564 *
565 * This function uses the variable-set which was read by using
566 * ntp_get_peervars and searches for a variable specified with varname. If
567 * such a variable exists, it writes its value into
568 * varvalue (maxlen specifies the size of this target buffer).
569 *
570 ****************************************************************************
571 * Parameters:
572 * varname char* requested variable name
573 * varvalue char* the buffer where the value should go into
574 * maxlen int maximum number of bytes that can be copied to
575 * varvalue
576 *
577 * Returns:
578 * int number of bytes copied to varvalue
579 * - OR -
580 * 0 (zero) if an error occured or the variable could
581 * not be found
582 ****************************************************************************/
583 int ntpq_get_peervar( const char *varname, char *varvalue, int maxlen)
584 {
585 return ( ntpq_getvar(peervars,peervarlen,varname,varvalue,maxlen) );
586 }
587
588
589
590 /*****************************************************************************
591 *
592 * ntpq_get_assoc_peervars
593 *
594 * This function requests the peer variables of the specified association
595 * from a NTP host. In order to access the variable values, the function
596 * ntpq_get_peervar must be used.
597 *
598 ****************************************************************************
599 * Parameters:
600 * associd int requested associaton ID
601 *
602 * Returns:
603 * int 1 (one) if the peervars have been read
604 * - OR -
605 * 0 (zero) if an error occured and the variable set
606 * could not be read
607 ****************************************************************************/
608 int
609 ntpq_get_assoc_peervars(
610 associd_t associd
611 )
612 {
613 peervarlen = ntpq_read_assoc_peervars(associd, peervars,
614 sizeof(peervars));
615 if (peervarlen <= 0) {
616 peervar_assoc = 0;
617
618 return 0;
619 }
620 peervar_assoc = associd;
621
622 return 1;
623 }
624
625
626 /*****************************************************************************
627 *
628 * ntp_read_assoc_clockvars
629 *
630 * This function reads the clockvars variable-set of a specified association
631 * from a NTP host and writes it to the result buffer specified, honoring
632 * the maxsize limit.
633 *
634 * It returns the number of bytes written or 0 when the variable-set is
635 * empty or failed to read.
636 *
637 ****************************************************************************
638 * Parameters:
639 * associd int requested associaton ID
640 * resultbuf char* character buffer where the variable set
641 * should be stored
642 * maxsize int the maximum number of bytes that can be
643 * written to resultbuf
644 *
645 * Returns:
646 * int number of chars that have been copied to
647 * resultbuf
648 * - OR -
649 * 0 (zero) if an error occured
650 ****************************************************************************/
651
652 int
653 ntpq_read_assoc_clockvars(
654 associd_t associd,
655 char * resultbuf,
656 int maxsize
657 )
658 {
659 const char *datap;
660 int res;
661 int dsize;
662 u_short rstatus;
663
664 res = ntpq_doquerylist(ntpq_varlist, CTL_OP_READCLOCK, associd,
665 0, &rstatus, &dsize, &datap);
666 if (res != 0)
667 return 0;
668
669 if (dsize == 0) {
670 if (numhosts > 1) /* no information returned from server */
671 return 0;
672 } else {
673 if (dsize > maxsize)
674 dsize = maxsize;
675 memcpy(resultbuf, datap, dsize);
676 }
677
678 return dsize;
679 }
680
681
682
683 /*****************************************************************************
684 *
685 * ntpq_get_assoc_clocktype
686 *
687 * This function returns a clocktype value for a given association number
688 * (not ID!):
689 *
690 * NTP_CLOCKTYPE_UNKNOWN Unknown clock type
691 * NTP_CLOCKTYPE_BROADCAST Broadcast server
692 * NTP_CLOCKTYPE_LOCAL Local clock
693 * NTP_CLOCKTYPE_UNICAST Unicast server
694 * NTP_CLOCKTYPE_MULTICAST Multicast server
695 *
696 ****************************************************************************/
697 int
698 ntpq_get_assoc_clocktype(
699 int assoc_index
700 )
701 {
702 associd_t associd;
703 int i;
704 int rc;
705 sockaddr_u dum_store;
706 char dstadr[LENHOSTNAME];
707 char resultbuf[NTPQ_BUFLEN];
708
709 if (assoc_index < 0 || assoc_index >= numassoc)
710 return -1;
711
712 associd = assoc_cache[assoc_index].assid;
713 if (associd == peervar_assoc) {
714 rc = ntpq_get_peervar("dstadr", dstadr, sizeof(dstadr));
715 } else {
716 i = ntpq_read_assoc_peervars(associd, resultbuf,
717 sizeof(resultbuf));
718 if (i <= 0)
719 return -1;
720 rc = ntpq_getvar(resultbuf, i, "dstadr", dstadr,
721 sizeof(dstadr));
722 }
723
724 if (0 != rc && decodenetnum(dstadr, &dum_store))
725 return ntpq_decodeaddrtype(&dum_store);
726
727 return -1;
728 }
729
730
731
732 /*****************************************************************************
733 *
734 * ntpq_get_assoc_clockvars
735 *
736 * With this function the clock variables of the specified association are
737 * requested from a NTP host. This makes only sense for associations with
738 * the type 'l' (Local Clock) and you should check this with
739 * ntpq_get_assoc_clocktype for each association, before you use this function
740 * on it.
741 *
742 ****************************************************************************
743 * Parameters:
744 * associd int requested associaton ID
745 *
746 * Returns:
747 * int 1 (one) if the clockvars have been read
748 * - OR -
749 * 0 (zero) if an error occured and the variable set
750 * could not be read
751 ****************************************************************************/
752 int ntpq_get_assoc_clockvars( associd_t associd )
753 {
754 if (NTP_CLOCKTYPE_LOCAL != ntpq_get_assoc_clocktype(
755 ntpq_get_assoc_number(associd)))
756 return 0;
757 clockvarlen = ntpq_read_assoc_clockvars( associd, clockvars,
758 sizeof(clockvars) );
759 if ( clockvarlen <= 0 ) {
760 clockvar_assoc = 0;
761 return 0;
762 } else {
763 clockvar_assoc = associd;
764 return 1;
765 }
766 }
767
768
769