Example of HTTPServer with additional features: * SNTPClient, DST rules * Link status indication * Local or SDCard-based WebServer * RPC-able class * Static and Dynamic HTML 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 Tue Jul 12 2022 17:12:14 by 1.7.2