sntp.c 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. /*
  2. * Copyright (C) 2001-2003 by egnite Software GmbH. All rights reserved.
  3. *
  4. * Redistribution and use in source and binary forms, with or without
  5. * modification, are permitted provided that the following conditions
  6. * are met:
  7. *
  8. * 1. Redistributions of source code must retain the above copyright
  9. * notice, this list of conditions and the following disclaimer.
  10. * 2. Redistributions in binary form must reproduce the above copyright
  11. * notice, this list of conditions and the following disclaimer in the
  12. * documentation and/or other materials provided with the distribution.
  13. * 3. Neither the name of the copyright holders nor the names of
  14. * contributors may be used to endorse or promote products derived
  15. * from this software without specific prior written permission.
  16. *
  17. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  18. * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  19. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  20. * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  21. * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  22. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  23. * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
  24. * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
  25. * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  26. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
  27. * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  28. * SUCH DAMAGE.
  29. *
  30. * For additional information see http://www.ethernut.de/
  31. *
  32. * Thanks to Lars H. Andersson, who submitted the first idea of this simple function
  33. */
  34. /*!
  35. * \file pro/sntp.c
  36. * \brief Simple Network Time Protocol Client.
  37. *
  38. * \verbatim
  39. *
  40. * $Log$
  41. * Revision 1.11 2009/02/13 14:52:05 haraldkipp
  42. * Include memdebug.h for heap management debugging support.
  43. *
  44. * Revision 1.10 2009/02/06 15:40:29 haraldkipp
  45. * Using newly available strdup() and calloc().
  46. * Replaced NutHeap routines by standard malloc/free.
  47. * Replaced pointer value 0 by NULL.
  48. *
  49. * Revision 1.9 2008/08/11 07:00:36 haraldkipp
  50. * BSD types replaced by stdint types (feature request #1282721).
  51. *
  52. * Revision 1.8 2005/08/03 11:46:59 olereinhardt
  53. * Removed unneeded comment line to fix compile bug
  54. *
  55. * Revision 1.7 2005/08/02 17:47:04 haraldkipp
  56. * Major API documentation update.
  57. *
  58. * Revision 1.6 2005/04/08 15:20:51 olereinhardt
  59. * added <sys/types.h> (__APPLE__) and <netinet/in.h> (__linux__)
  60. * for htons and simmilar.
  61. *
  62. * Revision 1.5 2005/04/05 17:44:57 haraldkipp
  63. * Made stack space configurable.
  64. *
  65. * Revision 1.4 2003/11/26 12:55:35 drsung
  66. * Portability issues ... again
  67. *
  68. * Revision 1.3 2003/11/26 11:16:44 haraldkipp
  69. * Portability issues
  70. *
  71. * Revision 1.2 2003/11/24 21:01:42 drsung
  72. * Now using UDP packet queue.
  73. *
  74. * Revision 1.1 2003/11/24 18:13:22 drsung
  75. * first release
  76. *
  77. * \endverbatim
  78. */
  79. #include <cfg/sntp.h>
  80. #include <pro/sntp.h>
  81. #include <sys/socket.h>
  82. #include <sys/heap.h>
  83. #include <stdlib.h>
  84. #include <string.h>
  85. #include "../crt/ctime.h"
  86. #include <stdio.h>
  87. #include <memdebug.h>
  88. #include <sys/thread.h>
  89. #include <sys/timer.h>
  90. #include <sys/types.h>
  91. #include <netinet/in.h>
  92. /*!
  93. * \addtogroup xgSntp
  94. */
  95. /*@{*/
  96. #ifndef NUT_THREAD_SNTPSTACK
  97. #define NUT_THREAD_SNTPSTACK 256
  98. #endif
  99. typedef struct _sntpframe sntpframe;
  100. struct _sntpframe {
  101. uint8_t mode;
  102. uint8_t stratum;
  103. uint8_t poll;
  104. uint8_t precision;
  105. uint32_t root_delay;
  106. uint32_t root_dispersion;
  107. uint32_t reference_identifier;
  108. uint32_t reference_ts_sec;
  109. uint32_t reference_ts_frac;
  110. uint32_t originate_ts_sec;
  111. uint32_t originate_ts_frac;
  112. uint32_t receive_ts_sec;
  113. uint32_t receive_ts_frac;
  114. uint32_t transmit_ts_sec;
  115. uint32_t transmit_ts_frac;
  116. };
  117. #define NTP_PORT 123
  118. #define SNTP_PORT NTP_PORT
  119. struct SNTP_resync_args {
  120. uint32_t server_addr;
  121. uint32_t interval;
  122. };
  123. THREAD(SNTP_resync, arg)
  124. {
  125. uint32_t server_addr = ((struct SNTP_resync_args *) arg)->server_addr;
  126. uint32_t interval = ((struct SNTP_resync_args *) arg)->interval;
  127. uint32_t cur_server_addr = server_addr;
  128. int retry = 0;
  129. time_t t;
  130. free(arg);
  131. NutThreadSetPriority(63);
  132. for (;;) {
  133. if (NutSNTPGetTime(&cur_server_addr, &t)) { /* if any error retry */
  134. if (cur_server_addr != server_addr && server_addr == 0xFFFFFFFF) {
  135. cur_server_addr = server_addr;
  136. continue;
  137. }
  138. if (retry++ >= 3) { /* if numer of retries >= 3 wait 30 secs before next retry sequence ... */
  139. retry = 0;
  140. NutSleep(30000);
  141. } else /* ... else wait 5 secs for next retry */
  142. NutSleep(5000);
  143. } else { /* no error */
  144. stime(&t); /* so set the time */
  145. retry = 0;
  146. NutSleep(interval); /* and wait the interval time */
  147. }
  148. }
  149. }
  150. int NutSNTPGetTime(uint32_t * server_adr, time_t * t)
  151. {
  152. /*first check the pointers */
  153. uint32_t rec_addr;
  154. UDPSOCKET *sock = NULL; /* the udp socket */
  155. sntpframe *data; /* we're using the heap to save stack space */
  156. uint16_t port; /* source port from incoming packet */
  157. int len;
  158. int result = -1;
  159. /* Set UDP input buffer to 256 bytes */
  160. uint16_t bufsize = 256;
  161. if (t == NULL)
  162. return -1;
  163. if (server_adr == NULL)
  164. return -1;
  165. if ((data = calloc(1, sizeof(*data))) == NULL)
  166. goto error;
  167. sock = NutUdpCreateSocket(0); /* allocate new udp socket */
  168. if (sock == NULL)
  169. goto error;
  170. NutUdpSetSockOpt(sock, SO_RCVBUF, &bufsize, sizeof(bufsize));
  171. data->mode = 0x1B; /* LI, VN and Mode bit fields (all in u_char mode); */
  172. if (NutUdpSendTo(sock, *server_adr, SNTP_PORT, data, sizeof(*data))) /* Send packet to server */
  173. goto error; /* on error return -1 */
  174. retry:
  175. rec_addr = 0;
  176. len = NutUdpReceiveFrom(sock, &rec_addr, &port, data, sizeof(*data), 5000); /* Receive packet with timeout of 5s */
  177. if (len <= 0) {
  178. goto error; /* error or timeout occured */
  179. }
  180. if (port != SNTP_PORT || (data->mode & 0xc0) == 0xc0) /* if source port is not SNTP_PORT or server is not in sync return */
  181. {
  182. if (*server_adr == 0xFFFFFFFF)
  183. goto retry; /* unusable packets will be just ignored. */
  184. else
  185. goto error;
  186. }
  187. *t = ntohl(data->transmit_ts_sec) - (70 * 365 + _LEAP_YEAR_ADJUST) * _DAY_SEC;
  188. *server_adr = rec_addr;
  189. result = 0;
  190. error:
  191. if (sock)
  192. NutUdpDestroySocket(sock);
  193. if (data)
  194. free(data);
  195. return result;
  196. }
  197. int NutSNTPStartThread(uint32_t server_addr, uint32_t interval)
  198. {
  199. struct SNTP_resync_args *arg = malloc(sizeof(struct SNTP_resync_args));
  200. if (!arg)
  201. return -1;
  202. arg->server_addr = server_addr;
  203. arg->interval = interval;
  204. if (NutThreadCreate("sntpc", SNTP_resync, arg,
  205. (NUT_THREAD_SNTPSTACK * NUT_THREAD_STACK_MULT) + NUT_THREAD_STACK_ADD))
  206. return 0;
  207. else {
  208. free(arg);
  209. return -1;
  210. }
  211. }
  212. /*@}*/