summaryrefslogtreecommitdiffstats
path: root/cpukit
diff options
context:
space:
mode:
authorJoel Sherrill <joel.sherrill@OARcorp.com>2004-07-25 15:04:13 +0000
committerJoel Sherrill <joel.sherrill@OARcorp.com>2004-07-25 15:04:13 +0000
commit8d2733f02076e6b11a718a0f4eff8ebbe7713eb7 (patch)
tree8c33f4e08abe26cdb87d63863279aa254df812dd /cpukit
parent2004-07-25 Thomas Rauscher <trauscher@loytec.com> (diff)
downloadrtems-8d2733f02076e6b11a718a0f4eff8ebbe7713eb7.tar.bz2
2004-07-25 Till Straumann <strauman@slac.stanford.edu>
PR 620/networking * libnetworking/lib/rtems_bsdnet_ntp.c, libnetworking/rtems/rtems_bsdnet.h: Enhance NTP API.
Diffstat (limited to 'cpukit')
-rw-r--r--cpukit/ChangeLog6
-rw-r--r--cpukit/libnetworking/lib/rtems_bsdnet_ntp.c128
-rw-r--r--cpukit/libnetworking/rtems/rtems_bsdnet.h67
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 <strauman@slac.stanford.edu>
+
+ PR 620/networking
+ * libnetworking/lib/rtems_bsdnet_ntp.c,
+ libnetworking/rtems/rtems_bsdnet.h: Enhance NTP API.
+
2004-07-25 Thomas Rauscher <trauscher@loytec.com>
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);
/*