source: rtems/cpukit/libnetworking/lib/rtems_bsdnet_ntp.c @ b2a1ea3

4.104.114.84.95
Last change on this file since b2a1ea3 was 126405d9, checked in by Joel Sherrill <joel.sherrill@…>, on 04/24/01 at 21:02:03

2000-04-24 Eric Norum <eric.norum@…>

  • lib/rtems_bsdnet_ntp.c: Modifications to make the RTEMS NTP synchronization a little more robust -- no NTP daemon yet, but at least it trys a little harder when the primary NTP server is down.
  • Property mode set to 100644
File size: 4.6 KB
Line 
1/*
2 * Synchronize with an NTP server
3 *
4 * This program may be distributed and used for any purpose.
5 * I ask only that you:
6 *      1. Leave this author information intact.
7 *      2. Document any changes you make.
8 *
9 * W. Eric Norum
10 * Canadian Light Source
11 * University of Saskatchewan
12 * Saskatoon, Saskatchewan, CANADA
13 * eric@cls.usask.ca
14 *
15 *  $Id$
16 */
17
18#include <stdio.h>
19#include <string.h>
20#include <errno.h>
21#include <time.h>
22#include <limits.h>
23#include <rtems.h>
24#include <rtems/rtems_bsdnet.h>
25#include <rtems/error.h>
26#include <sys/types.h>
27#include <sys/socket.h>
28#include <netinet/in.h>
29
30/*
31 * RTEMS base: 1988, January 1
32 *  UNIX base: 1970, January 1
33 *   NTP base: 1900, January 1
34 */
35#define UNIX_BASE_TO_NTP_BASE (((70UL*365UL)+17UL) * (24*60*60))
36
37struct timestamp {
38        rtems_unsigned32        integer;
39        rtems_unsigned32        fraction;
40};
41
42struct ntpPacketSmall {
43        rtems_unsigned8         li_vn_mode;
44        rtems_unsigned8         stratum;
45        rtems_signed8           poll_interval;
46        rtems_signed8           precision;
47        rtems_signed32          root_delay;
48        rtems_signed32          root_dispersion;
49        char                    reference_identifier[4];
50        struct timestamp        reference_timestamp;
51        struct timestamp        originate_timestamp;
52        struct timestamp        receive_timestamp;
53        struct timestamp        transmit_timestamp;
54};
55
56struct ntpPacket {
57        struct ntpPacketSmall   ntp;
58        char                    authenticator[96];
59};
60
61static int
62processPacket (struct ntpPacketSmall *p)
63{
64        time_t tbuf;
65        struct tm *lt;
66        rtems_time_of_day rt;
67        rtems_interval ticks_per_second;
68
69        if (((p->li_vn_mode & (0x7 << 3)) != (3 << 3))
70         || ((p->transmit_timestamp.integer == 0) && (p->transmit_timestamp.fraction == 0)))
71                return 0;
72        rtems_clock_get (RTEMS_CLOCK_GET_TICKS_PER_SECOND, &ticks_per_second);
73        tbuf = ntohl (p->transmit_timestamp.integer) - UNIX_BASE_TO_NTP_BASE - rtems_bsdnet_timeoffset;
74        lt = gmtime (&tbuf);
75        rt.year = lt->tm_year + 1900;
76        rt.month = lt->tm_mon + 1;
77        rt.day = lt->tm_mday;
78        rt.hour = lt->tm_hour;
79        rt.minute = lt->tm_min;
80        rt.second = lt->tm_sec;
81        rt.ticks = ntohl (p->transmit_timestamp.fraction) / (ULONG_MAX / ticks_per_second);
82        if (rt.ticks >= ticks_per_second)
83                rt.ticks = ticks_per_second - 1;
84        rtems_clock_set (&rt);
85        return 1;
86}
87
88static int
89tryServer (int i, int s)
90{
91        int l;
92        struct timeval tv;
93        int farlen;
94        struct sockaddr_in farAddr;
95        struct ntpPacketSmall packet;
96
97        if (i < 0)
98                tv.tv_sec = 80;
99        else
100                tv.tv_sec = 5;
101        tv.tv_usec = 0;
102        if (setsockopt (s, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof tv) < 0) {
103                printf ("Can't set socket receive timeout: %s\n", strerror (errno));
104                close (s);
105                return -1;
106        }
107        if (i >= 0) {
108                memset (&farAddr, 0, sizeof farAddr);
109                farAddr.sin_family = AF_INET;
110                farAddr.sin_port = htons (123);
111                farAddr.sin_addr = rtems_bsdnet_ntpserver[i];
112                memset (&packet, 0, sizeof packet);
113                packet.li_vn_mode = (3 << 3) | 3; /* NTP version 3, client */
114                l = sendto (s, &packet, sizeof packet, 0, (struct sockaddr *)&farAddr, sizeof farAddr);
115                if (l != sizeof packet) {
116                        printf ("Can't send: %s\n", strerror (errno));
117                        return -1;
118                }
119        }
120        farlen = sizeof farAddr;
121        i = recvfrom (s, &packet, sizeof packet, 0, (struct sockaddr *)&farAddr, &farlen);
122        if (i == 0)
123                printf ("Unexpected EOF");
124        if (i < 0) {
125                if ((errno == EWOULDBLOCK) || (errno == EAGAIN))
126                        return -1;
127                printf ("Can't receive: %s\n", strerror (errno));
128        }
129        if ((i >= sizeof packet) && processPacket (&packet))
130                return 0;
131        return -1;
132}
133
134int
135rtems_bsdnet_synchronize_ntp (int interval, rtems_task_priority priority)
136{
137        int s;
138        int i;
139        int retry;
140        struct sockaddr_in myAddr;
141        int reuseFlag;
142        int ret;
143
144        if (interval != 0) {
145                printf ("Daemon-mode note yet supported.\n");
146                errno = EINVAL;
147                return -1;
148        }
149        s = socket (AF_INET, SOCK_DGRAM, 0);
150        if (s < 0) {
151                printf ("Can't create socket: %s\n", strerror (errno));
152                return -1;
153        }
154        reuseFlag = 1;
155        if (setsockopt (s, SOL_SOCKET, SO_REUSEADDR, (char *)&reuseFlag, sizeof reuseFlag) < 0) {
156                printf ("Can't set socket reuse: %s\n", strerror (errno));
157                close (s);
158                return -1;
159        }
160        memset (&myAddr, 0, sizeof myAddr);
161        myAddr.sin_family = AF_INET;
162        myAddr.sin_port = htons (123);
163        myAddr.sin_addr.s_addr = htonl (INADDR_ANY);
164        if (bind (s, (struct sockaddr *)&myAddr, sizeof myAddr) < 0) {
165                printf ("Can't bind socket: %s\n", strerror (errno));
166                close (s);
167                return -1;
168        }
169        ret = -1;
170        for (retry = 0 ; (ret == -1) && (retry < 5) ; retry++) {
171                /*
172                 * If there's no server we just have to wait
173                 * and hope that there's an NTP broadcast
174                 * server out there somewhere.
175                 */
176                if (rtems_bsdnet_ntpserver_count < 0) {
177                        ret = tryServer (-1, s);
178                }
179                else {
180                        for (i = 0 ; (ret == -1) && (i < rtems_bsdnet_ntpserver_count) ; i++) {
181                                ret = tryServer (i, s);
182                        }
183                }
184        }
185        close (s);
186        return ret;
187}
Note: See TracBrowser for help on using the repository browser.