From 8d2733f02076e6b11a718a0f4eff8ebbe7713eb7 Mon Sep 17 00:00:00 2001 From: Joel Sherrill Date: Sun, 25 Jul 2004 15:04:13 +0000 Subject: 2004-07-25 Till Straumann PR 620/networking * libnetworking/lib/rtems_bsdnet_ntp.c, libnetworking/rtems/rtems_bsdnet.h: Enhance NTP API. --- cpukit/ChangeLog | 6 ++ cpukit/libnetworking/lib/rtems_bsdnet_ntp.c | 128 +++++++++++++++++----------- cpukit/libnetworking/rtems/rtems_bsdnet.h | 67 +++++++++++++++ 3 files changed, 149 insertions(+), 52 deletions(-) diff --git a/cpukit/ChangeLog b/cpukit/ChangeLog index 65d1a7a6d5..abe63a35da 100644 --- a/cpukit/ChangeLog +++ b/cpukit/ChangeLog @@ -1,3 +1,9 @@ +2004-07-25 Till Straumann + + PR 620/networking + * libnetworking/lib/rtems_bsdnet_ntp.c, + libnetworking/rtems/rtems_bsdnet.h: Enhance NTP API. + 2004-07-25 Thomas Rauscher PR 609/rtems diff --git a/cpukit/libnetworking/lib/rtems_bsdnet_ntp.c b/cpukit/libnetworking/lib/rtems_bsdnet_ntp.c index 50386a2376..38cb779f6a 100644 --- a/cpukit/libnetworking/lib/rtems_bsdnet_ntp.c +++ b/cpukit/libnetworking/lib/rtems_bsdnet_ntp.c @@ -34,41 +34,22 @@ */ #define UNIX_BASE_TO_NTP_BASE (((70UL*365UL)+17UL) * (24*60*60)) -struct timestamp { - uint32_t integer; - uint32_t fraction; -}; - -struct ntpPacketSmall { - uint8_t li_vn_mode; - uint8_t stratum; - int8_t poll_interval; - int8_t precision; - int32_t root_delay; - int32_t root_dispersion; - char reference_identifier[4]; - struct timestamp reference_timestamp; - struct timestamp originate_timestamp; - struct timestamp receive_timestamp; - struct timestamp transmit_timestamp; -}; - struct ntpPacket { struct ntpPacketSmall ntp; char authenticator[96]; }; static int -processPacket (struct ntpPacketSmall *p) +processPacket (struct ntpPacketSmall *p, int state, void *unused) { time_t tbuf; struct tm *lt; rtems_time_of_day rt; rtems_interval ticks_per_second; - if (((p->li_vn_mode & (0x7 << 3)) != (3 << 3)) - || ((p->transmit_timestamp.integer == 0) && (p->transmit_timestamp.fraction == 0))) + if ( state ) return 0; + rtems_clock_get (RTEMS_CLOCK_GET_TICKS_PER_SECOND, &ticks_per_second); tbuf = ntohl (p->transmit_timestamp.integer) - UNIX_BASE_TO_NTP_BASE - rtems_bsdnet_timeoffset; lt = gmtime (&tbuf); @@ -82,25 +63,46 @@ processPacket (struct ntpPacketSmall *p) if (rt.ticks >= ticks_per_second) rt.ticks = ticks_per_second - 1; rtems_clock_set (&rt); - return 1; + return 0; +} + +static int +getServerTimespec(struct ntpPacketSmall *p, int state, void *usr_data) +{ +struct timespec *ts = usr_data; +unsigned long long tmp; + + if ( 0 == state ) { + ts->tv_sec = ntohl( p->transmit_timestamp.integer ); + ts->tv_sec -= rtems_bsdnet_timeoffset + UNIX_BASE_TO_NTP_BASE; + + tmp = 1000000000 * (unsigned long long)ntohl(p->transmit_timestamp.fraction); + + ts->tv_nsec = (unsigned long) (tmp>>32); + } + return 0; } +int rtems_bsdnet_ntp_retry_count = 5; +int rtems_bsdnet_ntp_timeout_secs = 5; +int rtems_bsdnet_ntp_bcast_timeout_secs = 80; + static int -tryServer (int i, int s) +tryServer (int i, int s, rtems_bsdnet_ntp_callback_t callback, void *usr_data) { - int l; + int l = 0; struct timeval tv; int farlen; struct sockaddr_in farAddr; struct ntpPacketSmall packet; if (i < 0) - tv.tv_sec = 80; + tv.tv_sec = rtems_bsdnet_ntp_bcast_timeout_secs; else - tv.tv_sec = 5; + tv.tv_sec = rtems_bsdnet_ntp_timeout_secs; tv.tv_usec = 0; if (setsockopt (s, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof tv) < 0) { - printf ("Can't set socket receive timeout: %s\n", strerror (errno)); + fprintf (stderr, "rtems_bsdnet_get_ntp() Can't set socket receive timeout: %s\n", strerror (errno)); close (s); return -1; } @@ -111,49 +113,57 @@ tryServer (int i, int s) farAddr.sin_addr = rtems_bsdnet_ntpserver[i]; memset (&packet, 0, sizeof packet); packet.li_vn_mode = (3 << 3) | 3; /* NTP version 3, client */ + if ( callback( &packet, 1, usr_data ) ) + return -1; l = sendto (s, &packet, sizeof packet, 0, (struct sockaddr *)&farAddr, sizeof farAddr); if (l != sizeof packet) { - printf ("Can't send: %s\n", strerror (errno)); + fprintf (stderr, "rtems_bsdnet_get_ntp() Can't send: %s\n", strerror (errno)); return -1; } + } else { + if ( callback( &packet, -1, usr_data ) ) + return -1; } farlen = sizeof farAddr; i = recvfrom (s, &packet, sizeof packet, 0, (struct sockaddr *)&farAddr, &farlen); if (i == 0) - printf ("Unexpected EOF"); + fprintf (stderr, "rtems_bsdnet_get_ntp() Unexpected EOF"); if (i < 0) { if ((errno == EWOULDBLOCK) || (errno == EAGAIN)) return -1; - printf ("Can't receive: %s\n", strerror (errno)); + fprintf (stderr, "rtems_bsdnet_get_ntp() Can't receive: %s\n", strerror (errno)); } - if ((i >= sizeof packet) && processPacket (&packet)) + + if ( i >= sizeof packet && + ((packet.li_vn_mode & (0x7 << 3)) == (3 << 3)) && + ((packet.transmit_timestamp.integer != 0) || (packet.transmit_timestamp.fraction != 0)) && + 0 == callback( &packet, 0 , usr_data) ) return 0; + return -1; } -int -rtems_bsdnet_synchronize_ntp (int interval, rtems_task_priority priority) +int rtems_bsdnet_get_ntp(int sock, rtems_bsdnet_ntp_callback_t callback, void *usr_data) { - int s; - int i; - int retry; - struct sockaddr_in myAddr; - int reuseFlag; - int ret; +int s = -1; +int i; +int retry; +struct sockaddr_in myAddr; +int reuseFlag; +int ret; - if (interval != 0) { - printf ("Daemon-mode note yet supported.\n"); - errno = EINVAL; - return -1; - } + if ( !callback ) + callback = getServerTimespec; + + if ( sock < 0 ) { s = socket (AF_INET, SOCK_DGRAM, 0); if (s < 0) { - printf ("Can't create socket: %s\n", strerror (errno)); + fprintf (stderr, "rtems_bsdnet_get_ntp() Can't create socket: %s\n", strerror (errno)); return -1; } reuseFlag = 1; if (setsockopt (s, SOL_SOCKET, SO_REUSEADDR, (char *)&reuseFlag, sizeof reuseFlag) < 0) { - printf ("Can't set socket reuse: %s\n", strerror (errno)); + fprintf (stderr, "rtems_bsdnet_get_ntp() Can't set socket reuse: %s\n", strerror (errno)); close (s); return -1; } @@ -162,26 +172,40 @@ rtems_bsdnet_synchronize_ntp (int interval, rtems_task_priority priority) myAddr.sin_port = htons (123); myAddr.sin_addr.s_addr = htonl (INADDR_ANY); if (bind (s, (struct sockaddr *)&myAddr, sizeof myAddr) < 0) { - printf ("Can't bind socket: %s\n", strerror (errno)); + fprintf (stderr, "rtems_bsdnet_get_ntp() Can't bind socket: %s\n", strerror (errno)); close (s); return -1; } + sock = s; + } ret = -1; - for (retry = 0 ; (ret == -1) && (retry < 5) ; retry++) { + for (retry = 0 ; (ret == -1) && (retry < rtems_bsdnet_ntp_retry_count) ; retry++) { /* * If there's no server we just have to wait * and hope that there's an NTP broadcast * server out there somewhere. */ if (rtems_bsdnet_ntpserver_count < 0) { - ret = tryServer (-1, s); + ret = tryServer (-1, sock, callback, usr_data); } else { for (i = 0 ; (ret == -1) && (i < rtems_bsdnet_ntpserver_count) ; i++) { - ret = tryServer (i, s); + ret = tryServer (i, sock, callback, usr_data); } } } - close (s); + if ( s >= 0 ) + close (s); return ret; } + +int +rtems_bsdnet_synchronize_ntp (int interval, rtems_task_priority priority) +{ + if (interval != 0) { + fprintf (stderr, "Daemon-mode note yet supported.\n"); + errno = EINVAL; + return -1; + } + return rtems_bsdnet_get_ntp( -1, processPacket, 0); +} diff --git a/cpukit/libnetworking/rtems/rtems_bsdnet.h b/cpukit/libnetworking/rtems/rtems_bsdnet.h index e7ac7cd116..960f8cb5a1 100644 --- a/cpukit/libnetworking/rtems/rtems_bsdnet.h +++ b/cpukit/libnetworking/rtems/rtems_bsdnet.h @@ -180,6 +180,73 @@ int rtems_bsdnet_ifconfig (const char *ifname, uint32_t cmd, void *param); void rtems_bsdnet_do_bootp (void); void rtems_bsdnet_do_bootp_and_rootfs (void); +/* NTP tuning parameters */ +extern int rtems_bsdnet_ntp_retry_count; +extern int rtems_bsdnet_ntp_timeout_secs; +extern int rtems_bsdnet_ntp_bcast_timeout_secs; + + +struct timestamp { + rtems_unsigned32 integer; + rtems_unsigned32 fraction; +}; + +/* Data is passed in network byte order */ +struct ntpPacketSmall { + rtems_unsigned8 li_vn_mode; + rtems_unsigned8 stratum; + rtems_signed8 poll_interval; + rtems_signed8 precision; + rtems_signed32 root_delay; + rtems_signed32 root_dispersion; + char reference_identifier[4]; + struct timestamp reference_timestamp; + struct timestamp originate_timestamp; + struct timestamp receive_timestamp; + struct timestamp transmit_timestamp; +}; + +/* NOTE: packet data is *only* accessible from the callback + * + * 'callback' is invoked twice, once prior to sending a request + * to the server and one more time after receiving a valid reply. + * This allows for the user to measure round-trip times. + * + * Semantics of the 'state' parameter: + * + * state == 1: 1st call, just prior to sending request. The + * packet has been set up already but may be + * modified by the callback (e.g. to set the originate + * timestamp). + * state == -1: 1st call - no request will be sent but we'll + * wait for a reply from a broadcast server. The + * packet has not been set up. + * state == 0: 2nd call. The user is responsible for keeping track + * of the 'state' during the first call in order to + * know if it makes sense to calculate 'round-trip' times. + * + * RETURN VALUE: the callback should return 0 if processing the packet was + * successful and -1 on error in which case rtems_bsdnet_get_ntp() + * may try another server. + */ +typedef int (*rtems_bsdnet_ntp_callback_t)( + struct ntpPacketSmall *packet, + int state, + void *usr_data); + +/* Obtain time from a NTP server and call user callback to process data; + * socket parameter may be -1 to request the routine to open and close its own socket. + * Networking parameters as configured are used... + * + * It is legal to pass a NULL callback pointer. In this case, a default callback + * is used which determines the current time by contacting an NTP server. The current + * time is converted to a 'struct timespec' (seconds/nanoseconds) and passed into *usr_data. + * The caller is responsible for providing a memory area >= sizeof(struct timespec). + * + * RETURNS: 0 on success, -1 on failure. + */ +int rtems_bsdnet_get_ntp(int socket, rtems_bsdnet_ntp_callback_t callback, void *usr_data); + int rtems_bsdnet_synchronize_ntp (int interval, rtems_task_priority priority); /* -- cgit v1.2.3