Home | History | Annotate | Line # | Download | only in ntpq
libntpq.c revision 1.1.1.4
      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  *	fam		int	Address Family (AF_INET, AF_INET6, or 0)
    219  *
    220  * Returns:
    221  *	int		1 if the host connection could be set up, i.e.
    222  *			name resolution was succesful and/or IP address
    223  *			has been validated
    224  *  			- OR -
    225  *			0 (zero) if a failure occured
    226  ****************************************************************************/
    227 
    228 int
    229 ntpq_openhost(
    230 	char *hostname,
    231 	int fam
    232 	)
    233 {
    234 	if ( openhost(hostname, fam) )
    235 	{
    236 		numhosts = 1;
    237 	} else {
    238 		numhosts = 0;
    239 	}
    240 
    241 	return numhosts;
    242 
    243 }
    244 
    245 
    246 /*****************************************************************************
    247  *
    248  *  ntpq_closehost
    249  *
    250  *  Cleans up a connection by closing the used socket. Should be called
    251  *  when no further queries are required for the currently used host.
    252  *
    253  ****************************************************************************
    254  * Parameters:
    255  *	- none -
    256  *
    257  * Returns:
    258  *	int		0 (zero) if no host has been opened before
    259  *			- OR -
    260  *			the resultcode from the closesocket function call
    261  ****************************************************************************/
    262 
    263 int ntpq_closehost(void)
    264 {
    265 	if ( numhosts )
    266 	 return closesocket(sockfd);
    267 
    268 	return 0;
    269 }
    270 
    271 
    272 /*****************************************************************************
    273  *
    274  *  ntpq_read_associations
    275  *
    276  *  This function queries the ntp host for its associations and returns the
    277  *  number of associations found.
    278  *
    279  *  It takes an u_short array as its first parameter, this array holds the
    280  *  IDs of the associations,
    281  *  the function will not write more entries than specified with the
    282  *  max_entries parameter.
    283  *
    284  *  However, if more than max_entries associations were found, the return
    285  *  value of this function will reflect the real number, even if not all
    286  *  associations have been stored in the array.
    287  *
    288  ****************************************************************************
    289  * Parameters:
    290  *	resultbuf	u_short*Array that should hold the list of
    291  *				association IDs
    292  *	maxentries	int	maximum number of association IDs that can
    293  *				be stored in resultbuf
    294  *
    295  * Returns:
    296  *	int		number of association IDs stored in resultbuf
    297  *  			- OR -
    298  *			0 (zero) if a failure occured or no association has
    299  *			been returned.
    300  ****************************************************************************/
    301 
    302  int  ntpq_read_associations ( u_short resultbuf[], int max_entries )
    303 {
    304     int i = 0;
    305 
    306     if (ntpq_dogetassoc()) {
    307 
    308         if(numassoc < max_entries)
    309           max_entries = numassoc;
    310 
    311         for (i=0;i<max_entries;i++)
    312             resultbuf[i] = assoc_cache[i].assid;
    313 
    314         return numassoc;
    315     }
    316 
    317     return 0;
    318 }
    319 
    320 
    321 
    322 
    323 /*****************************************************************************
    324  *
    325  *  ntpq_get_assocs
    326  *
    327  *  This function reads the associations of a previously selected (with
    328  *  ntpq_openhost) NTP host into its own (global) array and returns the
    329  *  number of associations found.
    330  *
    331  *  The obtained association IDs can be read by using the ntpq_get_assoc_id
    332  *  function.
    333  *
    334  ****************************************************************************
    335  * Parameters:
    336  *	- none -
    337  *
    338  * Returns:
    339  *	int		number of association IDs stored in resultbuf
    340  *  			- OR -
    341  *			0 (zero) if a failure occured or no association has
    342  *			been returned.
    343  ****************************************************************************/
    344 
    345  int  ntpq_get_assocs ( void )
    346 {
    347     return ntpq_read_associations( ntpq_associations, MAXASSOC );
    348 }
    349 
    350 
    351 /*****************************************************************************
    352  *
    353  *  ntpq_get_assoc_number
    354  *
    355  *  This function returns for a given Association ID the association number
    356  *  in the internal association array, which is filled by the ntpq_get_assocs
    357  *  function.
    358  *
    359  ****************************************************************************
    360  * Parameters:
    361  *	associd		int	requested associaton ID
    362  *
    363  * Returns:
    364  *	int		the number of the association array element that is
    365  *			representing the given association ID
    366  *  			- OR -
    367  *			-1 if a failure occured or no matching association
    368  * 			ID has been found
    369  ****************************************************************************/
    370 
    371 int ntpq_get_assoc_number ( associd_t associd )
    372 {
    373 	int i;
    374 
    375 	for (i=0;i<numassoc;i++) {
    376 		if (assoc_cache[i].assid == associd)
    377 			return i;
    378 	}
    379 
    380 	return -1;
    381 
    382 }
    383 
    384 
    385 /*****************************************************************************
    386  *
    387  *  ntpq_read_assoc_peervars
    388  *
    389  *  This function reads the peervars variable-set of a specified association
    390  *  from a NTP host and writes it to the result buffer specified, honoring
    391  *  the maxsize limit.
    392  *
    393  *  It returns the number of bytes written or 0 when the variable-set is
    394  *  empty or failed to read.
    395  *
    396  ****************************************************************************
    397  * Parameters:
    398  *	associd		int	requested associaton ID
    399  *	resultbuf	char*	character buffer where the variable set
    400  *				should be stored
    401  *	maxsize		int	the maximum number of bytes that can be
    402  *				written to resultbuf
    403  *
    404  * Returns:
    405  *	int		number of chars that have been copied to
    406  *			resultbuf
    407  *			- OR -
    408  *			0 (zero) if an error occured
    409  ****************************************************************************/
    410 
    411 int
    412 ntpq_read_assoc_peervars(
    413 	associd_t	associd,
    414 	char *		resultbuf,
    415 	int		maxsize
    416 	)
    417 {
    418 	const char *	datap;
    419 	int		res;
    420 	int		dsize;
    421 	u_short		rstatus;
    422 
    423 	res = doquery(CTL_OP_READVAR, associd, 0, 0, NULL, &rstatus,
    424 		      &dsize, &datap);
    425 	if (res != 0)
    426 		return 0;
    427 	if (dsize <= 0) {
    428 		if (numhosts > 1)
    429 			fprintf(stderr, "server=%s ", currenthost);
    430 		fprintf(stderr,
    431 			"***No information returned for association %d\n",
    432 			associd);
    433 
    434 		return 0;
    435 	}
    436 	if (dsize > maxsize)
    437 		dsize = maxsize;
    438 	memcpy(resultbuf, datap, dsize);
    439 
    440 	return dsize;
    441 }
    442 
    443 
    444 
    445 
    446 /*****************************************************************************
    447  *
    448  *  ntpq_read_sysvars
    449  *
    450  *  This function reads the sysvars variable-set from a NTP host and writes it
    451  *  to the result buffer specified, honoring the maxsize limit.
    452  *
    453  *  It returns the number of bytes written or 0 when the variable-set is empty
    454  *  or could not be read.
    455  *
    456  ****************************************************************************
    457  * Parameters:
    458  *	resultbuf	char*	character buffer where the variable set
    459  *				should be stored
    460  *	maxsize		int	the maximum number of bytes that can be
    461  *				written to resultbuf
    462  *
    463  * Returns:
    464  *	int		number of chars that have been copied to
    465  *			resultbuf
    466  *			- OR -
    467  *			0 (zero) if an error occured
    468  ****************************************************************************/
    469 size_t
    470 ntpq_read_sysvars(
    471 	char *	resultbuf,
    472 	size_t	maxsize
    473 	)
    474 {
    475 	const char *	datap;
    476 	int		res;
    477 	int		i_dsize;
    478 	size_t		dsize;
    479 	u_short		rstatus;
    480 
    481 	res = doquery(CTL_OP_READVAR, 0, 0, 0, NULL, &rstatus,
    482 		      &i_dsize, &datap);
    483 
    484 	if (res != 0)
    485 		return 0;
    486 
    487 	if (i_dsize == 0) {
    488 		if (numhosts > 1)
    489 			fprintf(stderr, "server=%s ", currenthost);
    490 		fprintf(stderr, "***No sysvar information returned\n");
    491 
    492 		return 0;
    493 	} else {
    494 		dsize = max(0, i_dsize);
    495 		dsize = min(dsize, maxsize);
    496 		memcpy(resultbuf, datap, dsize);
    497 	}
    498 
    499 	return dsize;
    500 }
    501 
    502 
    503 /*****************************************************************************
    504  *  ntpq_get_assoc_allvars
    505  *
    506  *  With this function all association variables for the specified association
    507  *  ID can be requested from a NTP host. They are stored internally and can be
    508  *  read by using the ntpq_get_peervar or ntpq_get_clockvar functions.
    509  *
    510  *  Basically this is only a combination of the ntpq_get_assoc_peervars and
    511  *  ntpq_get_assoc_clockvars functions.
    512  *
    513  *  It returns 1 if both variable-sets (peervars and clockvars) were
    514  *  received successfully. If one variable-set or both of them weren't
    515  *  received,
    516  *
    517  ****************************************************************************
    518  * Parameters:
    519  *	associd		int	requested associaton ID
    520  *
    521  * Returns:
    522  *	int		nonzero if at least one variable set could be read
    523  * 			- OR -
    524  *			0 (zero) if an error occured and both variable sets
    525  *			could not be read
    526  ****************************************************************************/
    527  int  ntpq_get_assoc_allvars( associd_t associd  )
    528 {
    529 	return ntpq_get_assoc_peervars ( associd ) &
    530 	       ntpq_get_assoc_clockvars( associd );
    531 }
    532 
    533 
    534 
    535 
    536 /*****************************************************************************
    537  *
    538  *  ntpq_get_sysvars
    539  *
    540  *  The system variables of a NTP host can be requested by using this function
    541  *  and afterwards using ntpq_get_sysvar to read the single variable values.
    542  *
    543  ****************************************************************************
    544  * Parameters:
    545  *	- none -
    546  *
    547  * Returns:
    548  *	int		nonzero if the variable set could be read
    549  * 			- OR -
    550  *			0 (zero) if an error occured and the sysvars
    551  *			could not be read
    552  ****************************************************************************/
    553 int
    554 ntpq_get_sysvars(void)
    555 {
    556 	sysvarlen = ntpq_read_sysvars(sysvars, sizeof(sysvars));
    557 	if (sysvarlen <= 0)
    558 		return 0;
    559 	else
    560 		return 1;
    561 }
    562 
    563 
    564 /*****************************************************************************
    565  *
    566  *  ntp_get_peervar
    567  *
    568  *  This function uses the variable-set which was read by using
    569  *  ntp_get_peervars and searches for a variable specified with varname. If
    570  *  such a variable exists, it writes its value into
    571  *  varvalue (maxlen specifies the size of this target buffer).
    572  *
    573  ****************************************************************************
    574  * Parameters:
    575  *	varname		char*	requested variable name
    576  *	varvalue	char*	the buffer where the value should go into
    577  *	maxlen		int	maximum number of bytes that can be copied to
    578  *				varvalue
    579  *
    580  * Returns:
    581  *	int		number of bytes copied to varvalue
    582  * 			- OR -
    583  *			0 (zero) if an error occured or the variable could
    584  *			not be found
    585  ****************************************************************************/
    586 int ntpq_get_peervar( const char *varname, char *varvalue, int maxlen)
    587 {
    588     return ( ntpq_getvar(peervars,peervarlen,varname,varvalue,maxlen) );
    589 }
    590 
    591 
    592 
    593 /*****************************************************************************
    594  *
    595  *  ntpq_get_assoc_peervars
    596  *
    597  *  This function requests the peer variables of the specified association
    598  *  from a NTP host. In order to access the variable values, the function
    599  *  ntpq_get_peervar must be used.
    600  *
    601  ****************************************************************************
    602  * Parameters:
    603  *	associd		int	requested associaton ID
    604  *
    605  * Returns:
    606  *	int		1 (one) if the peervars have been read
    607  * 			- OR -
    608  *			0 (zero) if an error occured and the variable set
    609  *			could not be read
    610  ****************************************************************************/
    611 int
    612 ntpq_get_assoc_peervars(
    613 	associd_t associd
    614 	)
    615 {
    616 	peervarlen = ntpq_read_assoc_peervars(associd, peervars,
    617 					      sizeof(peervars));
    618 	if (peervarlen <= 0) {
    619 		peervar_assoc = 0;
    620 
    621 		return 0;
    622 	}
    623 	peervar_assoc = associd;
    624 
    625 	return 1;
    626 }
    627 
    628 
    629 /*****************************************************************************
    630  *
    631  *  ntp_read_assoc_clockvars
    632  *
    633  *  This function reads the clockvars variable-set of a specified association
    634  *  from a NTP host and writes it to the result buffer specified, honoring
    635  *  the maxsize limit.
    636  *
    637  *  It returns the number of bytes written or 0 when the variable-set is
    638  *  empty or failed to read.
    639  *
    640  ****************************************************************************
    641  * Parameters:
    642  *	associd		int	requested associaton ID
    643  *	resultbuf	char*	character buffer where the variable set
    644  *				should be stored
    645  *	maxsize		int	the maximum number of bytes that can be
    646  *				written to resultbuf
    647  *
    648  * Returns:
    649  *	int		number of chars that have been copied to
    650  *			resultbuf
    651  *			- OR -
    652  *			0 (zero) if an error occured
    653  ****************************************************************************/
    654 
    655 int
    656 ntpq_read_assoc_clockvars(
    657 	associd_t	associd,
    658 	char *		resultbuf,
    659 	int		maxsize
    660 	)
    661 {
    662 	const char *datap;
    663 	int res;
    664 	int dsize;
    665 	u_short rstatus;
    666 
    667 	res = ntpq_doquerylist(ntpq_varlist, CTL_OP_READCLOCK, associd,
    668 			       0, &rstatus, &dsize, &datap);
    669 	if (res != 0)
    670 		return 0;
    671 
    672 	if (dsize == 0) {
    673 		if (numhosts > 1) /* no information returned from server */
    674 			return 0;
    675 	} else {
    676 		if (dsize > maxsize)
    677 			dsize = maxsize;
    678 		memcpy(resultbuf, datap, dsize);
    679 	}
    680 
    681 	return dsize;
    682 }
    683 
    684 
    685 
    686 /*****************************************************************************
    687  *
    688  *  ntpq_get_assoc_clocktype
    689  *
    690  *  This function returns a clocktype value for a given association number
    691  *  (not ID!):
    692  *
    693  *  NTP_CLOCKTYPE_UNKNOWN   Unknown clock type
    694  *  NTP_CLOCKTYPE_BROADCAST Broadcast server
    695  *  NTP_CLOCKTYPE_LOCAL     Local clock
    696  *  NTP_CLOCKTYPE_UNICAST   Unicast server
    697  *  NTP_CLOCKTYPE_MULTICAST Multicast server
    698  *
    699  ****************************************************************************/
    700 int
    701 ntpq_get_assoc_clocktype(
    702 	int assoc_index
    703 	)
    704 {
    705 	associd_t	associd;
    706 	int		i;
    707 	int		rc;
    708 	sockaddr_u	dum_store;
    709 	char		dstadr[LENHOSTNAME];
    710 	char		resultbuf[NTPQ_BUFLEN];
    711 
    712 	if (assoc_index < 0 || assoc_index >= numassoc)
    713 		return -1;
    714 
    715 	associd = assoc_cache[assoc_index].assid;
    716 	if (associd == peervar_assoc) {
    717 		rc = ntpq_get_peervar("dstadr", dstadr, sizeof(dstadr));
    718 	} else {
    719 		i = ntpq_read_assoc_peervars(associd, resultbuf,
    720 					     sizeof(resultbuf));
    721 		if (i <= 0)
    722 			return -1;
    723 		rc = ntpq_getvar(resultbuf, i, "dstadr", dstadr,
    724 				 sizeof(dstadr));
    725 	}
    726 
    727 	if (0 != rc && decodenetnum(dstadr, &dum_store))
    728 		return ntpq_decodeaddrtype(&dum_store);
    729 
    730 	return -1;
    731 }
    732 
    733 
    734 
    735 /*****************************************************************************
    736  *
    737  *  ntpq_get_assoc_clockvars
    738  *
    739  *  With this function the clock variables of the specified association are
    740  *  requested from a NTP host. This makes only sense for associations with
    741  *  the type 'l' (Local Clock) and you should check this with
    742  *  ntpq_get_assoc_clocktype for each association, before you use this function
    743  *  on it.
    744  *
    745  ****************************************************************************
    746  * Parameters:
    747  *	associd		int	requested associaton ID
    748  *
    749  * Returns:
    750  *	int		1 (one) if the clockvars have been read
    751  * 			- OR -
    752  *			0 (zero) if an error occured and the variable set
    753  *			could not be read
    754  ****************************************************************************/
    755 int  ntpq_get_assoc_clockvars( associd_t associd )
    756 {
    757 	if (NTP_CLOCKTYPE_LOCAL != ntpq_get_assoc_clocktype(
    758 	    ntpq_get_assoc_number(associd)))
    759 		return 0;
    760 	clockvarlen = ntpq_read_assoc_clockvars( associd, clockvars,
    761 						 sizeof(clockvars) );
    762 	if ( clockvarlen <= 0 ) {
    763 		clockvar_assoc = 0;
    764 		return 0;
    765 	} else {
    766 		clockvar_assoc = associd;
    767 		return 1;
    768 	}
    769 }
    770 
    771 
    772