[cbccd37] | 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 | |
---|
| 37 | struct timestamp { |
---|
| 38 | rtems_unsigned32 integer; |
---|
| 39 | rtems_unsigned32 fraction; |
---|
| 40 | }; |
---|
| 41 | |
---|
| 42 | struct 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 | |
---|
| 56 | struct ntpPacket { |
---|
| 57 | struct ntpPacketSmall ntp; |
---|
| 58 | char authenticator[96]; |
---|
| 59 | }; |
---|
| 60 | |
---|
| 61 | static int |
---|
| 62 | processPacket (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 | |
---|
| 88 | int |
---|
| 89 | rtems_bsdnet_synchronize_ntp (int interval, rtems_task_priority priority) |
---|
| 90 | { |
---|
| 91 | int s; |
---|
| 92 | int i; |
---|
| 93 | static struct sockaddr_in myAddr, farAddr; |
---|
| 94 | int fromlen; |
---|
| 95 | struct ntpPacketSmall packet; |
---|
| 96 | struct timeval tv; |
---|
| 97 | |
---|
| 98 | if (interval != 0) { |
---|
| 99 | printf ("Daemon-mode note yet supported.\n"); |
---|
| 100 | errno = EINVAL; |
---|
| 101 | return -1; |
---|
| 102 | } |
---|
| 103 | s = socket (AF_INET, SOCK_DGRAM, 0); |
---|
| 104 | if (s < 0) { |
---|
| 105 | printf ("Can't create socket: %s\n", strerror (errno)); |
---|
| 106 | return -1; |
---|
| 107 | } |
---|
| 108 | tv.tv_sec = 5; |
---|
| 109 | tv.tv_usec = 0; |
---|
| 110 | if (setsockopt (s, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof tv) < 0) { |
---|
| 111 | printf ("Can't set socket receive timeout: %s", strerror (errno)); |
---|
| 112 | return -1; |
---|
| 113 | } |
---|
| 114 | memset (&myAddr, sizeof myAddr, 0); |
---|
| 115 | myAddr.sin_family = AF_INET; |
---|
| 116 | myAddr.sin_port = htons (123); |
---|
| 117 | myAddr.sin_addr.s_addr = htonl (INADDR_ANY); |
---|
| 118 | if (bind (s, (struct sockaddr *)&myAddr, sizeof myAddr) < 0) { |
---|
| 119 | printf ("Can't bind socket: %s\n", strerror (errno)); |
---|
| 120 | return -1; |
---|
| 121 | } |
---|
| 122 | for (;;) { |
---|
| 123 | /* |
---|
| 124 | * If there's no server we just have to wait |
---|
| 125 | * and hope that there's an NTP broadcast |
---|
| 126 | * server out there somewhere. |
---|
| 127 | */ |
---|
| 128 | if (rtems_bsdnet_ntpserver_count > 0) { |
---|
| 129 | memset (&farAddr, sizeof farAddr, 0); |
---|
| 130 | farAddr.sin_family = AF_INET; |
---|
| 131 | farAddr.sin_port = htons (123); |
---|
| 132 | /* |
---|
| 133 | * For now, try only the first server. |
---|
| 134 | */ |
---|
| 135 | farAddr.sin_addr = rtems_bsdnet_ntpserver[0]; |
---|
| 136 | memset (&packet, sizeof packet, 0); |
---|
| 137 | packet.li_vn_mode = (3 << 3) | 3; /* NTP version 3, client */ |
---|
| 138 | i = sendto (s, &packet, sizeof packet, 0, (struct sockaddr *)&farAddr, sizeof farAddr); |
---|
| 139 | if (i != sizeof packet) { |
---|
| 140 | printf ("Can't send: %s\n", strerror (errno)); |
---|
| 141 | return -1; |
---|
| 142 | } |
---|
| 143 | } |
---|
| 144 | fromlen = sizeof farAddr; |
---|
| 145 | i = recvfrom (s, &packet, sizeof packet, 0, (struct sockaddr *)&farAddr, &fromlen); |
---|
| 146 | if (i == 0) |
---|
| 147 | rtems_panic ("EOF"); |
---|
| 148 | if (i < 0) { |
---|
[fc0b91c] | 149 | if ((errno == EWOULDBLOCK) || (errno == EAGAIN)) |
---|
[cbccd37] | 150 | continue; |
---|
| 151 | rtems_panic ("Can't receive: %s", strerror (errno)); |
---|
| 152 | } |
---|
| 153 | if (i >= sizeof packet) { |
---|
| 154 | if (processPacket (&packet)) |
---|
| 155 | return 0; |
---|
| 156 | } |
---|
| 157 | } |
---|
| 158 | } |
---|