3 /*****************************************************************************
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.
13 ****************************************************************************/
15 #define NO_MAIN_ALLOWED 1
16 /* #define BUILD_AS_LIB Already provided by the Makefile */
21 /* Function Prototypes */
22 int ntpq_openhost(char *);
23 int ntpq_closehost(void);
24 int ntpq_queryhost(unsigned short VARSET
, unsigned short association
, char *resultbuf
, int maxlen
);
25 int ntpq_stripquotes ( char *resultbuf
, char *srcbuf
, int datalen
, int maxlen
);
26 int ntpq_queryhost_peervars(unsigned short association
, char *resultbuf
, int maxlen
);
27 int ntpq_getvar( char *resultbuf
, int datalen
, const char *varname
, char *varvalue
, int maxlen
);
28 int ntpq_get_peervar( const char *varname
, char *varvalue
, int maxlen
);
29 int ntpq_read_associations ( unsigned short resultbuf
[], int max_entries
);
30 int ntpq_read_sysvars( char *resultbuf
, int maxsize
);
31 int ntpq_get_assoc_allvars( int associd
);
32 int ntpq_get_sysvars( void );
33 int ntpq_get_assocs ( void );
34 int ntpq_read_assoc_peervars( int associd
, char *resultbuf
, int maxsize
);
35 int ntpq_read_assoc_clockvars( int associd
, char *resultbuf
, int maxsize
);
36 int ntpq_get_assoc_number ( int associd
);
37 int ntpq_get_assoc_peervars( int associd
);
38 int ntpq_get_assoc_clockvars( int associd
);
39 int ntpq_get_assoc_clocktype ( int assoc_number
);
42 const char *Version
= "libntpq 0.3beta";
44 /* global variables used for holding snapshots of data */
45 char peervars
[NTPQ_BUFLEN
];
47 int peervar_assoc
= 0;
48 char clockvars
[NTPQ_BUFLEN
];
50 int clockvar_assoc
= 0;
51 char sysvars
[NTPQ_BUFLEN
];
53 char *ntpq_resultbuffer
[NTPQ_BUFLEN
];
54 unsigned short ntpq_associations
[MAXASSOC
];
56 struct ntpq_varlist ntpq_varlist
[MAXLIST
];
58 /*****************************************************************************
62 * Parses a given character buffer srcbuf and removes all quoted
63 * characters. The resulting string is copied to the specified
64 * resultbuf character buffer. E.g. \" will be translated into "
66 ****************************************************************************
68 * resultbuf char* The resulting string without quoted
70 * srcbuf char* The buffer holding the original string
71 * datalen int The number of bytes stored in srcbuf
72 * maxlen int Max. number of bytes for resultbuf
75 * int number of chars that have been copied to
77 ****************************************************************************/
79 int ntpq_stripquotes ( char *resultbuf
, char *srcbuf
, int datalen
, int maxlen
)
81 char* tmpbuf
= srcbuf
;
83 while ( *tmpbuf
!= 0 )
85 if ( *tmpbuf
== '\"' )
91 if ( *tmpbuf
== '\\' )
96 /* ignore if end of string */
99 /* skip and do not copy */
100 case '\"': /* quotes */
101 case 'n': /*newline*/
102 case 'r': /*carriage return*/
110 *resultbuf
++ = *tmpbuf
++;
115 return strlen(resultbuf
);
119 /*****************************************************************************
123 * This function parses a given buffer for a variable/value pair and
124 * copies the value of the requested variable into the specified
127 * It returns the number of bytes copied or zero for an empty result
128 * (=no matching variable found or empty value)
130 ****************************************************************************
132 * resultbuf char* The resulting string without quoted
134 * datalen int The number of bytes stored in
136 * varname char* Name of the required variable
137 * varvalue char* Where the value of the variable should
139 * maxlen int Max. number of bytes for varvalue
142 * int number of chars that have been copied to
144 ****************************************************************************/
146 int ntpq_getvar( char *resultbuf
, int datalen
, const char *varname
, char *varvalue
, int maxlen
)
151 while (nextvar(&datalen
, &resultbuf
, &name
, &value
)) {
153 if ( strcmp(varname
, name
) == 0 ) {
154 ntpq_stripquotes(varvalue
,value
,strlen(value
),maxlen
);
155 return strlen(varvalue
);
163 /*****************************************************************************
167 * Sends a mode 6 query packet to the current open host (see
168 * ntpq_openhost) and stores the requested variable set in the specified
170 * It returns the number of bytes read or zero for an empty result
171 * (=no answer or empty value)
173 ****************************************************************************
175 * VARSET u_short Which variable set should be
176 * read (PEERVARS or CLOCKVARS)
177 * association int The association ID that should be read
178 * 0 represents the ntpd instance itself
179 * resultbuf char* The resulting string without quoted
181 * maxlen int Max. number of bytes for varvalue
184 * int number of bytes that have been copied to
187 * 0 (zero) if no reply has been received or
188 * another failure occured
189 ****************************************************************************/
191 int ntpq_queryhost(unsigned short VARSET
, unsigned short association
, char *resultbuf
, int maxlen
)
199 res
= doquery(VARSET
,association
,0,0, (char *)0, &rstatus
, &dsize
, &datap
);
203 if ( ( res
!= 0) || ( dsize
== 0 ) ) /* no data */
210 /* fill result resultbuf */
211 memcpy(resultbuf
, datap
, dsize
);
218 /*****************************************************************************
222 * Sets up a connection to the ntpd instance of a specified host. Note:
223 * There is no real "connection" established because NTP solely works
226 ****************************************************************************
228 * hostname char* Hostname/IP of the host running ntpd
231 * int 1 if the host connection could be set up, i.e.
232 * name resolution was succesful and/or IP address
235 * 0 (zero) if a failure occured
236 ****************************************************************************/
238 int ntpq_openhost(char *hostname
)
240 if ( openhost(hostname
) )
252 /*****************************************************************************
256 * Cleans up a connection by closing the used socket. Should be called
257 * when no further queries are required for the currently used host.
259 ****************************************************************************
264 * int 0 (zero) if no host has been opened before
266 * the resultcode from the closesocket function call
267 ****************************************************************************/
269 int ntpq_closehost(void)
272 return closesocket(sockfd
);
278 /*****************************************************************************
280 * ntpq_read_associations
282 * This function queries the ntp host for its associations and returns the
283 * number of associations found.
285 * It takes an u_short array as its first parameter, this array holds the
286 * IDs of the associations,
287 * the function will not write more entries than specified with the
288 * max_entries parameter.
290 * However, if more than max_entries associations were found, the return
291 * value of this function will reflect the real number, even if not all
292 * associations have been stored in the array.
294 ****************************************************************************
296 * resultbuf u_short*Array that should hold the list of
298 * maxentries int maximum number of association IDs that can
299 * be stored in resultbuf
302 * int number of association IDs stored in resultbuf
304 * 0 (zero) if a failure occured or no association has
306 ****************************************************************************/
308 int ntpq_read_associations ( u_short resultbuf
[], int max_entries
)
312 if (ntpq_dogetassoc()) {
314 if(numassoc
< max_entries
)
315 max_entries
= numassoc
;
317 for (i
=0;i
<max_entries
;i
++)
318 resultbuf
[i
] = assoc_cache
[i
].assid
;
329 /*****************************************************************************
333 * This function reads the associations of a previously selected (with
334 * ntpq_openhost) NTP host into its own (global) array and returns the
335 * number of associations found.
337 * The obtained association IDs can be read by using the ntpq_get_assoc_id
340 ****************************************************************************
345 * int number of association IDs stored in resultbuf
347 * 0 (zero) if a failure occured or no association has
349 ****************************************************************************/
351 int ntpq_get_assocs ( void )
353 return ntpq_read_associations( ntpq_associations
, MAXASSOC
);
357 /*****************************************************************************
359 * ntpq_get_assoc_number
361 * This function returns for a given Association ID the association number
362 * in the internal association array, which is filled by the ntpq_get_assocs
365 ****************************************************************************
367 * associd int requested associaton ID
370 * int the number of the association array element that is
371 * representing the given association ID
373 * -1 if a failure occured or no matching association
375 ****************************************************************************/
377 int ntpq_get_assoc_number ( int associd
)
381 for (i
=0;i
<numassoc
;i
++) {
382 if (assoc_cache
[i
].assid
== associd
)
391 /*****************************************************************************
393 * ntpq_read_assoc_peervars
395 * This function reads the peervars variable-set of a specified association
396 * from a NTP host and writes it to the result buffer specified, honoring
399 * It returns the number of bytes written or 0 when the variable-set is
400 * empty or failed to read.
402 ****************************************************************************
404 * associd int requested associaton ID
405 * resultbuf char* character buffer where the variable set
407 * maxsize int the maximum number of bytes that can be
408 * written to resultbuf
411 * int number of chars that have been copied to
414 * 0 (zero) if an error occured
415 ****************************************************************************/
417 int ntpq_read_assoc_peervars( int associd
, char *resultbuf
, int maxsize
)
426 char value
[NTPQ_BUFLEN
];
429 res
= doquery(CTL_OP_READVAR
, associd
, 0, 0, (char *)0, &rstatus
,
439 (void) fprintf(stderr
, "server=%s ", currenthost
);
440 (void) fprintf(stderr
,
441 "***No information returned for association %d\n",
445 if ( dsize
> maxsize
)
448 memcpy(resultbuf
,datap
,dsize
);
449 resultbuf
[dsize
]=0x0;
451 ntpq_getvar(resultbuf
, dsize
, "rec", value
, sizeof (value
) );
453 if (!decodets(value
, &rec
))
456 memcpy(resultbuf
,value
,maxsize
);
457 resultbuf
[dsize
]=0x0;
458 dsize
=strlen(resultbuf
);
469 /*****************************************************************************
473 * This function reads the sysvars variable-set from a NTP host and writes it
474 * to the result buffer specified, honoring the maxsize limit.
476 * It returns the number of bytes written or 0 when the variable-set is empty
477 * or could not be read.
479 ****************************************************************************
481 * resultbuf char* character buffer where the variable set
483 * maxsize int the maximum number of bytes that can be
484 * written to resultbuf
487 * int number of chars that have been copied to
490 * 0 (zero) if an error occured
491 ****************************************************************************/
492 int ntpq_read_sysvars( char *resultbuf
, int maxsize
)
500 res
= doquery(CTL_OP_READVAR
, 0, 0, 0, (char *)0, &rstatus
,
508 (void) fprintf(stderr
, "server=%s ", currenthost
);
509 (void) fprintf(stderr
,
510 "***No sysvar information returned \n");
513 if ( dsize
> maxsize
)
516 memcpy(resultbuf
,datap
,dsize
);
524 /*****************************************************************************
525 * ntpq_get_assoc_allvars
527 * With this function all association variables for the specified association
528 * ID can be requested from a NTP host. They are stored internally and can be
529 * read by using the ntpq_get_peervar or ntpq_get_clockvar functions.
531 * Basically this is only a combination of the ntpq_get_assoc_peervars and
532 * ntpq_get_assoc_clockvars functions.
534 * It returns 1 if both variable-sets (peervars and clockvars) were
535 * received successfully. If one variable-set or both of them weren't
538 ****************************************************************************
540 * associd int requested associaton ID
543 * int nonzero if at least one variable set could be read
545 * 0 (zero) if an error occured and both variable sets
547 ****************************************************************************/
548 int ntpq_get_assoc_allvars( int associd
)
550 return ( ntpq_get_assoc_peervars ( associd
) & ntpq_get_assoc_clockvars( associd
) );
556 /*****************************************************************************
560 * The system variables of a NTP host can be requested by using this function
561 * and afterwards using ntpq_get_sysvar to read the single variable values.
563 ****************************************************************************
568 * int nonzero if the variable set could be read
570 * 0 (zero) if an error occured and the sysvars
572 ****************************************************************************/
573 int ntpq_get_sysvars( void )
575 sysvarlen
= ( ntpq_read_sysvars( sysvars
, sizeof(sysvars
)) );
576 if ( sysvarlen
<= 0 ) {
584 /*****************************************************************************
588 * This function uses the variable-set which was read by using
589 * ntp_get_peervars and searches for a variable specified with varname. If
590 * such a variable exists, it writes its value into
591 * varvalue (maxlen specifies the size of this target buffer).
593 ****************************************************************************
595 * varname char* requested variable name
596 * varvalue char* the buffer where the value should go into
597 * maxlen int maximum number of bytes that can be copied to
601 * int number of bytes copied to varvalue
603 * 0 (zero) if an error occured or the variable could
605 ****************************************************************************/
606 int ntpq_get_peervar( const char *varname
, char *varvalue
, int maxlen
)
608 return ( ntpq_getvar(peervars
,peervarlen
,varname
,varvalue
,maxlen
) );
613 /*****************************************************************************
615 * ntpq_get_assoc_peervars
617 * This function requests the peer variables of the specified association
618 * from a NTP host. In order to access the variable values, the function
619 * ntpq_get_peervar must be used.
621 ****************************************************************************
623 * associd int requested associaton ID
626 * int 1 (one) if the peervars have been read
628 * 0 (zero) if an error occured and the variable set
630 ****************************************************************************/
631 int ntpq_get_assoc_peervars( int associd
)
633 peervarlen
= ( ntpq_read_assoc_peervars( associd
, peervars
, sizeof(peervars
)) );
634 if ( peervarlen
<= 0 ) {
638 peervar_assoc
= associd
;
644 /*****************************************************************************
646 * ntp_read_assoc_clockvars
648 * This function reads the clockvars variable-set of a specified association
649 * from a NTP host and writes it to the result buffer specified, honoring
652 * It returns the number of bytes written or 0 when the variable-set is
653 * empty or failed to read.
655 ****************************************************************************
657 * associd int requested associaton ID
658 * resultbuf char* character buffer where the variable set
660 * maxsize int the maximum number of bytes that can be
661 * written to resultbuf
664 * int number of chars that have been copied to
667 * 0 (zero) if an error occured
668 ****************************************************************************/
670 int ntpq_read_assoc_clockvars( int associd
, char *resultbuf
, int maxsize
)
678 res
= ntpq_doquerylist(ntpq_varlist
, CTL_OP_READCLOCK
, associd
, 0, &rstatus
, &dsize
, &datap
);
684 if (numhosts
> 1) /* no information returned from server */
687 if ( dsize
> maxsize
)
690 memcpy(resultbuf
,datap
,dsize
);
698 /*****************************************************************************
700 * ntpq_get_assoc_clocktype
702 * This function returns a clocktype value for a given association number
705 * NTP_CLOCKTYPE_UNKNOWN Unknown clock type
706 * NTP_CLOCKTYPE_BROADCAST Broadcast server
707 * NTP_CLOCKTYPE_LOCAL Local clock
708 * NTP_CLOCKTYPE_UNICAST Unicast server
709 * NTP_CLOCKTYPE_MULTICAST Multicast server
711 ****************************************************************************/
712 int ntpq_get_assoc_clocktype ( int assoc_number
)
716 sockaddr_u dum_store
;
717 char value
[LENHOSTNAME
];
718 char resultbuf
[1024];
721 if ( assoc_number
< 0 || assoc_number
> numassoc
) {
724 if ( peervar_assoc
!= assoc_cache
[assoc_number
].assid
) {
726 i
=ntpq_read_assoc_peervars(assoc_cache
[assoc_number
].assid
, resultbuf
, sizeof(resultbuf
));
731 rc
= ntpq_getvar(resultbuf
, i
, "dstadr", value
, LENHOSTNAME
);
736 rc
= ntpq_get_peervar("dstadr",value
,LENHOSTNAME
);
741 if (decodenetnum(value
, &dum_store
)) {
742 type
= ntpq_decodeaddrtype(&dum_store
);
756 /*****************************************************************************
758 * ntpq_get_assoc_clockvars
760 * With this function the clock variables of the specified association are
761 * requested from a NTP host. This makes only sense for associations with
762 * the type 'l' (Local Clock) and you should check this with
763 * ntpq_get_assoc_clocktype for each association, before you use this function
766 ****************************************************************************
768 * associd int requested associaton ID
771 * int 1 (one) if the clockvars have been read
773 * 0 (zero) if an error occured and the variable set
775 ****************************************************************************/
776 int ntpq_get_assoc_clockvars( int associd
)
779 if ( ntpq_get_assoc_clocktype(ntpq_get_assoc_number(associd
)) != NTP_CLOCKTYPE_LOCAL
)
782 clockvarlen
= ( ntpq_read_assoc_clockvars( associd
, clockvars
, sizeof(clockvars
)) );
783 if ( clockvarlen
<= 0 ) {
787 clockvar_assoc
= associd
;