forked from Imagelibrary/rtems
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.
This commit is contained in:
@@ -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>
|
2004-07-25 Thomas Rauscher <trauscher@loytec.com>
|
||||||
|
|
||||||
PR 609/rtems
|
PR 609/rtems
|
||||||
|
|||||||
@@ -34,41 +34,22 @@
|
|||||||
*/
|
*/
|
||||||
#define UNIX_BASE_TO_NTP_BASE (((70UL*365UL)+17UL) * (24*60*60))
|
#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 ntpPacket {
|
||||||
struct ntpPacketSmall ntp;
|
struct ntpPacketSmall ntp;
|
||||||
char authenticator[96];
|
char authenticator[96];
|
||||||
};
|
};
|
||||||
|
|
||||||
static int
|
static int
|
||||||
processPacket (struct ntpPacketSmall *p)
|
processPacket (struct ntpPacketSmall *p, int state, void *unused)
|
||||||
{
|
{
|
||||||
time_t tbuf;
|
time_t tbuf;
|
||||||
struct tm *lt;
|
struct tm *lt;
|
||||||
rtems_time_of_day rt;
|
rtems_time_of_day rt;
|
||||||
rtems_interval ticks_per_second;
|
rtems_interval ticks_per_second;
|
||||||
|
|
||||||
if (((p->li_vn_mode & (0x7 << 3)) != (3 << 3))
|
if ( state )
|
||||||
|| ((p->transmit_timestamp.integer == 0) && (p->transmit_timestamp.fraction == 0)))
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
rtems_clock_get (RTEMS_CLOCK_GET_TICKS_PER_SECOND, &ticks_per_second);
|
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;
|
tbuf = ntohl (p->transmit_timestamp.integer) - UNIX_BASE_TO_NTP_BASE - rtems_bsdnet_timeoffset;
|
||||||
lt = gmtime (&tbuf);
|
lt = gmtime (&tbuf);
|
||||||
@@ -82,25 +63,46 @@ processPacket (struct ntpPacketSmall *p)
|
|||||||
if (rt.ticks >= ticks_per_second)
|
if (rt.ticks >= ticks_per_second)
|
||||||
rt.ticks = ticks_per_second - 1;
|
rt.ticks = ticks_per_second - 1;
|
||||||
rtems_clock_set (&rt);
|
rtems_clock_set (&rt);
|
||||||
return 1;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
tryServer (int i, int s)
|
getServerTimespec(struct ntpPacketSmall *p, int state, void *usr_data)
|
||||||
{
|
{
|
||||||
int l;
|
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, rtems_bsdnet_ntp_callback_t callback, void *usr_data)
|
||||||
|
{
|
||||||
|
int l = 0;
|
||||||
struct timeval tv;
|
struct timeval tv;
|
||||||
int farlen;
|
int farlen;
|
||||||
struct sockaddr_in farAddr;
|
struct sockaddr_in farAddr;
|
||||||
struct ntpPacketSmall packet;
|
struct ntpPacketSmall packet;
|
||||||
|
|
||||||
if (i < 0)
|
if (i < 0)
|
||||||
tv.tv_sec = 80;
|
tv.tv_sec = rtems_bsdnet_ntp_bcast_timeout_secs;
|
||||||
else
|
else
|
||||||
tv.tv_sec = 5;
|
tv.tv_sec = rtems_bsdnet_ntp_timeout_secs;
|
||||||
tv.tv_usec = 0;
|
tv.tv_usec = 0;
|
||||||
if (setsockopt (s, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof tv) < 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);
|
close (s);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -111,49 +113,57 @@ tryServer (int i, int s)
|
|||||||
farAddr.sin_addr = rtems_bsdnet_ntpserver[i];
|
farAddr.sin_addr = rtems_bsdnet_ntpserver[i];
|
||||||
memset (&packet, 0, sizeof packet);
|
memset (&packet, 0, sizeof packet);
|
||||||
packet.li_vn_mode = (3 << 3) | 3; /* NTP version 3, client */
|
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);
|
l = sendto (s, &packet, sizeof packet, 0, (struct sockaddr *)&farAddr, sizeof farAddr);
|
||||||
if (l != sizeof packet) {
|
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;
|
return -1;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
if ( callback( &packet, -1, usr_data ) )
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
farlen = sizeof farAddr;
|
farlen = sizeof farAddr;
|
||||||
i = recvfrom (s, &packet, sizeof packet, 0, (struct sockaddr *)&farAddr, &farlen);
|
i = recvfrom (s, &packet, sizeof packet, 0, (struct sockaddr *)&farAddr, &farlen);
|
||||||
if (i == 0)
|
if (i == 0)
|
||||||
printf ("Unexpected EOF");
|
fprintf (stderr, "rtems_bsdnet_get_ntp() Unexpected EOF");
|
||||||
if (i < 0) {
|
if (i < 0) {
|
||||||
if ((errno == EWOULDBLOCK) || (errno == EAGAIN))
|
if ((errno == EWOULDBLOCK) || (errno == EAGAIN))
|
||||||
return -1;
|
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 0;
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int rtems_bsdnet_get_ntp(int sock, rtems_bsdnet_ntp_callback_t callback, void *usr_data)
|
||||||
rtems_bsdnet_synchronize_ntp (int interval, rtems_task_priority priority)
|
|
||||||
{
|
{
|
||||||
int s;
|
int s = -1;
|
||||||
int i;
|
int i;
|
||||||
int retry;
|
int retry;
|
||||||
struct sockaddr_in myAddr;
|
struct sockaddr_in myAddr;
|
||||||
int reuseFlag;
|
int reuseFlag;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (interval != 0) {
|
if ( !callback )
|
||||||
printf ("Daemon-mode note yet supported.\n");
|
callback = getServerTimespec;
|
||||||
errno = EINVAL;
|
|
||||||
return -1;
|
if ( sock < 0 ) {
|
||||||
}
|
|
||||||
s = socket (AF_INET, SOCK_DGRAM, 0);
|
s = socket (AF_INET, SOCK_DGRAM, 0);
|
||||||
if (s < 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;
|
return -1;
|
||||||
}
|
}
|
||||||
reuseFlag = 1;
|
reuseFlag = 1;
|
||||||
if (setsockopt (s, SOL_SOCKET, SO_REUSEADDR, (char *)&reuseFlag, sizeof reuseFlag) < 0) {
|
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);
|
close (s);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -162,26 +172,40 @@ rtems_bsdnet_synchronize_ntp (int interval, rtems_task_priority priority)
|
|||||||
myAddr.sin_port = htons (123);
|
myAddr.sin_port = htons (123);
|
||||||
myAddr.sin_addr.s_addr = htonl (INADDR_ANY);
|
myAddr.sin_addr.s_addr = htonl (INADDR_ANY);
|
||||||
if (bind (s, (struct sockaddr *)&myAddr, sizeof myAddr) < 0) {
|
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);
|
close (s);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
sock = s;
|
||||||
|
}
|
||||||
ret = -1;
|
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
|
* If there's no server we just have to wait
|
||||||
* and hope that there's an NTP broadcast
|
* and hope that there's an NTP broadcast
|
||||||
* server out there somewhere.
|
* server out there somewhere.
|
||||||
*/
|
*/
|
||||||
if (rtems_bsdnet_ntpserver_count < 0) {
|
if (rtems_bsdnet_ntpserver_count < 0) {
|
||||||
ret = tryServer (-1, s);
|
ret = tryServer (-1, sock, callback, usr_data);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
for (i = 0 ; (ret == -1) && (i < rtems_bsdnet_ntpserver_count) ; i++) {
|
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;
|
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);
|
||||||
|
}
|
||||||
|
|||||||
@@ -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 (void);
|
||||||
void rtems_bsdnet_do_bootp_and_rootfs (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);
|
int rtems_bsdnet_synchronize_ntp (int interval, rtems_task_priority priority);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
Reference in New Issue
Block a user