ntp.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464
  1. /*
  2. *
  3. * (C) 2014 David Lettier.
  4. * (C) 2018 Armink (armink.ztl@gmail.com)
  5. *
  6. * http://www.lettier.com/
  7. *
  8. * NTP client.
  9. *
  10. * Compiled with gcc version 4.7.2 20121109 (Red Hat 4.7.2-8) (GCC).
  11. *
  12. * Tested on Linux 3.8.11-200.fc18.x86_64 #1 SMP Wed May 1 19:44:27 UTC 2013 x86_64 x86_64 x86_64 GNU/Linux.
  13. * Tested on RT-Thread 3.0.0+
  14. *
  15. * To compile: $ gcc main.c -o ntpClient.out
  16. *
  17. * Usage: $ ./ntpClient.out
  18. *
  19. * Change Logs:
  20. * Date Author Notes
  21. * 2018-02-10 armink the first version
  22. * 2020-07-21 Chenxuan C++ support
  23. * 2021-05-09 Meco Man remove timezone function
  24. */
  25. #include <rtthread.h>
  26. #include <stdio.h>
  27. #include <stdlib.h>
  28. #include <string.h>
  29. #include <sys/time.h>
  30. #include <sys/types.h>
  31. #include <rtdevice.h>
  32. #if defined(RT_USING_SAL)
  33. #include <arpa/inet.h>
  34. #include <sys/socket.h>
  35. #include <netdb.h>
  36. #elif defined(RT_USING_LWIP)
  37. #include <lwip/inet.h>
  38. #include <lwip/sockets.h>
  39. #include <lwip/netdb.h>
  40. extern struct hostent *gethostbyname(const char *name);
  41. extern int recvfrom(int s, void *mem, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen);
  42. extern int sendto(int s, const void *dataptr, size_t size, int flags, const struct sockaddr *to, socklen_t tolen);
  43. extern int socket(int domain, int type, int protocol);
  44. extern int closesocket(int s);
  45. #endif /* RT_USING_SAL */
  46. #if defined(RT_USING_NETDEV)
  47. #include <netdev.h>
  48. #elif defined(RT_USING_LWIP)
  49. #include <lwip/netif.h>
  50. #endif /* RT_USING_NETDEV */
  51. #define DBG_SECTION_NAME "ntp"
  52. #define DBG_LEVEL DBG_INFO
  53. #include <rtdbg.h>
  54. #if RT_VER_NUM <= 0x40003
  55. #ifndef NETUTILS_NTP_TIMEZONE
  56. #define NETUTILS_NTP_TIMEZONE 8
  57. #endif
  58. #endif
  59. #ifdef NETUTILS_NTP_HOSTNAME
  60. #define NTP_HOSTNAME1 NETUTILS_NTP_HOSTNAME
  61. #else
  62. #define NTP_HOSTNAME1 NULL
  63. #endif
  64. #ifdef NETUTILS_NTP_HOSTNAME2
  65. #define NTP_HOSTNAME2 NETUTILS_NTP_HOSTNAME2
  66. #else
  67. #define NTP_HOSTNAME2 NULL
  68. #endif
  69. #ifdef NETUTILS_NTP_HOSTNAME3
  70. #define NTP_HOSTNAME3 NETUTILS_NTP_HOSTNAME3
  71. #else
  72. #define NTP_HOSTNAME3 NULL
  73. #endif
  74. #define NTP_TIMESTAMP_DELTA 2208988800ull
  75. #define LI(packet) (uint8_t) ((packet.li_vn_mode & 0xC0) >> 6) /* (li & 11 000 000) >> 6 */
  76. #define VN(packet) (uint8_t) ((packet.li_vn_mode & 0x38) >> 3) /* (vn & 00 111 000) >> 3 */
  77. #define MODE(packet) (uint8_t) ((packet.li_vn_mode & 0x07) >> 0) /* (mode & 00 000 111) >> 0 */
  78. /* Structure that defines the 48 byte NTP packet protocol */
  79. typedef struct {
  80. uint8_t li_vn_mode; /* Eight bits. li, vn, and mode */
  81. /* li. Two bits. Leap indicator */
  82. /* vn. Three bits. Version number of the protocol */
  83. /* mode. Three bits. Client will pick mode 3 for client */
  84. uint8_t stratum; /* Eight bits. Stratum level of the local clock */
  85. uint8_t poll; /* Eight bits. Maximum interval between successive messages */
  86. uint8_t precision; /* Eight bits. Precision of the local clock */
  87. uint32_t rootDelay; /* 32 bits. Total round trip delay time */
  88. uint32_t rootDispersion; /* 32 bits. Max error aloud from primary clock source */
  89. uint32_t refId; /* 32 bits. Reference clock identifier */
  90. uint32_t refTm_s; /* 32 bits. Reference time-stamp seconds */
  91. uint32_t refTm_f; /* 32 bits. Reference time-stamp fraction of a second */
  92. uint32_t origTm_s; /* 32 bits. Originate time-stamp seconds */
  93. uint32_t origTm_f; /* 32 bits. Originate time-stamp fraction of a second */
  94. uint32_t rxTm_s; /* 32 bits. Received time-stamp seconds */
  95. uint32_t rxTm_f; /* 32 bits. Received time-stamp fraction of a second */
  96. uint32_t txTm_s; /* 32 bits and the most important field the client cares about. Transmit time-stamp seconds */
  97. uint32_t txTm_f; /* 32 bits. Transmit time-stamp fraction of a second */
  98. } ntp_packet; /* Total: 384 bits or 48 bytes */
  99. static ntp_packet packet = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
  100. static int sendto_ntp_server(int sockfd, const char *host_name, struct sockaddr_in *serv_addr)
  101. {
  102. struct hostent *server;
  103. socklen_t addr_len = sizeof(struct sockaddr_in);
  104. /* NTP UDP port number. */
  105. int portno = 123;
  106. server = gethostbyname(host_name);
  107. if (server == NULL)
  108. {
  109. LOG_D("No such host(%s)", host_name);
  110. return -RT_ERROR;
  111. }
  112. else
  113. {
  114. /* Zero out the server address structure. */
  115. rt_memset((char *)serv_addr, 0, addr_len);
  116. serv_addr->sin_family = AF_INET;
  117. /* Convert the port number integer to network big-endian style and save it to the server address structure. */
  118. serv_addr->sin_port = htons(portno);
  119. /* Copy the server's IP address to the server address structure. */
  120. rt_memcpy(&serv_addr->sin_addr.s_addr, (char *) server->h_addr, server->h_length);
  121. return sendto(sockfd, (char *) &packet, sizeof(ntp_packet), 0, (const struct sockaddr *)serv_addr, addr_len);
  122. }
  123. }
  124. /**
  125. * Get the UTC time from NTP server
  126. *
  127. * @param host_name NTP server host name, NULL: will using default host name
  128. *
  129. * @note this function is not reentrant
  130. *
  131. * @return >0: success, current GMT time
  132. * =0: get failed
  133. */
  134. time_t ntp_get_time(const char *host_name)
  135. {
  136. /* the delay(ms) between two receive */
  137. #define RECV_TIME_DELAY_MS 10
  138. /* NTP receive timeout(S) */
  139. #define NTP_GET_TIMEOUT 5
  140. /* number of NTP servers */
  141. #define NTP_SERVER_NUM 3
  142. int sockfd, n, i = 0, server_num = 0;
  143. struct sockaddr_in serv_addr[NTP_SERVER_NUM];
  144. rt_tick_t start = 0;
  145. time_t new_time = 0;
  146. socklen_t addr_len = sizeof(struct sockaddr_in);
  147. const char *const host_name_buf[NTP_SERVER_NUM] = {NTP_HOSTNAME1, NTP_HOSTNAME2, NTP_HOSTNAME3};
  148. /* Create and zero out the packet. All 48 bytes worth. */
  149. rt_memset(&packet, 0, sizeof(ntp_packet));
  150. /* Set the first byte's bits to 00,011,011 for li = 0, vn = 3, and mode = 3. The rest will be left set to zero.
  151. Represents 27 in base 10 or 00011011 in base 2. */
  152. *((char *) &packet + 0) = 0x1b;
  153. #if defined(RT_USING_NETDEV) || defined(RT_USING_LWIP)
  154. {
  155. #define NTP_INTERNET 0x02
  156. #define NTP_INTERNET_BUFF_LEN 18
  157. #define NTP_INTERNET_MONTH_LEN 4
  158. #define NTP_INTERNET_DATE_LEN 16
  159. #ifndef SW_VER_NUM
  160. #define SW_VER_NUM 0x00000000
  161. #endif
  162. const char month[][NTP_INTERNET_MONTH_LEN] =
  163. {"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"};
  164. char date[NTP_INTERNET_DATE_LEN] = {0};
  165. uint8_t send_data[NTP_INTERNET_BUFF_LEN] = {0};
  166. uint8_t index, moth_num = 0;
  167. uint16_t check = 0;
  168. /* get build moth value*/
  169. rt_snprintf(date, NTP_INTERNET_DATE_LEN, "%s", __DATE__);
  170. for (index = 0; index < sizeof(month) / NTP_INTERNET_MONTH_LEN; index++)
  171. {
  172. if (rt_memcmp(date, month[index], NTP_INTERNET_MONTH_LEN - 1) == 0)
  173. {
  174. moth_num = index + 1;
  175. break;
  176. }
  177. }
  178. send_data[0] = NTP_INTERNET;
  179. /* get hardware address */
  180. {
  181. #if defined(RT_USING_LWIP) && !defined(RT_USING_NETDEV)
  182. #define netdev netif
  183. #define netdev_default netif_default
  184. #endif
  185. extern struct netdev *netdev_default;
  186. struct netdev *dev = netdev_default;
  187. for (index = 0; index < dev->hwaddr_len; index++)
  188. {
  189. send_data[index + 1] = dev->hwaddr[index] + moth_num;
  190. }
  191. }
  192. send_data[9] = RT_VERSION;
  193. send_data[10] = RT_SUBVERSION;
  194. send_data[11] = RT_REVISION;
  195. send_data[12] = (uint8_t)(SW_VER_NUM >> 24);
  196. send_data[13] = (uint8_t)(SW_VER_NUM >> 16);
  197. send_data[14] = (uint8_t)(SW_VER_NUM >> 8);
  198. send_data[15] = (uint8_t)(SW_VER_NUM & 0xFF);
  199. /* get the check value */
  200. for (index = 0; index < NTP_INTERNET_BUFF_LEN - sizeof(check); index++)
  201. {
  202. check += (uint8_t)send_data[index];
  203. }
  204. send_data[NTP_INTERNET_BUFF_LEN - 2] = check >> 8;
  205. send_data[NTP_INTERNET_BUFF_LEN - 1] = check & 0xFF;
  206. rt_memcpy(((char *)&packet + 4), send_data, NTP_INTERNET_BUFF_LEN);
  207. }
  208. #endif /* RT_USING_NETDEV || RT_USING_LWIP */
  209. /* Create a UDP socket. */
  210. sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
  211. if (sockfd < 0)
  212. {
  213. LOG_E("Create socket failed");
  214. return 0;
  215. }
  216. if (host_name)
  217. {
  218. /* access the incoming host_name server */
  219. if (sendto_ntp_server(sockfd, host_name, serv_addr) >= 0)
  220. {
  221. server_num = 1;
  222. }
  223. }
  224. else
  225. {
  226. /* use the static default NTP server */
  227. for (i = 0; i < NTP_SERVER_NUM; i++)
  228. {
  229. if (host_name_buf[i] == NULL || strlen(host_name_buf[i]) == 0)
  230. continue;
  231. if (sendto_ntp_server(sockfd, host_name_buf[i], &serv_addr[server_num]) >= 0)
  232. {
  233. server_num ++;
  234. }
  235. }
  236. }
  237. if (server_num <= 0)
  238. {
  239. closesocket(sockfd);
  240. return 0;
  241. }
  242. start = rt_tick_get();
  243. while (rt_tick_get() <= start + NTP_GET_TIMEOUT * RT_TICK_PER_SECOND)
  244. {
  245. for (i = 0; i < server_num; i++)
  246. {
  247. /* non-blocking receive the packet back from the server. If n == -1, it failed. */
  248. n = recvfrom(sockfd, (char *) &packet, sizeof(ntp_packet), MSG_DONTWAIT, (struct sockaddr *)&serv_addr[i], &addr_len);
  249. if (n <= 0)
  250. {
  251. LOG_D("Reading from server %s error (%d).", inet_ntoa(serv_addr[i].sin_addr.s_addr), n);
  252. }
  253. else if (n > 0)
  254. {
  255. goto __exit;
  256. }
  257. }
  258. rt_thread_mdelay(RECV_TIME_DELAY_MS);
  259. }
  260. __exit:
  261. if (rt_tick_get() <= start + NTP_GET_TIMEOUT * RT_TICK_PER_SECOND)
  262. {
  263. /* These two fields contain the time-stamp seconds as the packet left the NTP server.
  264. The number of seconds correspond to the seconds passed since 1900.
  265. ntohl() converts the bit/byte order from the network's to host's "endianness". */
  266. packet.txTm_s = ntohl(packet.txTm_s); // Time-stamp seconds.
  267. packet.txTm_f = ntohl(packet.txTm_f); // Time-stamp fraction of a second.
  268. /* Extract the 32 bits that represent the time-stamp seconds (since NTP epoch) from when the packet left the server.
  269. Subtract 70 years worth of seconds from the seconds since 1900.
  270. This leaves the seconds since the UNIX epoch of 1970.
  271. (1900)------------------(1970)**************************************(Time Packet Left the Server) */
  272. new_time = (time_t)(packet.txTm_s - NTP_TIMESTAMP_DELTA);
  273. }
  274. else
  275. {
  276. LOG_E("Receive the socket from server timeout (%dS).", NTP_GET_TIMEOUT);
  277. }
  278. closesocket(sockfd);
  279. return new_time;
  280. }
  281. #if RT_VER_NUM <= 0x40003
  282. /**
  283. * Get the local time from NTP server
  284. *
  285. * @param host_name NTP server host name, NULL: will using default host name
  286. *
  287. * @return >0: success, current local time, offset timezone by NETUTILS_NTP_TIMEZONE
  288. * =0: get failed
  289. */
  290. time_t ntp_get_local_time(const char *host_name)
  291. {
  292. time_t cur_time = ntp_get_time(host_name);
  293. if (cur_time)
  294. {
  295. /* add the timezone offset for set_time/set_date */
  296. cur_time += NETUTILS_NTP_TIMEZONE * 3600;
  297. }
  298. return cur_time;
  299. }
  300. #endif /*RT_VER_NUM <= 0x40003*/
  301. /**
  302. * Sync current local time to RTC by NTP
  303. *
  304. * @param host_name NTP server host name, NULL: will using default host name
  305. *
  306. * @return >0: success
  307. * =0: sync failed
  308. */
  309. time_t ntp_sync_to_rtc(const char *host_name)
  310. {
  311. #if RT_VER_NUM <= 0x40003
  312. time_t cur_time = ntp_get_local_time(host_name);
  313. #else
  314. time_t cur_time = ntp_get_time(host_name); /*after v4.0.3, RT-Thread takes over the timezone management*/
  315. #endif /*RT_VER_NUM <= 0x40003*/
  316. if (cur_time)
  317. {
  318. #ifdef RT_USING_RTC
  319. #if RT_VER_NUM <= 0x40003
  320. struct tm *cur_tm;
  321. cur_tm = localtime(&cur_time);
  322. set_time(cur_tm->tm_hour, cur_tm->tm_min, cur_tm->tm_sec);
  323. cur_tm = localtime(&cur_time);
  324. set_date(cur_tm->tm_year + 1900, cur_tm->tm_mon + 1, cur_tm->tm_mday);
  325. #else
  326. rt_device_control(rt_device_find("rtc"), RT_DEVICE_CTRL_RTC_SET_TIME, &cur_time);
  327. #endif /*RT_VER_NUM <= 0x40003*/
  328. LOG_I("Get local time from NTP server: %s", ctime((const time_t *) &cur_time));
  329. #else
  330. LOG_E("The system time update failed. Please enable RT_USING_RTC.\n");
  331. cur_time = 0;
  332. #endif /* RT_USING_RTC */
  333. }
  334. return cur_time;
  335. }
  336. #if RT_VER_NUM > 0x40003
  337. #ifdef NTP_USING_AUTO_SYNC
  338. #ifndef NTP_AUTO_SYNC_THREAD_STACK_SIZE
  339. #define NTP_AUTO_SYNC_THREAD_STACK_SIZE (1500)
  340. #endif
  341. /* NTP first sync delay time for network connect, unit: second */
  342. #ifndef NTP_AUTO_SYNC_FIRST_DELAY
  343. #define NTP_AUTO_SYNC_FIRST_DELAY (30)
  344. #endif
  345. /* NTP sync period, unit: second */
  346. #ifndef NTP_AUTO_SYNC_PERIOD
  347. #define NTP_AUTO_SYNC_PERIOD (1L*60L*60L)
  348. #endif
  349. static void ntp_sync_thread_enrty(void *param)
  350. {
  351. /* first sync delay for network connect */
  352. rt_thread_delay(NTP_AUTO_SYNC_FIRST_DELAY * RT_TICK_PER_SECOND);
  353. while (1)
  354. {
  355. ntp_sync_to_rtc(NULL);
  356. rt_thread_delay(NTP_AUTO_SYNC_PERIOD * RT_TICK_PER_SECOND);
  357. }
  358. }
  359. static int ntp_auto_sync_init(void)
  360. {
  361. static rt_bool_t init_ok = RT_FALSE;
  362. rt_thread_t thread;
  363. if (init_ok)
  364. {
  365. return 0;
  366. }
  367. thread = rt_thread_create("ntp-sync", ntp_sync_thread_enrty, RT_NULL,
  368. NTP_AUTO_SYNC_THREAD_STACK_SIZE, RT_THREAD_PRIORITY_MAX - 2, 20);
  369. if (thread)
  370. {
  371. rt_thread_startup(thread);
  372. }
  373. else
  374. {
  375. return -RT_ENOMEM;
  376. }
  377. init_ok = RT_TRUE;
  378. return RT_EOK;
  379. }
  380. INIT_COMPONENT_EXPORT(ntp_auto_sync_init);
  381. #endif /*NTP_USING_AUTO_SYNC*/
  382. #endif /*RT_VER_NUM > 0x40003*/
  383. #ifdef FINSH_USING_MSH
  384. #include <finsh.h>
  385. static void cmd_ntp_sync(int argc, char **argv)
  386. {
  387. char *host_name = NULL;
  388. if (argc > 1)
  389. {
  390. host_name = argv[1];
  391. }
  392. ntp_sync_to_rtc(host_name);
  393. }
  394. MSH_CMD_EXPORT_ALIAS(cmd_ntp_sync, ntp_sync, Update time by NTP(Network Time Protocol): ntp_sync [host_name]);
  395. #endif /* RT_USING_FINSH */