Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
sntp.c
00001 /** 00002 * @file 00003 * SNTP client module 00004 * 00005 */ 00006 00007 /* 00008 * Redistribution and use in source and binary forms, with or without modification, 00009 * are permitted provided that the following conditions are met: 00010 * 00011 * 1. Redistributions of source code must retain the above copyright notice, 00012 * this list of conditions and the following disclaimer. 00013 * 2. Redistributions in binary form must reproduce the above copyright notice, 00014 * this list of conditions and the following disclaimer in the documentation 00015 * and/or other materials provided with the distribution. 00016 * 3. The name of the author may not be used to endorse or promote products 00017 * derived from this software without specific prior written permission. 00018 * 00019 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 00020 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 00021 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 00022 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 00023 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 00024 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 00025 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 00026 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 00027 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 00028 * OF SUCH DAMAGE. 00029 * 00030 * This file is part of the lwIP TCP/IP stack. 00031 * 00032 * Author: Simon Goldschmidt (lwIP raw API part) 00033 */ 00034 00035 #include "lwip/opt.h" 00036 00037 //#include "sntp.h" 00038 00039 #include "lwip/sys.h" 00040 #include "lwip/sockets.h" 00041 #include "lwip/udp.h" 00042 #include "lwip/dns.h" 00043 00044 #include "sntp.h" // [iva2k] moving below for re-defines 00045 00046 #include <string.h> 00047 #include <time.h> 00048 #define static 00049 /** This is simple "SNTP" client for socket or raw API. 00050 * It is a minimal implementation of SNTPv4 as specified in RFC 4330. 00051 * 00052 * For a list of some public NTP servers, see this link : 00053 * http://support.ntp.org/bin/view/Servers/NTPPoolServers 00054 * 00055 * @todo: 00056 * - set/change servers at runtime 00057 * - complete SNTP_CHECK_RESPONSE checks 3 and 4 00058 * - support broadcast/multicast mode? 00059 */ 00060 00061 /** Decide whether to build SNTP for socket or raw API 00062 * The socket API SNTP client is a very minimal implementation that does not 00063 * fully confor to the SNTPv4 RFC, especially regarding server load and error 00064 * procesing. */ 00065 #ifndef SNTP_SOCKET 00066 #define SNTP_SOCKET 0 00067 #endif 00068 00069 /** 00070 * SNTP_DEBUG: Enable debugging for SNTP. 00071 */ 00072 #ifndef SNTP_DEBUG 00073 #define SNTP_DEBUG LWIP_DBG_OFF 00074 #endif 00075 00076 /** SNTP server port */ 00077 #ifndef SNTP_PORT 00078 #define SNTP_PORT 123 00079 #endif 00080 00081 /** Set this to 1 to allow SNTP_SERVER_ADDRESS to be a DNS name */ 00082 #ifndef SNTP_SERVER_DNS 00083 #define SNTP_SERVER_DNS 0 00084 #endif 00085 00086 /** Set this to 1 to support more than one server */ 00087 #ifndef SNTP_SUPPORT_MULTIPLE_SERVERS 00088 #define SNTP_SUPPORT_MULTIPLE_SERVERS 0 00089 #endif 00090 00091 /** SNTP server address: 00092 * - as IPv4 address in "u32_t" format 00093 * - as a DNS name if SNTP_SERVER_DNS is set to 1 00094 * May contain multiple server names (e.g. "pool.ntp.org","second.time.server") 00095 */ 00096 #ifndef SNTP_SERVER_ADDRESS 00097 #if SNTP_SERVER_DNS 00098 #define SNTP_SERVER_ADDRESS "pool.ntp.org" 00099 #else 00100 #define SNTP_SERVER_ADDRESS "213.161.194.93" /* pool.ntp.org */ 00101 #endif 00102 #endif 00103 00104 /** Sanity check: 00105 * Define this to 00106 * - 0 to turn off sanity checks (default; smaller code) 00107 * - >= 1 to check address and port of the response packet to ensure the 00108 * response comes from the server we sent the request to. 00109 * - >= 2 to check returned Originate Timestamp against Transmit Timestamp 00110 * sent to the server (to ensure response to older request). 00111 * - >= 3 @todo: discard reply if any of the LI, Stratum, or Transmit Timestamp 00112 * fields is 0 or the Mode field is not 4 (unicast) or 5 (broadcast). 00113 * - >= 4 @todo: to check that the Root Delay and Root Dispersion fields are each 00114 * greater than or equal to 0 and less than infinity, where infinity is 00115 * currently a cozy number like one second. This check avoids using a 00116 * server whose synchronization source has expired for a very long time. 00117 */ 00118 #ifndef SNTP_CHECK_RESPONSE 00119 #define SNTP_CHECK_RESPONSE 0 00120 #endif 00121 00122 /** According to the RFC, this shall be a random delay 00123 * between 1 and 5 minutes (in milliseconds) to prevent load peaks. 00124 * This can be defined to a random generation function, 00125 * which must return the delay in milliseconds as u32_t. 00126 * Turned off by default. 00127 */ 00128 #ifndef SNTP_STARTUP_DELAY 00129 #define SNTP_STARTUP_DELAY 0 00130 #endif 00131 00132 /** SNTP receive timeout - in milliseconds 00133 * Also used as retry timeout - this shouldn't be too low. 00134 * Default is 3 seconds. 00135 */ 00136 #ifndef SNTP_RECV_TIMEOUT 00137 #define SNTP_RECV_TIMEOUT 3000 00138 #endif 00139 00140 /** SNTP update delay - in milliseconds 00141 * Default is 1 hour. 00142 */ 00143 #ifndef SNTP_UPDATE_DELAY 00144 #define SNTP_UPDATE_DELAY 3600000 00145 #endif 00146 #if (SNTP_UPDATE_DELAY < 15000) && !SNTP_SUPPRESS_DELAY_CHECK 00147 #error "SNTPv4 RFC 4330 enforces a minimum update time of 15 seconds!" 00148 #endif 00149 00150 /** SNTP macro to change system time and/or the update the RTC clock */ 00151 #ifndef SNTP_SET_SYSTEM_TIME 00152 #define SNTP_SET_SYSTEM_TIME(sec) 00153 #endif 00154 00155 /** SNTP macro to change system time including microseconds */ 00156 #ifdef SNTP_SET_SYSTEM_TIME_US 00157 #define SNTP_CALC_TIME_US 1 00158 #define SNTP_RECEIVE_TIME_SIZE 2 00159 #else 00160 #define SNTP_SET_SYSTEM_TIME_US(sec, us) 00161 #define SNTP_CALC_TIME_US 0 00162 #define SNTP_RECEIVE_TIME_SIZE 1 00163 #endif 00164 00165 /** SNTP macro to get system time, used with SNTP_CHECK_RESPONSE >= 2 00166 * to send in request and compare in response. 00167 */ 00168 #ifndef SNTP_GET_SYSTEM_TIME 00169 #define SNTP_GET_SYSTEM_TIME(sec, us) do { (sec) = 0; (us) = 0; } while(0) 00170 #endif 00171 00172 /** Default retry timeout (in milliseconds) if the response 00173 * received is invalid. 00174 * This is doubled with each retry until SNTP_RETRY_TIMEOUT_MAX is reached. 00175 */ 00176 #ifndef SNTP_RETRY_TIMEOUT 00177 #define SNTP_RETRY_TIMEOUT SNTP_RECV_TIMEOUT 00178 #endif 00179 00180 /** Maximum retry timeout (in milliseconds). */ 00181 #ifndef SNTP_RETRY_TIMEOUT_MAX 00182 #define SNTP_RETRY_TIMEOUT_MAX (SNTP_RETRY_TIMEOUT * 10) 00183 #endif 00184 00185 /** Increase retry timeout with every retry sent 00186 * Default is on to conform to RFC. 00187 */ 00188 #ifndef SNTP_RETRY_TIMEOUT_EXP 00189 #define SNTP_RETRY_TIMEOUT_EXP 1 00190 #endif 00191 00192 /* the various debug levels for this file */ 00193 #define SNTP_DEBUG_TRACE (SNTP_DEBUG | LWIP_DBG_TRACE) 00194 #define SNTP_DEBUG_STATE (SNTP_DEBUG | LWIP_DBG_STATE) 00195 #define SNTP_DEBUG_WARN (SNTP_DEBUG | LWIP_DBG_LEVEL_WARNING) 00196 #define SNTP_DEBUG_WARN_STATE (SNTP_DEBUG | LWIP_DBG_LEVEL_WARNING | LWIP_DBG_STATE) 00197 #define SNTP_DEBUG_SERIOUS (SNTP_DEBUG | LWIP_DBG_LEVEL_SERIOUS) 00198 00199 #define SNTP_ERR_KOD 1 00200 00201 /* SNTP protocol defines */ 00202 #define SNTP_MSG_LEN 48 00203 00204 #define SNTP_OFFSET_LI_VN_MODE 0 00205 #define SNTP_LI_MASK 0xC0 00206 #define SNTP_LI_NO_WARNING 0x00 00207 #define SNTP_LI_LAST_MINUTE_61_SEC 0x01 00208 #define SNTP_LI_LAST_MINUTE_59_SEC 0x02 00209 #define SNTP_LI_ALARM_CONDITION 0x03 /* (clock not synchronized) */ 00210 00211 #define SNTP_VERSION_MASK 0x38 00212 #define SNTP_VERSION (4/* NTP Version 4*/<<3) 00213 00214 #define SNTP_MODE_MASK 0x07 00215 #define SNTP_MODE_CLIENT 0x03 00216 #define SNTP_MODE_SERVER 0x04 00217 #define SNTP_MODE_BROADCAST 0x05 00218 00219 #define SNTP_OFFSET_STRATUM 1 00220 #define SNTP_STRATUM_KOD 0x00 00221 00222 #define SNTP_OFFSET_ORIGINATE_TIME 24 00223 #define SNTP_OFFSET_RECEIVE_TIME 32 00224 #define SNTP_OFFSET_TRANSMIT_TIME 40 00225 00226 /* number of seconds between 1900 and 1970 */ 00227 #define DIFF_SEC_1900_1970 (2208988800) 00228 00229 /** 00230 * SNTP packet format (without optional fields) 00231 * Timestamps are coded as 64 bits: 00232 * - 32 bits seconds since Jan 01, 1970, 00:00 00233 * - 32 bits seconds fraction (0-padded) 00234 * For future use, if the MSB in the seconds part is set, seconds are based 00235 * on Feb 07, 2036, 06:28:16. 00236 */ 00237 #ifdef PACK_STRUCT_USE_INCLUDES 00238 # include "arch/bpstruct.h" 00239 #endif 00240 PACK_STRUCT_BEGIN 00241 struct sntp_msg { 00242 PACK_STRUCT_FIELD(u8_t li_vn_mode); 00243 PACK_STRUCT_FIELD(u8_t stratum); 00244 PACK_STRUCT_FIELD(u8_t poll); 00245 PACK_STRUCT_FIELD(u8_t precision); 00246 PACK_STRUCT_FIELD(u32_t root_delay); 00247 PACK_STRUCT_FIELD(u32_t root_dispersion); 00248 PACK_STRUCT_FIELD(u32_t reference_identifier); 00249 PACK_STRUCT_FIELD(u32_t reference_timestamp[2]); 00250 PACK_STRUCT_FIELD(u32_t originate_timestamp[2]); 00251 PACK_STRUCT_FIELD(u32_t receive_timestamp[2]); 00252 PACK_STRUCT_FIELD(u32_t transmit_timestamp[2]); 00253 } PACK_STRUCT_STRUCT; 00254 PACK_STRUCT_END 00255 #ifdef PACK_STRUCT_USE_INCLUDES 00256 # include "arch/epstruct.h" 00257 #endif 00258 00259 /* function prototypes */ 00260 static void sntp_request(void *arg); 00261 00262 /** The UDP pcb used by the SNTP client */ 00263 static struct udp_pcb* sntp_pcb; 00264 /** Addresses of servers */ 00265 static char* sntp_server_addresses[] = {SNTP_SERVER_ADDRESS}; 00266 #if SNTP_SUPPORT_MULTIPLE_SERVERS 00267 /** The currently used server (initialized to 0) */ 00268 static u8_t sntp_current_server; 00269 static u8_t sntp_num_servers = sizeof(sntp_server_addresses)/sizeof(char*); 00270 #else /* SNTP_SUPPORT_MULTIPLE_SERVERS */ 00271 #define sntp_current_server 0 00272 #endif /* SNTP_SUPPORT_MULTIPLE_SERVERS */ 00273 00274 #if SNTP_RETRY_TIMEOUT_EXP 00275 #define SNTP_RESET_RETRY_TIMEOUT() sntp_retry_timeout = SNTP_RETRY_TIMEOUT 00276 /** Retry time, initialized with SNTP_RETRY_TIMEOUT and doubled with each retry. */ 00277 static u32_t sntp_retry_timeout; 00278 #else /* SNTP_RETRY_TIMEOUT_EXP */ 00279 #define SNTP_RESET_RETRY_TIMEOUT() 00280 #define sntp_retry_timeout SNTP_RETRY_TIMEOUT 00281 #endif /* SNTP_RETRY_TIMEOUT_EXP */ 00282 00283 #if SNTP_CHECK_RESPONSE >= 1 00284 /** Saves the last server address to compare with response */ 00285 static struct ip_addr sntp_last_server_address; 00286 #endif /* SNTP_CHECK_RESPONSE >= 1 */ 00287 00288 #if SNTP_CHECK_RESPONSE >= 2 00289 /** Saves the last timestamp sent (which is sent back by the server) 00290 * to compare against in response */ 00291 static u32_t sntp_last_timestamp_sent[2]; 00292 #endif /* SNTP_CHECK_RESPONSE >= 2 */ 00293 00294 /** 00295 * SNTP processing of received timestamp 00296 */ 00297 static void 00298 sntp_process(u32_t *receive_timestamp) 00299 { 00300 /* convert SNTP time (1900-based) to unix GMT time (1970-based) 00301 * @todo: if MSB is 1, SNTP time is 2036-based! 00302 */ 00303 time_t t = (ntohl(receive_timestamp[0]) - DIFF_SEC_1900_1970); 00304 00305 #if SNTP_CALC_TIME_US 00306 u32_t us = ntohl(receive_timestamp[1]) / 4295; 00307 SNTP_SET_SYSTEM_TIME_US(t, us); 00308 /* display local time from GMT time */ 00309 LWIP_DEBUGF(SNTP_DEBUG_TRACE, ("sntp_process: %s, %"U32_F" us", ctime(&t), us)); 00310 00311 #else /* SNTP_CALC_TIME_US */ 00312 00313 /* change system time and/or the update the RTC clock */ 00314 SNTP_SET_SYSTEM_TIME(t); 00315 /* display local time from GMT time */ 00316 LWIP_DEBUGF(SNTP_DEBUG_TRACE, ("sntp_process: %s", ctime(&t))); 00317 #endif /* SNTP_CALC_TIME_US */ 00318 } 00319 00320 /** 00321 * Initialize request struct to be sent to server. 00322 */ 00323 static void 00324 sntp_initialize_request(struct sntp_msg *req) 00325 { 00326 memset(req, 0, SNTP_MSG_LEN); 00327 req->li_vn_mode = SNTP_LI_NO_WARNING | SNTP_VERSION | SNTP_MODE_CLIENT; 00328 00329 #if SNTP_CHECK_RESPONSE >= 2 00330 { 00331 u32_t sntp_time_sec, sntp_time_us; 00332 /* fill in transmit timestamp and save it in 'sntp_last_timestamp_sent' */ 00333 SNTP_GET_SYSTEM_TIME(sntp_time_sec, sntp_time_us); 00334 sntp_last_timestamp_sent[0] = htonl(sntp_time_sec + DIFF_SEC_1900_1970); 00335 req->transmit_timestamp[0] = sntp_last_timestamp_sent[0]; 00336 /* we send/save us instead of fraction to be faster... */ 00337 sntp_last_timestamp_sent[1] = htonl(sntp_time_us); 00338 req->transmit_timestamp[1] = sntp_last_timestamp_sent[1]; 00339 } 00340 #endif /* SNTP_CHECK_RESPONSE >= 2 */ 00341 } 00342 00343 #if SNTP_SOCKET 00344 00345 /** 00346 * Send an SNTP request via sockets. 00347 * This is a very minimal implementation that does not fully conform 00348 * to the SNTPv4 RFC, especially regarding server load and error procesing. 00349 */ 00350 static void 00351 sntp_request(void *arg) 00352 { 00353 int sock; 00354 struct sockaddr_in local; 00355 struct sockaddr_in to; 00356 int tolen; 00357 int size; 00358 int timeout; 00359 struct sntp_msg sntpmsg; 00360 u32_t sntp_server_address; 00361 00362 LWIP_UNUSED_ARG(arg); 00363 00364 /* if we got a valid SNTP server address... */ 00365 if (inet_aton(SNTP_SERVER_ADDRESS, (struct in_addr*)&sntp_server_address)) { 00366 /* create new socket */ 00367 sock = lwip_socket(AF_INET, SOCK_DGRAM, 0); 00368 if (sock >= 0) { 00369 /* prepare local address */ 00370 memset(&local, 0, sizeof(local)); 00371 local.sin_family = AF_INET; 00372 local.sin_port = htons(INADDR_ANY); 00373 local.sin_addr.s_addr = htonl(INADDR_ANY); 00374 00375 /* bind to local address */ 00376 if (lwip_bind(sock, (struct sockaddr *)&local, sizeof(local)) == 0) { 00377 /* set recv timeout */ 00378 timeout = SNTP_RECV_TIMEOUT; 00379 lwip_setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(timeout)); 00380 00381 /* prepare SNTP request */ 00382 sntp_initialize_request(&sntpmsg); 00383 00384 /* prepare SNTP server address */ 00385 memset(&to, 0, sizeof(to)); 00386 to.sin_family = AF_INET; 00387 to.sin_port = htons(SNTP_PORT); 00388 to.sin_addr.s_addr = sntp_server_address; 00389 00390 /* send SNTP request to server */ 00391 if (lwip_sendto(sock, &sntpmsg, SNTP_MSG_LEN, 0, (struct sockaddr *)&to, sizeof(to)) >= 0) { 00392 /* receive SNTP server response */ 00393 tolen = sizeof(to); 00394 size = lwip_recvfrom(sock, &sntpmsg, SNTP_MSG_LEN, 0, (struct sockaddr *)&to, (socklen_t *)&tolen); 00395 /* if the response size is good */ 00396 if (size == SNTP_MSG_LEN) { 00397 /* if this is a SNTP response... */ 00398 if (((sntpmsg.li_vn_mode & SNTP_MODE_MASK) == SNTP_MODE_SERVER) || 00399 ((sntpmsg.li_vn_mode & SNTP_MODE_MASK) == SNTP_MODE_BROADCAST)) { 00400 /* do time processing */ 00401 sntp_process(sntpmsg.receive_timestamp); 00402 } else { 00403 LWIP_DEBUGF( SNTP_DEBUG_WARN, ("sntp_request: not response frame code\n")); 00404 } 00405 } 00406 } else { 00407 LWIP_DEBUGF( SNTP_DEBUG_WARN, ("sntp_request: not sendto==%i\n", errno)); 00408 } 00409 } 00410 /* close the socket */ 00411 closesocket(sock); 00412 } 00413 } 00414 } 00415 00416 /** 00417 * SNTP thread 00418 */ 00419 static void 00420 sntp_thread(void *arg) 00421 { 00422 LWIP_UNUSED_ARG(arg); 00423 while(1) { 00424 sntp_request(NULL); 00425 sys_msleep(SNTP_UPDATE_DELAY); 00426 } 00427 } 00428 00429 /** 00430 * Initialize this module when using sockets 00431 */ 00432 void 00433 sntp_init(void) 00434 { 00435 sys_thread_new("sntp_thread", sntp_thread, NULL, DEFAULT_THREAD_STACKSIZE, DEFAULT_THREAD_PRIO); 00436 } 00437 00438 #else /* SNTP_SOCKET */ 00439 00440 /** 00441 * Retry: send a new request (and increase retry timeout). 00442 * 00443 * @param arg is unused (only necessary to conform to sys_timeout) 00444 */ 00445 static void 00446 sntp_retry(void* arg) 00447 { 00448 LWIP_UNUSED_ARG(arg); 00449 00450 LWIP_DEBUGF(SNTP_DEBUG_STATE, ("sntp_retry: Next request will be sent in %"U32_F" ms\n", 00451 sntp_retry_timeout)); 00452 00453 /* set up a timer to send a retry and increase the retry delay */ 00454 sys_timeout(sntp_retry_timeout, sntp_request, NULL); 00455 00456 #if SNTP_RETRY_TIMEOUT_EXP 00457 { 00458 u32_t new_retry_timeout; 00459 /* increase the timeout for next retry */ 00460 new_retry_timeout = sntp_retry_timeout << 1; 00461 /* limit to maximum timeout and prevent overflow */ 00462 if ((new_retry_timeout <= SNTP_RETRY_TIMEOUT_MAX) && 00463 (new_retry_timeout > sntp_retry_timeout)) { 00464 sntp_retry_timeout = new_retry_timeout; 00465 } 00466 } 00467 #endif /* SNTP_RETRY_TIMEOUT_EXP */ 00468 } 00469 00470 #if SNTP_SUPPORT_MULTIPLE_SERVERS 00471 /** 00472 * If Kiss-of-Death is received (or another packet parsing error), 00473 * try the next server or retry the current server and increase the retry 00474 * timeout if only one server is available. 00475 * 00476 * @param arg is unused (only necessary to conform to sys_timeout) 00477 */ 00478 static void 00479 sntp_try_next_server(void* arg) 00480 { 00481 LWIP_UNUSED_ARG(arg); 00482 00483 if (sntp_num_servers > 1) { 00484 /* new server: reset retry timeout */ 00485 SNTP_RESET_RETRY_TIMEOUT(); 00486 sntp_current_server++; 00487 if (sntp_current_server >= sntp_num_servers) { 00488 sntp_current_server = 0; 00489 } 00490 LWIP_DEBUGF(SNTP_DEBUG_STATE, ("sntp_try_next_server: Sending request to server %"U16_F"\n", 00491 (u16_t)sntp_current_server)); 00492 /* instantly send a request to the next server */ 00493 sntp_request(NULL); 00494 } else { 00495 sntp_retry(NULL); 00496 } 00497 } 00498 #else /* SNTP_SUPPORT_MULTIPLE_SERVERS */ 00499 /* Always retry on error if only one server is supported */ 00500 #define sntp_try_next_server sntp_retry 00501 #endif /* SNTP_SUPPORT_MULTIPLE_SERVERS */ 00502 00503 /** UDP recv callback for the sntp pcb */ 00504 static void 00505 sntp_recv(void *arg, struct udp_pcb* pcb, struct pbuf *p, struct ip_addr *addr, u16_t port) 00506 { 00507 u8_t mode; 00508 u8_t stratum; 00509 u32_t receive_timestamp[SNTP_RECEIVE_TIME_SIZE]; 00510 err_t err; 00511 00512 LWIP_UNUSED_ARG(arg); 00513 LWIP_UNUSED_ARG(pcb); 00514 00515 /* packet received: stop retry timeout */ 00516 sys_untimeout(sntp_try_next_server, NULL); 00517 sys_untimeout(sntp_request, NULL); 00518 00519 err = ERR_ARG; 00520 #if SNTP_CHECK_RESPONSE >= 1 00521 /* check server address and port */ 00522 if ((addr->addr == sntp_last_server_address.addr) && 00523 (port == SNTP_PORT)) 00524 #else /* SNTP_CHECK_RESPONSE >= 1 */ 00525 LWIP_UNUSED_ARG(addr); 00526 LWIP_UNUSED_ARG(port); 00527 #endif /* SNTP_CHECK_RESPONSE >= 1 */ 00528 { 00529 /* process the response */ 00530 if (p->tot_len == SNTP_MSG_LEN) { 00531 pbuf_copy_partial(p, &mode, 1, SNTP_OFFSET_LI_VN_MODE); 00532 mode &= SNTP_MODE_MASK; 00533 /* if this is a SNTP response... */ 00534 if ((mode == SNTP_MODE_SERVER) || 00535 (mode == SNTP_MODE_BROADCAST)) { 00536 pbuf_copy_partial(p, &stratum, 1, SNTP_OFFSET_STRATUM); 00537 if (stratum == SNTP_STRATUM_KOD) { 00538 /* Kiss-of-death packet. Use another server or increase UPDATE_DELAY. */ 00539 err = SNTP_ERR_KOD; 00540 LWIP_DEBUGF(SNTP_DEBUG_STATE, ("sntp_recv: Received Kiss-of-Death\n")); 00541 } else { 00542 #if SNTP_CHECK_RESPONSE >= 2 00543 /* check originate_timetamp against sntp_last_timestamp_sent */ 00544 u32_t originate_timestamp[2]; 00545 pbuf_copy_partial(p, &originate_timestamp, 8, SNTP_OFFSET_ORIGINATE_TIME); 00546 if ((originate_timestamp[0] != sntp_last_timestamp_sent[0]) || 00547 (originate_timestamp[1] != sntp_last_timestamp_sent[1])) 00548 { 00549 LWIP_DEBUGF(SNTP_DEBUG_WARN, ("sntp_recv: Invalid originate timestamp in response\n")); 00550 } else 00551 #endif /* SNTP_CHECK_RESPONSE >= 2 */ 00552 /* @todo: add code for SNTP_CHECK_RESPONSE >= 3 and >= 4 here */ 00553 { 00554 /* correct answer */ 00555 err = ERR_OK; 00556 pbuf_copy_partial(p, &receive_timestamp, SNTP_RECEIVE_TIME_SIZE * 4, SNTP_OFFSET_RECEIVE_TIME); 00557 } 00558 } 00559 } else { 00560 LWIP_DEBUGF(SNTP_DEBUG_WARN, ("sntp_recv: Invalid mode in response: %"U16_F"\n", (u16_t)mode)); 00561 } 00562 } else { 00563 LWIP_DEBUGF(SNTP_DEBUG_WARN, ("sntp_recv: Invalid packet length: %"U16_F"\n", p->tot_len)); 00564 } 00565 } 00566 pbuf_free(p); 00567 if (err == ERR_OK) { 00568 /* Correct response, reset retry timeout */ 00569 SNTP_RESET_RETRY_TIMEOUT(); 00570 00571 sntp_process(receive_timestamp); 00572 00573 /* Set up timeout for next request */ 00574 sys_timeout((u32_t)SNTP_UPDATE_DELAY, sntp_request, NULL); 00575 LWIP_DEBUGF(SNTP_DEBUG_STATE, ("sntp_recv: Scheduled next time request: %"U32_F" ms\n", 00576 (u32_t)SNTP_UPDATE_DELAY)); 00577 } else if (err == SNTP_ERR_KOD) { 00578 /* Kiss-of-death packet. Use another server or increase UPDATE_DELAY. */ 00579 sntp_try_next_server(NULL); 00580 } else { 00581 /* another error, try the same server again */ 00582 sntp_retry(NULL); 00583 } 00584 } 00585 00586 /** Actually send an sntp request to a server. 00587 * 00588 * @param server_addr resolved IP address of the SNTP server 00589 */ 00590 static void 00591 sntp_send_request(struct ip_addr *server_addr) 00592 { 00593 struct pbuf* p; 00594 p = pbuf_alloc(PBUF_TRANSPORT, SNTP_MSG_LEN, PBUF_RAM); 00595 if (p != NULL) { 00596 struct sntp_msg *sntpmsg = (struct sntp_msg *)p->payload; 00597 LWIP_DEBUGF(SNTP_DEBUG_STATE, ("sntp_send_request: Sending request to server\n")); 00598 /* initialize request message */ 00599 sntp_initialize_request(sntpmsg); 00600 /* send request */ 00601 udp_sendto(sntp_pcb, p, server_addr, SNTP_PORT); 00602 pbuf_free(p); // [iva2k] fixing memory leak 00603 /* set up receive timeout: try next server or retry on timeout */ 00604 sys_timeout((u32_t)SNTP_RECV_TIMEOUT, sntp_try_next_server, NULL); 00605 #if SNTP_CHECK_RESPONSE >= 1 00606 /* save server address to verify it in sntp_recv */ 00607 sntp_last_server_address.addr = server_addr->addr; 00608 #endif /* SNTP_CHECK_RESPONSE >= 1 */ 00609 } else { 00610 LWIP_DEBUGF(SNTP_DEBUG_SERIOUS, ("sntp_send_request: Out of memory, trying again in %"U32_F" ms\n", 00611 (u32_t)SNTP_RETRY_TIMEOUT)); 00612 /* out of memory: set up a timer to send a retry */ 00613 sys_timeout((u32_t)SNTP_RETRY_TIMEOUT, sntp_request, NULL); 00614 } 00615 } 00616 00617 /** 00618 * DNS found callback when using DNS names as server address. 00619 */ 00620 static void 00621 sntp_dns_found(const char* hostname, struct ip_addr *ipaddr, void *arg) 00622 { 00623 LWIP_UNUSED_ARG(hostname); 00624 LWIP_UNUSED_ARG(arg); 00625 00626 if (ipaddr != NULL) { 00627 /* Address resolved, send request */ 00628 LWIP_DEBUGF(SNTP_DEBUG_STATE, ("sntp_dns_found: Server address resolved, sending request\n")); 00629 sntp_send_request(ipaddr); 00630 } else { 00631 /* DNS resolving failed -> try another server */ 00632 LWIP_DEBUGF(SNTP_DEBUG_WARN_STATE, ("sntp_dns_found: Failed to resolve server address resolved, trying next server\n")); 00633 // sntp_try_next_server(NULL); 00634 // [iva2k] changing to delayed - having no DNS may mean that there is something wrong. don't hang in here. 00635 sys_timeout((u32_t)SNTP_RECV_TIMEOUT, sntp_try_next_server, NULL); 00636 } 00637 } 00638 00639 /** 00640 * Send out an sntp request via raw API. 00641 * 00642 * @param arg is unused (only necessary to conform to sys_timeout) 00643 */ 00644 static void 00645 sntp_request(void *arg) 00646 { 00647 struct ip_addr sntp_server_address; 00648 err_t err; 00649 00650 LWIP_UNUSED_ARG(arg); 00651 00652 /* initialize SNTP server address */ 00653 #if SNTP_SERVER_DNS 00654 err = dns_gethostbyname(sntp_server_addresses[sntp_current_server], &sntp_server_address, 00655 sntp_dns_found, NULL); 00656 if (err == ERR_INPROGRESS) { 00657 /* DNS request sent, wait for sntp_dns_found being called */ 00658 LWIP_DEBUGF(SNTP_DEBUG_STATE, ("sntp_request: Waiting for server address to be resolved.\n")); 00659 return; 00660 } 00661 #else /* SNTP_SERVER_DNS */ 00662 err = inet_aton(sntp_server_addresses[sntp_current_server], (struct in_addr*)&sntp_server_address) 00663 ? ERR_OK : ERR_ARG; 00664 00665 #endif /* SNTP_SERVER_DNS */ 00666 00667 if (err == ERR_OK) { 00668 sntp_send_request(&sntp_server_address); 00669 } else { 00670 /* address conversion failed, try another server */ 00671 LWIP_DEBUGF(SNTP_DEBUG_WARN_STATE, ("sntp_request: Invalid server address, trying next server.\n")); 00672 sys_timeout((u32_t)SNTP_RETRY_TIMEOUT, sntp_try_next_server, NULL); 00673 } 00674 } 00675 00676 /** 00677 * Initialize this module when using raw API. 00678 * Send out request instantly or after SNTP_STARTUP_DELAY. 00679 */ 00680 void 00681 sntp_init(void) 00682 { 00683 SNTP_RESET_RETRY_TIMEOUT(); 00684 sntp_pcb = udp_new(); 00685 LWIP_ASSERT("Failed to allocate udp pcb for sntp client", sntp_pcb != NULL); 00686 if (sntp_pcb != NULL) { 00687 udp_recv(sntp_pcb, sntp_recv, NULL); 00688 #if SNTP_STARTUP_DELAY 00689 sys_timeout((u32_t)SNTP_STARTUP_DELAY, sntp_request, NULL); 00690 #else 00691 sntp_request(NULL); 00692 #endif 00693 } 00694 } 00695 00696 #endif /* SNTP_SOCKET */
Generated on Wed Jul 13 2022 07:13:43 by
1.7.2