📄 sntpclib.c
字号:
/* sntpcLib.c - Simple Network Time Protocol (SNTP) client library *//* Copyright 1984-2002 Wind River Systems, Inc. */#include "copyright_wrs.h"/*modification history --------------------01k,07jan02,vvv doc: added errnos for sntpcTimeGet and sntpcFetch (SPR #71557)01j,16mar99,spm doc: removed references to configAll.h (SPR #25663)01e,14dec97,jdi doc: cleanup.01d,10dec97,kbw making man page changes01c,27aug97,spm corrections for man page generation01b,15jul97,spm code cleanup, documentation, and integration; entered in source code control01a,24may97,kyc written*//* DESCRIPTIONThis library implements the client side of the Simple Network Time Protocol (SNTP), a protocol that allows a system to maintain the accuracy of its internal clock based on time values reported by one or more remote sources. The library is included in the VxWorks image if INCLUDE_SNTPC is defined at the time the image is built.USER INTERFACEThe sntpcTimeGet() routine retrieves the time reported by a remote source andconverts that value for POSIX-compliant clocks. The routine will either send a request and extract the time from the reply, or it will wait until a message isreceived from an SNTP/NTP server executing in broadcast mode.INCLUDE FILES: sntpcLib.hSEE ALSO: clockLib, RFC 1769*//* includes */#include "vxWorks.h"#include "sysLib.h"#include "ioLib.h"#include "inetLib.h"#include "hostLib.h"#include "sockLib.h"#include "errnoLib.h"#include "sntpcLib.h"/* globals */u_short sntpcPort;/* forward declarations */LOCAL STATUS sntpcListen (u_int, struct timespec *);LOCAL STATUS sntpcFetch (struct in_addr *, u_int, struct timespec *);/********************************************************************************* sntpcInit - set up the SNTP client** This routine is called to link the SNTP client module into the VxWorks* image. It assigns the UDP source and destination port according to the* corresponding SNTP_PORT setting.* * RETURNS: OK, always.** ERRNO: N/A** NOMANUAL*/STATUS sntpcInit ( u_short port /* UDP source/destination port */ ) { sntpcPort = htons (port); return (OK); }/********************************************************************************* sntpcFractionToNsec - convert time from the NTP format to POSIX time format** This routine converts the fractional part of the NTP timestamp format to a * value in nanoseconds compliant with the POSIX clock. While the NTP time * format provides a precision of about 200 pico-seconds, rounding error in the * conversion routine reduces the precision to tenths of a micro-second.* * RETURNS: Value for struct timespec corresponding to NTP fractional part** ERRNO: N/A** INTERNAL** Floating-point calculations can't be used because some boards (notably* the SPARC architectures) disable software floating point by default to * speed up context switching. These boards abort with an exception when* floating point operations are encountered.** NOMANUAL*/LOCAL ULONG sntpcFractionToNsec ( ULONG sntpFraction /* base 2 fractional part of the NTP timestamp */ ) { ULONG factor = 0x8AC72305; /* Conversion factor from base 2 to base 10 */ ULONG divisor = 10; /* Initial exponent for mantissa. */ ULONG mask = 1000000000; /* Pulls digits of factor from left to right. */ int loop; ULONG nsec = 0; BOOL shift = FALSE; /* Shifted to avoid overflow? */ /* * Adjust large values so that no intermediate calculation exceeds * 32 bits. (This test is overkill, since the fourth MSB can be set * sometimes, but it's fast). */ if (sntpFraction & 0xF0000000) { sntpFraction /= 10; shift = TRUE; } /* * In order to increase portability, the following conversion avoids * floating point operations, so it is somewhat obscure. * * Incrementing the NTP fractional part increases the corresponding * decimal value by 2^(-32). By interpreting the fractional part as an * integer representing the number of increments, the equivalent decimal * value is equal to the product of the fractional part and 0.2328306437. * That value is the mantissa for 2^(-32). Multiplying by 2.328306437E-10 * would convert the NTP fractional part into the equivalent in seconds. * * The mask variable selects each digit from the factor sequentially, and * the divisor shifts the digit the appropriate number of decimal places. * The initial value of the divisor is 10 instead of 1E10 so that the * conversion produces results in nanoseconds, as required by POSIX clocks. */ for (loop = 0; loop < 10; loop++) /* Ten digits in mantissa */ { nsec += sntpFraction * (factor/mask)/divisor; /* Use current digit. */ factor %= mask; /* Remove most significant digit from the factor. */ mask /= 10; /* Reduce length of mask by one. */ divisor *= 10; /* Increase preceding zeroes by one. */ } /* Scale result upwards if value was adjusted before processing. */ if (shift) nsec *= 10; return (nsec); }/********************************************************************************* sntpcTimeGet - retrieve the current time from a remote source** This routine stores the current time as reported by an SNTP/NTP server in* the location indicated by <pCurrTime>. The reported time is first converted* to the elapsed time since January 1, 1970, 00:00, GMT, which is the base value* used by UNIX systems. If <pServerAddr> is NULL, the routine listens for * messages sent by an SNTP/NTP server in broadcast mode. Otherwise, this* routine sends a request to the specified SNTP/NTP server and extracts the* reported time from the reply. In either case, an error is returned if no * message is received within the interval specified by <timeout>. Typically, * SNTP/NTP servers operating in broadcast mode send update messages every 64 * to 1024 seconds. An infinite timeout value is specified by WAIT_FOREVER.* * RETURNS: OK, or ERROR if unsuccessful.** ERRNO:* S_sntpcLib_INVALID_PARAMETER, S_sntpcLib_INVALID_ADDRESS, S_sntpcLib_TIMEOUT,* S_sntpcLib_SERVER_UNSYNC, S_sntpcLib_VERSION_UNSUPPORTED*/STATUS sntpcTimeGet ( char * pServerAddr, /* server IP address or hostname */ u_int timeout, /* timeout interval in ticks */ struct timespec * pCurrTime /* storage for retrieved time value */ ) { STATUS result; struct in_addr target; if (pCurrTime == NULL || (timeout < 0 && timeout != WAIT_FOREVER)) { errnoSet (S_sntpcLib_INVALID_PARAMETER); return (ERROR); } if (pServerAddr == NULL) result = sntpcListen (timeout, pCurrTime); else { target.s_addr = hostGetByName (pServerAddr); if (target.s_addr == ERROR) target.s_addr = inet_addr (pServerAddr); if (target.s_addr == ERROR) { errnoSet (S_sntpcLib_INVALID_ADDRESS); return (ERROR); } result = sntpcFetch (&target, timeout, pCurrTime); } return (result); }/********************************************************************************* sntpcFetch - send an SNTP request and retrieve the time from the reply** This routine sends an SNTP request to the IP address specified by* <pTargetAddr>, converts the returned NTP timestamp to the POSIX-compliant * clock format with the UNIX base value (elapsed time since 00:00 GMT on * Jan. 1, 1970), and stores the result in the location indicated by <pTime>.* * RETURNS: OK, or ERROR if unsuccessful.** ERRNO:* S_sntpcLib_SERVER_UNSYNC* S_sntpcLib_VERSION_UNSUPPORTED* S_sntpcLib_TIMEOUT** NOMANUAL*/LOCAL STATUS sntpcFetch ( struct in_addr * pTargetAddr, /* SNTP/NTP server IP address */ u_int timeout, /* timeout in ticks */ struct timespec * pCurrTime /* storage for retrieved time value */ ) { SNTP_PACKET sntpRequest; /* sntp request packet for */ /* transmission to server */ SNTP_PACKET sntpReply; /* buffer for server reply */ struct sockaddr_in dstAddr; struct sockaddr_in servAddr; struct timeval sockTimeout; int optval; int clockRate; int sntpSocket; fd_set readFds; int result; int servAddrLen; /* Set destination for request. */ bzero ( (char *)&dstAddr, sizeof (dstAddr)); dstAddr.sin_addr.s_addr = pTargetAddr->s_addr; dstAddr.sin_family = AF_INET; dstAddr.sin_port = sntpcPort; /* Create socket for transmission. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -