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