sntpsLib.c
上传用户:nvosite88
上传日期:2007-01-17
资源大小:4983k
文件大小:27k
源码类别:

VxWorks

开发平台:

C/C++

  1. /* sntpsLib.c - Simple Network Time Protocol (SNTP) server library */
  2. /* Copyright 1984 - 2000 Wind River Systems, Inc. */
  3. #include "copyright_wrs.h"
  4. /*
  5. modification history 
  6. --------------------
  7. 01l,07may02,kbw  man page edits
  8. 01k,25oct00,ham  doc: cleanup for vxWorks AE 1.0.
  9. 01j,16mar99,spm  removed references to configAll.h (SPR #25663)
  10. 01i,16mar99,spm  recovered orphaned code from tor2_0_x branch (SPR #25770)
  11. 01h,01dec98,spm  corrected man page references for clock hook (SPR #22860)
  12. 01g,14dec97,jdi  doc: cleanup.
  13. 01f,10dec97,kbw  made minor man page changes
  14. 01e,04dec97,spm  added minor changes to man pages; changed parameter names to 
  15.                  comply with coding standards
  16. 01d,02sep97,spm  corrected return value and typecast for sntpsConfigSet routine
  17. 01c,27aug97,spm  corrected header file name in library description
  18. 01b,15jul97,spm  code cleanup, documentation, and integration; entered in
  19.                  source code control
  20. 01a,24may97,kyc  written
  21. */
  22. /* 
  23. DESCRIPTION
  24. This library implements the server side of the Simple Network Time Protocol
  25. (SNTP), a protocol that allows a system to maintain the accuracy of its 
  26. internal clock based on time values reported by one or more remote sources. 
  27. The library is included in the VxWorks image if INCLUDE_SNTPS is defined 
  28. at the time the image is built.
  29. USER INTERFACE
  30. The routine sntpsInit() is called automatically during system startup when 
  31. the SNTP server library is included in the VxWorks image. Depending on the 
  32. value of SNTPS_MODE, the server executes in either a passive or an active 
  33. mode.  When SNTPS_MODE is set to SNTP_PASSIVE (0x2), the server waits for
  34. requests from clients, and sends replies containing an NTP timestamp. When
  35. the mode is set to SNTP_ACTIVE (0x1), the server transmits NTP timestamp
  36. information at fixed intervals. 
  37. When executing in active mode, the SNTP server uses the SNTPS_DSTADDR and 
  38. SNTPS_INTERVAL definitions to determine the target IP address and broadcast
  39. interval.  By default, the server will transmit the timestamp information to
  40. the local subnet broadcast address every 64 seconds.  These settings can be
  41. changed with a call to the sntpsConfigSet() routine.  The SNTP server operating
  42. in active mode will still respond to client requests.
  43. The SNTP_PORT definition in assigns the source and destination UDP port.  The 
  44. default port setting is 123 as specified by the relevant RFC.  Finally, the
  45. SNTP server requires access to a reliable external time source.  The
  46. SNTPS_TIME_HOOK constant specifies the name of a routine with the following
  47. interface:
  48. .CS
  49.     STATUS sntpsTimeHook (int request, void *pBuffer);
  50. .CE
  51. This routine can be assigned directly by altering the value of SNTPS_TIME_HOOK
  52. or can be installed by a call to the sntpsClockSet() routine. The manual pages
  53. for sntpsClockSet() describe the parameters and required operation of the
  54. timestamp retrieval routine.  Until this routine is specified, the SNTP server
  55. will not provide timestamp information.
  56. VXWORKS AE PROTECTION DOMAINS
  57. Under VxWorks AE, the SNPT server can run in the kernel protection domain only. 
  58. The SNTPS_TIME_HOOK MUST, if used, must reference a function in the kernel 
  59. protection domain.  This restriction does not apply under non-AE versions of 
  60. VxWorks.  
  61. INCLUDE FILES: sntpsLib.h
  62. SEE ALSO: sntpcLib, RFC 1769
  63. */
  64. /* includes */
  65. #include "vxWorks.h"
  66. #include "sysLib.h"
  67. #include "inetLib.h"
  68. #include "sockLib.h"
  69. #include "netLib.h"
  70. #include "ioLib.h"
  71. #include "wdLib.h"
  72. #include "usrLib.h"
  73. #include "errnoLib.h"
  74. #include "sntpsLib.h"
  75. #include <sys/ioctl.h>
  76. /* defines */
  77. #define NSEC_BASE2  30  /* Integral log2 for nanosecond conversion. */
  78. /* forward declarations */
  79. LOCAL void sntpsMsgSend (void);
  80. LOCAL void sntpsStart (void);
  81. LOCAL int sntpsTaskPriority  = 56;    /* Priority level of SNTP server. */
  82. LOCAL int sntpsTaskOptions = 0;       /* Option settings for SNTP server. */
  83. LOCAL int sntpsTaskStackSize = 5000;  /* Stack size for SNTP server task. */
  84. LOCAL WDOG_ID   sntpsTimer;           /* Timer for periodic broadcasts. */
  85. LOCAL SEM_ID    sntpsMutexSem;        /* Protection for clock changes. */
  86. LOCAL BOOL  sntpsInitialized;     /* Ready to send timestamps? */
  87. LOCAL BOOL  sntpsClockReady;      /* Clock hook assigned? */
  88. LOCAL ULONG  sntpsClockId;         /* SNTP clock identifier. */
  89. LOCAL ULONG     sntpsRefId;           /* Default reference identifier. */
  90. LOCAL ULONG     sntpsResolution;      /* Clock resolution, in nanoseconds. */
  91. LOCAL INT8      sntpsPrecision;       /* Clock precision, in RFC format. */
  92. LOCAL u_char  sntpsMode;            /* Active or passive operation. */
  93. LOCAL short  sntpsInterval;        /* Broadcast interval, in seconds. */
  94. LOCAL u_short  sntpsPort;            /* UDP source and destination port. */
  95. LOCAL struct in_addr  sntpsDstAddr; /* Broadcast or multicast destination. */
  96. LOCAL FUNCPTR   sntpsClockHookRtn;    /* Access to timestamp information. */
  97. /*******************************************************************************
  98. *
  99. * sntpsInit - set up the SNTP server
  100. *
  101. * This routine is called from usrNetwork.c to link the SNTP server module into
  102. * the VxWorks image.  It creates all necessary internal data structures and
  103. * initializes the SNTP server according to the assigned settings.
  104. *
  105. * RETURNS: OK or ERROR.
  106. *
  107. * ERRNO:
  108. *  S_sntpsLib_INVALID_PARAMETER
  109. *
  110. * NOMANUAL
  111. */
  112. STATUS sntpsInit 
  113.     (
  114.     char *  pDevName,  /* boot device name */
  115.     u_char  mode,  /* broadcast or unicast mode */
  116.     char *  pDstAddr,  /* destination IP address for broadcasts */
  117.     short  interval,  /* broadcast interval */
  118.     u_short  port,  /* UDP source/destination port */
  119.     FUNCPTR  pTimeHookRtn  /* timestamp retrieval routine */
  120.     )
  121.     {
  122.     STATUS result = OK;
  123.     int retVal;
  124.     int sockNum = 0;
  125.     struct ifreq ifr;
  126.     struct in_addr ifAddr;
  127.     struct in_addr ifMask;
  128.     sntpsInitialized = FALSE;
  129.     sntpsClockReady = FALSE;
  130.     sntpsRefId = 0;    /* Default ref. ID if hook routine returns ERROR */
  131.     /* Set mode to specified value. */
  132.     if (mode != SNTP_ACTIVE && mode != SNTP_PASSIVE)
  133.         {
  134.         errnoSet (S_sntpsLib_INVALID_PARAMETER);
  135.         return (ERROR);
  136.         }
  137.     else
  138.         sntpsMode = mode;
  139.        
  140.     /* For active (broadcast) mode, set message interval and target address. */
  141.     if (sntpsMode == SNTP_ACTIVE)
  142.         {
  143.         /* Sanity check broadcast interval and assign target address. */
  144.         if (interval < 0)
  145.             interval = 0;
  146.         sntpsInterval = interval;
  147.         /* Use subnet local broadcast address if none specified. */
  148.         if (pDstAddr == NULL)
  149.             {
  150.             /* Combine IP address of interface and current netmask. */
  151.             sockNum = socket (AF_INET, SOCK_RAW, 0);
  152.             if (sockNum == -1)
  153.                 return (ERROR);
  154.             bzero ( (char *)&ifr, sizeof (struct ifreq));
  155.             strcpy (ifr.ifr_name, pDevName);
  156.             ifr.ifr_addr.sa_len = sizeof (struct sockaddr_in);
  157.             retVal = ioctl (sockNum, SIOCGIFADDR, (int)&ifr);
  158.             if (retVal != 0)
  159.                 {
  160.                 close (sockNum);
  161.                 return (ERROR);
  162.                 }
  163.             ifAddr.s_addr = 
  164.                        ( (struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr;
  165.             retVal = ioctl (sockNum, SIOCGIFNETMASK, (int)&ifr);
  166.             if (retVal != 0)
  167.                 {
  168.                 close (sockNum);
  169.                 return (ERROR);
  170.                 }
  171.             ifMask.s_addr = 
  172.                        ( (struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr;
  173.             close (sockNum);
  174.             /* Extract network address and fill host portion with ones. */
  175.             sntpsDstAddr.s_addr = (ifAddr.s_addr & ifMask.s_addr) 
  176.                                     | ~ifMask.s_addr;
  177.             }
  178.         else        /* Use specified destination address. */
  179.             {
  180.             sntpsDstAddr.s_addr = inet_addr (pDstAddr);
  181.             if (sntpsDstAddr.s_addr == ERROR)
  182.                 {
  183.                 errnoSet (S_sntpsLib_INVALID_PARAMETER);
  184.                 return (ERROR);
  185.                 }
  186.             }
  187.         /* Create timer for periodic transmissions. */
  188.         sntpsTimer = wdCreate ();
  189.         if (sntpsTimer == NULL)
  190.             return (ERROR);
  191.         }
  192.     /* Create synchronization semaphore for changing clock. */
  193.     sntpsMutexSem = semBCreate (SEM_Q_FIFO, SEM_FULL);
  194.     if (sntpsMutexSem == NULL)
  195.         {
  196.         if (sntpsMode == SNTP_ACTIVE)
  197.             wdDelete (sntpsTimer);
  198.         return (ERROR);
  199.         }
  200.     sntpsPort = htons (port);
  201.     sntpsInitialized = TRUE;
  202.     /* Enable transmission if timestamp retrieval routine is provided. */
  203.     result = sntpsClockSet (pTimeHookRtn);
  204.     if (result == OK)
  205.         sntpsClockReady = TRUE;
  206.  
  207.     result = taskSpawn ("tSntpsTask", sntpsTaskPriority, sntpsTaskOptions,
  208.                         sntpsTaskStackSize, (FUNCPTR) sntpsStart,
  209.                         0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
  210.     return (result);
  211.     }
  212. /*******************************************************************************
  213. *
  214. * sntpsLog2Get - find approximate power of two
  215. *
  216. * This routine determines the nearest integral power of two for the given 
  217. * value, without using floating point arithmetic.  It is used to convert 
  218. * 32-bit nanosecond values into signed integers for assignment to the poll 
  219. * and precision fields of NTP messages.
  220. *
  221. * RETURNS: Nearest integral log base two value, in host byte order.
  222. *
  223. * ERRNO: N/A
  224. *
  225. * INTERNAL
  226. * Floating-point calculations can't be used because some boards (notably
  227. * the SPARC architectures) disable software floating point by default to
  228. * speed up context switching. These boards abort with an exception when
  229. * floating point operations are encountered.
  230. *
  231. * NOMANUAL
  232. */
  233. INT8 sntpsLog2Get
  234.     (
  235.     ULONG inval  /* input value for calculation */
  236.     )
  237.     {
  238.     int loop;
  239.     int floor;  /* Nearest power of two for smaller value */
  240.     int limit;  /* Nearest power of two for larger value */
  241.     int result;
  242.     ULONG mask;  /* Bitmask for log2 calculation */
  243.     if (inval == 0)
  244.         result = 0;
  245.     else
  246.         {
  247.         /*
  248.          * Set increasing numbers of the low-order bits of the input value
  249.          * to zero until all bits have been cleared. The current and previous
  250.          * values of the loop counter indicate the adjacent integral powers
  251.          * of two.
  252.          */
  253.         for (loop = 0; loop < 32; loop ++)
  254.             {
  255.             mask = ~0 << loop;     /* Mask out the rightmost "loop" bits. */
  256.             if ( (inval & mask) == 0)
  257.                 break;
  258.             }
  259.         floor = 1 << (loop - 1);
  260.         limit = 1 << loop;
  261.         if (inval - floor < limit - inval)
  262.             result = loop - 1;
  263.         else
  264.             result = loop;
  265.         }
  266.    
  267.     return (result);
  268.     }
  269. /*******************************************************************************
  270. *
  271. * sntpsClockSet - assign a routine to access the reference clock
  272. *
  273. * This routine installs a hook routine that is called to access the 
  274. * reference clock used by the SNTP server. This hook routine must use the 
  275. * following interface:
  276. * .CS
  277. *     STATUS sntpsClockHook (int request, void *pBuffer);
  278. * .CE 
  279. * The hook routine should copy one of three settings used by the server to
  280. * construct outgoing NTP messages into <pBuffer> according to the value of 
  281. * the <request> parameter.  If the requested setting is available, the 
  282. * installed routine should return OK (or ERROR otherwise).
  283. *
  284. * This routine calls the given hook routine with the <request> parameter 
  285. * set to SNTPS_ID to get the 32-bit reference identifier in the format
  286. * specified in RFC 1769.  It also calls the hook routine with <request> 
  287. * set to SNTPS_RESOLUTION to retrieve a 32-bit value containing the clock 
  288. * resolution in nanoseconds.  That value will be used to determine the 8-bit 
  289. * signed integer indicating the clock precision (according to the format 
  290. * specified in RFC 1769).  Other library routines will set the <request> 
  291. * parameter to SNTPS_TIME to retrieve the current 64-bit NTP timestamp 
  292. * from <pBuffer> in host byte order.  The routine sntpsNsecToFraction() will 
  293. * convert a value in nanoseconds to the format required for the NTP 
  294. * fractional part.
  295. *
  296. * VXWORKS AE PROTECTION DOMAINS
  297. * Under VxWorks AE, you can call this function from within the kernel 
  298. * protection domain only.  In addition, all arguments to this function can  
  299. * reference only that data which is valid in the kernel protection domain. 
  300. * This restriction does not apply under non-AE versions of VxWorks.  
  301. *
  302. * RETURNS: OK or ERROR.
  303. *
  304. * ERRNO: N/A
  305. */
  306. STATUS sntpsClockSet
  307.     (
  308.     FUNCPTR  pClockHookRtn  /* new interface to reference clock */
  309.     )
  310.     {
  311.     STATUS result;
  312.     INT8 basetwo;
  313.     if (pClockHookRtn == NULL)
  314.         return (ERROR);
  315.     /* Don't change clock setting if current routine is in use. */
  316.     semTake (sntpsMutexSem, WAIT_FOREVER);
  317.     sntpsClockHookRtn = pClockHookRtn;
  318.     /* Get clock precision and clock identifier. */
  319.     result = (* sntpsClockHookRtn) (SNTPS_ID, &sntpsClockId);
  320.     if (result == ERROR)  /* Clock ID not available. Use default value. */
  321.         sntpsClockId = sntpsRefId;
  322.     result = (* sntpsClockHookRtn) (SNTPS_RESOLUTION, &sntpsResolution);
  323.     if (result == ERROR)
  324.         sntpsPrecision = 0;
  325.     else
  326.         {
  327.         /* Find nearest power of two to clock resolution. */
  328.         basetwo = sntpsLog2Get (sntpsResolution);
  329.         /*
  330.          * Convert to seconds required for NTP message. Subtract nearest 
  331.          * integer to log base two of 1E9 (corresponds to division of clock 
  332.          * resolution by 1E9).
  333.          */
  334.         sntpsPrecision = basetwo - NSEC_BASE2;
  335.         }
  336.     if (!sntpsClockReady)
  337.         sntpsClockReady = TRUE;     /* Enable transmission of messages. */
  338.     semGive (sntpsMutexSem);
  339.     return (OK);
  340.     }
  341. /*******************************************************************************
  342. *
  343. * sntpsNsecToFraction - convert portions of a second to NTP format
  344. *
  345. * This routine is provided for convenience in fulfilling an SNTPS_TIME request
  346. * to the clock hook.  It converts a value in nanoseconds to the fractional part 
  347. * of the NTP timestamp format.  The routine is not designed to convert 
  348. * non-normalized values greater than or equal to one second.  Although the NTP 
  349. * time format provides a precision of about 200 pico-seconds, rounding errors 
  350. * in the conversion process decrease the accuracy as the input value increases.
  351. * In the worst case, only the 24 most significant bits are valid, which reduces
  352. * the precision to tenths of a micro-second.
  353. *
  354. * RETURNS: Value for NTP fractional part in host-byte order.
  355. *
  356. * ERRNO: N/A
  357. *
  358. * INTERNAL
  359. * Floating-point calculations can't be used because some boards (notably
  360. * the SPARC architectures) disable software floating point by default to
  361. * speed up context switching. These boards abort with an exception when
  362. * floating point operations are encountered.
  363. */
  364. ULONG sntpsNsecToFraction
  365.     (
  366.     ULONG nsecs  /* nanoseconds to convert to binary fraction */
  367.     )
  368.     {
  369.     ULONG factor = 294967296;  /* Partial conversion factor from base 10 */
  370.     ULONG divisor = 10;        /* Initial exponent for mantissa. */
  371.     ULONG mask = 100000000;    /* Pulls digits of factor from left to right. */
  372.     int loop;
  373.     ULONG fraction = 0;
  374.     BOOL shift = FALSE;        /* Shifted to avoid overflow? */
  375.     /*
  376.      * Adjust large values so that no intermediate calculation exceeds
  377.      * 32 bits. (This test is overkill, since the fourth MSB can be set
  378.      * sometimes, but it's fast).
  379.      */
  380.     if (nsecs & 0xF0000000)
  381.         {
  382.         nsecs >>= 4;     /* Exclude rightmost hex digit. */
  383.         shift = TRUE;
  384.         }
  385.     /*
  386.      * In order to increase portability, the following conversion avoids
  387.      * floating point operations, so it is somewhat obscure.
  388.      *
  389.      * A one nanosecond increase corresponds to increasing the NTP fractional 
  390.      * part by (2^32)/1E9. Multiplying the number of nanoseconds by that value
  391.      * (4.294967286) produces the NTP fractional part.
  392.      *
  393.      * The above constant is separated into integer and decimal parts to avoid
  394.      * overflow. The mask variable selects each digit from the decimal part
  395.      * sequentially, and the divisor shifts the digit the appropriate number
  396.      * of decimal places.
  397.      */
  398.     fraction += nsecs * 4;              /* Handle integer part of conversion */
  399.     for (loop = 0; loop < 9; loop++)    /* Nine digits in mantissa */
  400.         {
  401.         fraction += nsecs * (factor/mask)/divisor;
  402.         factor %= mask;    /* Remove most significant digit from the factor. */
  403.         mask /= 10;        /* Reduce length of mask by one. */
  404.         divisor *= 10;     /* Increase shift by one decimal place. */
  405.         }
  406.     /* Scale result upwards if value was adjusted before processing. */
  407.     if (shift)
  408.         fraction <<= 4;
  409.     return (fraction);
  410.     }
  411. /*******************************************************************************
  412. *
  413. * sntpsConfigSet - change SNTP server broadcast settings
  414. *
  415. * This routine alters the configuration of the SNTP server when operating
  416. * in broadcast mode.  A <setting> value of SNTPS_DELAY interprets the contents
  417. * of <pValue> as the new 16-bit broadcast interval.  When <setting> equals
  418. * SNTPS_ADDRESS, <pValue> should provide the string representation of an
  419. * IP broadcast or multicast address (for example, "224.0.1.1").  Any changed 
  420. * settings will take effect after the current broadcast interval is 
  421. * completed and the corresponding NTP message is sent.
  422. *
  423. * RETURNS: OK or ERROR.
  424. *
  425. * ERRNO:
  426. *  S_sntpsLib_INVALID_PARAMETER
  427. */
  428. STATUS sntpsConfigSet
  429.     (
  430.     int  setting,     /* configuration option to change */
  431.     void *  pValue       /* new value for parameter */
  432.     )
  433.     {
  434.     struct in_addr target;
  435.     short interval;
  436.     int result = OK;
  437.     /* Don't change settings if message transmission in progress. */
  438.     semTake (sntpsMutexSem, WAIT_FOREVER);
  439.     if (setting == SNTPS_ADDRESS)
  440.         {
  441.         target.s_addr = inet_addr ( (char *)pValue);
  442.         if (target.s_addr == ERROR)
  443.             {
  444.             errnoSet (S_sntpsLib_INVALID_PARAMETER);
  445.             result = ERROR; 
  446.             }
  447.         else
  448.             sntpsDstAddr.s_addr = target.s_addr;
  449.         }
  450.     else if (setting == SNTPS_DELAY)
  451.         {
  452.         interval = (short) (*( (int *)pValue));
  453.         sntpsInterval = interval;
  454.         }
  455.     else
  456.         {
  457.         errnoSet (S_sntpsLib_INVALID_PARAMETER);
  458.         result = ERROR;
  459.         }
  460.     semGive (sntpsMutexSem);
  461.     return (result);
  462.     }
  463. /*******************************************************************************
  464. *
  465. * sntpsStart - execute the SNTP server
  466. *
  467. * This routine monitors the specified SNTP/NTP port for incoming requests from
  468. * clients and transmits replies containing the NTP timestamp obtained from
  469. * the hook provided by the user. If the server executes in broadcast mode,
  470. * this routine also schedules the transmission of NTP messages at the assigned
  471. * broadcast interval. It is the entry point for the SNTP server task and should
  472. * only be called internally.
  473. *
  474. * RETURNS: N/A
  475. *
  476. * ERRNO: N/A
  477. *
  478. * NOMANUAL
  479. */
  480. LOCAL void sntpsStart (void)
  481.     {
  482.     SNTP_PACKET sntpRequest;     /* SNTP request received from client */
  483.     SNTP_PACKET sntpReply;       /* buffer for server reply */
  484.  
  485.     struct sockaddr_in srcAddr;  /* address of requesting SNTP/NTP client */
  486.     struct sockaddr_in dstAddr;  /* target address of transmission */
  487.     int sntpSocket;
  488.     int result;
  489.     int addrLen;
  490.     SNTP_TIMESTAMP refTime;
  491.     BOOL unsync;
  492.     if (!sntpsInitialized)    /* Sanity check to force initialization. */
  493.         return;
  494.     addrLen = sizeof (dstAddr);
  495.     /* Set address information. */
  496.     bzero ( (char *)&srcAddr, sizeof(srcAddr));
  497.     bzero ( (char *)&dstAddr, sizeof(dstAddr));
  498.     srcAddr.sin_addr.s_addr = INADDR_ANY;
  499.     srcAddr.sin_family = AF_INET;
  500.     srcAddr.sin_port = sntpsPort;
  501.   
  502.     /* Create UDP socket and bind to the SNTP port. */
  503.   
  504.     sntpSocket = socket (AF_INET, SOCK_DGRAM, 0);
  505.     if (sntpSocket == -1) 
  506.         return;
  507.     result = bind (sntpSocket, (struct sockaddr *)&srcAddr, sizeof (srcAddr));
  508.     if (result == -1)
  509.         {
  510.         close (sntpSocket);
  511.         return;
  512.         }
  513.  
  514.     /* 
  515.      * The use of sntpsInterval below doesn't need to be guarded from a call to
  516.      * sntpsConfigSet() because this routine is called during system startup.
  517.      */
  518.     if (sntpsMode == SNTP_ACTIVE)
  519.         wdStart (sntpsTimer, sntpsInterval * sysClkRateGet (),
  520.                  (FUNCPTR)netJobAdd, (int)sntpsMsgSend);
  521.     FOREVER 
  522.         {
  523.         result = recvfrom (sntpSocket, (caddr_t)&sntpRequest, 
  524.                            sizeof (sntpRequest), 0, 
  525.                            (struct sockaddr *)&dstAddr, &addrLen);
  526.         if (result == -1)
  527.             continue;
  528.         semTake (sntpsMutexSem, WAIT_FOREVER);   /* Lock out clock changes. */
  529.         /* Can't transmit messages if no access to clock is provided. */
  530.         if (!sntpsClockReady || sntpsClockHookRtn == NULL)
  531.             {
  532.             semGive (sntpsMutexSem);
  533.             continue;
  534.             }
  535.         /* All timestamp fields are zero by default. */
  536.         bzero ( (char *)&sntpReply, sizeof (sntpReply));
  537.         /* Retrieve the current clock ID, precision, and NTP timestamp. */
  538.         sntpReply.precision = sntpsPrecision;
  539.         sntpReply.referenceIdentifier = sntpsClockId;
  540.         unsync = FALSE;
  541.         result = (* sntpsClockHookRtn) (SNTPS_TIME, &refTime);
  542.         if (result == ERROR)
  543.             unsync = TRUE;
  544.         semGive (sntpsMutexSem);
  545.         /* Set the leap indicator and version number. */
  546.         sntpReply.leapVerMode = 0;
  547.         if (unsync)
  548.             {
  549.             sntpReply.stratum = SNTP_STRATUM_0;
  550.             sntpReply.leapVerMode |= SNTP_LI_3;
  551.             }
  552.         else
  553.             {
  554.             sntpReply.stratum = SNTP_STRATUM_1;
  555.             sntpReply.leapVerMode |= SNTP_LI_0;
  556.             }
  557.         sntpReply.leapVerMode |= (sntpRequest.leapVerMode & SNTP_VN_MASK);
  558.         /* Set mode to server for client response, or to symmetric passive. */
  559.         if ( (sntpRequest.leapVerMode & SNTP_MODE_MASK) == SNTP_MODE_3)
  560.             sntpReply.leapVerMode |= SNTP_MODE_4;
  561.         else
  562.             sntpReply.leapVerMode |= SNTP_MODE_2;
  563.         /* Copy the poll field from the request. */
  564.         sntpReply.poll = sntpRequest.poll;
  565.         /* 
  566.          * Leave the root delay and root dispersion fields at zero.
  567.          * Set the timestamp fields and send the message.
  568.          */
  569.         if (!unsync)
  570.             {
  571.             sntpReply.referenceTimestampSec = htonl (refTime.seconds);
  572.             sntpReply.referenceTimestampFrac = htonl (refTime.fraction);
  573.       
  574.             sntpReply.receiveTimestampSec = sntpReply.referenceTimestampSec;
  575.             sntpReply.receiveTimestampFrac = sntpReply.referenceTimestampFrac;
  576.             sntpReply.transmitTimestampSec = sntpReply.referenceTimestampSec;
  577.             sntpReply.transmitTimestampFrac = sntpReply.referenceTimestampFrac;
  578.             /* The originate timestamp contains the request transmit time. */
  579.             sntpReply.originateTimestampSec = sntpRequest.transmitTimestampSec;
  580.             sntpReply.originateTimestampFrac =
  581.                                              sntpRequest.transmitTimestampFrac;
  582.             }
  583.         result = sendto (sntpSocket, (caddr_t)&sntpReply, sizeof (sntpReply), 
  584.                           0, (struct sockaddr *)&dstAddr, sizeof (dstAddr));
  585.         }
  586.     /* Not reached. */
  587.     close (sntpSocket);
  588.     return;
  589.     }
  590. /*******************************************************************************
  591. *
  592. * sntpsMsgSend - transmit an unsolicited NTP message
  593. *
  594. * This routine sends an NTP message to the assigned destination address when 
  595. * the broadcast interval has elapsed.  It is called by watchdog timers set
  596. * during initialization, and should not be used directly.
  597. *
  598. * RETURNS: N/A
  599. *
  600. * ERRNO: N/A
  601. *
  602. * NOMANUAL
  603. */
  604. void sntpsMsgSend (void)
  605.     {
  606.     SNTP_PACKET sntpReply;
  607.     int result;
  608.     int optval;
  609.     short interval;
  610.     SNTP_TIMESTAMP refTime;
  611.     int sntpSocket;
  612.     struct sockaddr_in dstAddr;
  613.     if (!sntpsInitialized)    /* Sanity check to prevent direct calls. */
  614.         return;
  615.     /* Lock out clock and configuration changes. */
  616.     semTake (sntpsMutexSem, WAIT_FOREVER);
  617.     /* Can't transmit messages if no access to clock is provided. */
  618.     if (!sntpsClockReady || sntpsClockHookRtn == NULL)
  619.         {
  620.         semGive (sntpsMutexSem);
  621.         wdStart (sntpsTimer, sntpsInterval * sysClkRateGet (),
  622.                  (FUNCPTR)netJobAdd, (int)sntpsMsgSend);
  623.         return;
  624.         }
  625.     interval = sntpsInterval;    /* Save current broadcast interval. */
  626.     /* Retrieve the current clock ID, precision, and NTP timestamp. */
  627.     sntpReply.precision = sntpsPrecision;
  628.     sntpReply.referenceIdentifier = sntpsClockId;
  629.     result = (* sntpsClockHookRtn) (SNTPS_TIME, &refTime);
  630.     if (result == ERROR)
  631.         {
  632.         semGive (sntpsMutexSem);
  633.         wdStart (sntpsTimer, sntpsInterval * sysClkRateGet (),
  634.                  (FUNCPTR)netJobAdd, (int)sntpsMsgSend);
  635.         return;
  636.         }
  637.     /* Assign target address for outgoing message. */
  638.     bzero ( (char *)&dstAddr, sizeof(dstAddr));
  639.     dstAddr.sin_addr.s_addr = sntpsDstAddr.s_addr;
  640.     dstAddr.sin_family = AF_INET;
  641.     dstAddr.sin_port = sntpsPort;
  642.     semGive (sntpsMutexSem);
  643.   
  644.     /* Create UDP socket for transmission. */
  645.   
  646.     sntpSocket = socket (AF_INET, SOCK_DGRAM, 0);
  647.     if (sntpSocket == -1) 
  648.         {
  649.         wdStart (sntpsTimer, interval * sysClkRateGet (),
  650.                  (FUNCPTR)netJobAdd, (int)sntpsMsgSend);
  651.         return;
  652.         }
  653.     /* Enable broadcast option for socket. */
  654.     optval = 1;
  655.     result = setsockopt (sntpSocket, SOL_SOCKET, SO_BROADCAST, (char *)&optval,
  656.                          sizeof (optval));
  657.     if (result == ERROR)
  658.         {
  659.         close (sntpSocket);
  660.         wdStart (sntpsTimer, interval * sysClkRateGet (),
  661.                  (FUNCPTR)netJobAdd, (int)sntpsMsgSend);
  662.         return;
  663.         }
  664.     /* 
  665.      * Set the common values for outgoing NTP messages - root delay
  666.      * and root dispersion are 0. 
  667.      */
  668.   
  669.     bzero ((char *)&sntpReply, sizeof (sntpReply));
  670.     sntpReply.stratum = SNTP_STRATUM_1;
  671.       
  672.     /* Set the leap indicator, version number and mode. */
  673.     sntpReply.leapVerMode |= SNTP_LI_0;
  674.     sntpReply.leapVerMode |= SNTP_VN_3;
  675.     sntpReply.leapVerMode |= SNTP_MODE_5;
  676.     /* Set the poll field: find the nearest integral power of two. */
  677.     sntpReply.poll = sntpsLog2Get (interval);
  678.     /* Set the timestamp fields and send the message. */
  679.     sntpReply.referenceTimestampSec = htonl (refTime.seconds);
  680.     sntpReply.referenceTimestampFrac = htonl (refTime.fraction);
  681.       
  682.     sntpReply.receiveTimestampSec = sntpReply.referenceTimestampSec;
  683.     sntpReply.receiveTimestampFrac = sntpReply.referenceTimestampFrac;
  684.     sntpReply.transmitTimestampSec = sntpReply.referenceTimestampSec;
  685.     sntpReply.transmitTimestampFrac = sntpReply.referenceTimestampFrac;
  686.     sntpReply.originateTimestampSec = sntpReply.referenceTimestampSec;
  687.     sntpReply.originateTimestampFrac = sntpReply.referenceTimestampFrac;
  688.     result = sendto (sntpSocket, (caddr_t)&sntpReply, sizeof (sntpReply), 0, 
  689.                      (struct sockaddr *)&dstAddr, sizeof (dstAddr));
  690.     close (sntpSocket);
  691.     /* Schedule a new transmission after the broadcast interval. */
  692.     wdStart (sntpsTimer, interval * sysClkRateGet (),
  693.              (FUNCPTR)netJobAdd, (int)sntpsMsgSend);
  694.     return;
  695.     }