Marco Zecchini
/
Example_RTOS
Rtos API example
Embed:
(wiki syntax)
Show/hide line numbers
lwip_sntp.c
Go to the documentation of this file.
00001 /** 00002 * @file 00003 * SNTP client module 00004 */ 00005 00006 /* 00007 * Copyright (c) 2007-2009 Frédéric Bernon, Simon Goldschmidt 00008 * All rights reserved. 00009 * 00010 * Redistribution and use in source and binary forms, with or without modification, 00011 * are permitted provided that the following conditions are met: 00012 * 00013 * 1. Redistributions of source code must retain the above copyright notice, 00014 * this list of conditions and the following disclaimer. 00015 * 2. Redistributions in binary form must reproduce the above copyright notice, 00016 * this list of conditions and the following disclaimer in the documentation 00017 * and/or other materials provided with the distribution. 00018 * 3. The name of the author may not be used to endorse or promote products 00019 * derived from this software without specific prior written permission. 00020 * 00021 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 00022 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 00023 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 00024 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 00025 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 00026 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 00027 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 00028 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 00029 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 00030 * OF SUCH DAMAGE. 00031 * 00032 * This file is part of the lwIP TCP/IP stack. 00033 * 00034 * Author: Frédéric Bernon, Simon Goldschmidt 00035 */ 00036 00037 00038 /** 00039 * @defgroup sntp SNTP 00040 * @ingroup apps 00041 * 00042 * This is simple "SNTP" client for the lwIP raw API. 00043 * It is a minimal implementation of SNTPv4 as specified in RFC 4330. 00044 * 00045 * For a list of some public NTP servers, see this link : 00046 * http://support.ntp.org/bin/view/Servers/NTPPoolServers 00047 * 00048 * @todo: 00049 * - set/change servers at runtime 00050 * - complete SNTP_CHECK_RESPONSE checks 3 and 4 00051 */ 00052 00053 #include "lwip/apps/sntp.h" 00054 00055 #include "lwip/opt.h" 00056 #include "lwip/timeouts.h" 00057 #include "lwip/udp.h" 00058 #include "lwip/dns.h" 00059 #include "lwip/ip_addr.h" 00060 #include "lwip/pbuf.h" 00061 #include "lwip/dhcp.h" 00062 00063 #include <string.h> 00064 #include <time.h> 00065 00066 #if LWIP_UDP 00067 00068 /* Handle support for more than one server via SNTP_MAX_SERVERS */ 00069 #if SNTP_MAX_SERVERS > 1 00070 #define SNTP_SUPPORT_MULTIPLE_SERVERS 1 00071 #else /* NTP_MAX_SERVERS > 1 */ 00072 #define SNTP_SUPPORT_MULTIPLE_SERVERS 0 00073 #endif /* NTP_MAX_SERVERS > 1 */ 00074 00075 #if (SNTP_UPDATE_DELAY < 15000) && !defined(SNTP_SUPPRESS_DELAY_CHECK) 00076 #error "SNTPv4 RFC 4330 enforces a minimum update time of 15 seconds (define SNTP_SUPPRESS_DELAY_CHECK to disable this error)!" 00077 #endif 00078 00079 /* Configure behaviour depending on microsecond or second precision */ 00080 #ifdef SNTP_SET_SYSTEM_TIME_US 00081 #define SNTP_CALC_TIME_US 1 00082 #define SNTP_RECEIVE_TIME_SIZE 2 00083 #else 00084 #define SNTP_SET_SYSTEM_TIME_US(sec, us) 00085 #define SNTP_CALC_TIME_US 0 00086 #define SNTP_RECEIVE_TIME_SIZE 1 00087 #endif 00088 00089 00090 /* the various debug levels for this file */ 00091 #define SNTP_DEBUG_TRACE (SNTP_DEBUG | LWIP_DBG_TRACE) 00092 #define SNTP_DEBUG_STATE (SNTP_DEBUG | LWIP_DBG_STATE) 00093 #define SNTP_DEBUG_WARN (SNTP_DEBUG | LWIP_DBG_LEVEL_WARNING) 00094 #define SNTP_DEBUG_WARN_STATE (SNTP_DEBUG | LWIP_DBG_LEVEL_WARNING | LWIP_DBG_STATE) 00095 #define SNTP_DEBUG_SERIOUS (SNTP_DEBUG | LWIP_DBG_LEVEL_SERIOUS) 00096 00097 #define SNTP_ERR_KOD 1 00098 00099 /* SNTP protocol defines */ 00100 #define SNTP_MSG_LEN 48 00101 00102 #define SNTP_OFFSET_LI_VN_MODE 0 00103 #define SNTP_LI_MASK 0xC0 00104 #define SNTP_LI_NO_WARNING 0x00 00105 #define SNTP_LI_LAST_MINUTE_61_SEC 0x01 00106 #define SNTP_LI_LAST_MINUTE_59_SEC 0x02 00107 #define SNTP_LI_ALARM_CONDITION 0x03 /* (clock not synchronized) */ 00108 00109 #define SNTP_VERSION_MASK 0x38 00110 #define SNTP_VERSION (4/* NTP Version 4*/<<3) 00111 00112 #define SNTP_MODE_MASK 0x07 00113 #define SNTP_MODE_CLIENT 0x03 00114 #define SNTP_MODE_SERVER 0x04 00115 #define SNTP_MODE_BROADCAST 0x05 00116 00117 #define SNTP_OFFSET_STRATUM 1 00118 #define SNTP_STRATUM_KOD 0x00 00119 00120 #define SNTP_OFFSET_ORIGINATE_TIME 24 00121 #define SNTP_OFFSET_RECEIVE_TIME 32 00122 #define SNTP_OFFSET_TRANSMIT_TIME 40 00123 00124 /* number of seconds between 1900 and 1970 (MSB=1)*/ 00125 #define DIFF_SEC_1900_1970 (2208988800UL) 00126 /* number of seconds between 1970 and Feb 7, 2036 (6:28:16 UTC) (MSB=0) */ 00127 #define DIFF_SEC_1970_2036 (2085978496UL) 00128 00129 /** 00130 * SNTP packet format (without optional fields) 00131 * Timestamps are coded as 64 bits: 00132 * - 32 bits seconds since Jan 01, 1970, 00:00 00133 * - 32 bits seconds fraction (0-padded) 00134 * For future use, if the MSB in the seconds part is set, seconds are based 00135 * on Feb 07, 2036, 06:28:16. 00136 */ 00137 #ifdef PACK_STRUCT_USE_INCLUDES 00138 # include "arch/bpstruct.h" 00139 #endif 00140 PACK_STRUCT_BEGIN 00141 struct sntp_msg { 00142 PACK_STRUCT_FLD_8(u8_t li_vn_mode); 00143 PACK_STRUCT_FLD_8(u8_t stratum); 00144 PACK_STRUCT_FLD_8(u8_t poll); 00145 PACK_STRUCT_FLD_8(u8_t precision); 00146 PACK_STRUCT_FIELD(u32_t root_delay); 00147 PACK_STRUCT_FIELD(u32_t root_dispersion); 00148 PACK_STRUCT_FIELD(u32_t reference_identifier); 00149 PACK_STRUCT_FIELD(u32_t reference_timestamp[2]); 00150 PACK_STRUCT_FIELD(u32_t originate_timestamp[2]); 00151 PACK_STRUCT_FIELD(u32_t receive_timestamp[2]); 00152 PACK_STRUCT_FIELD(u32_t transmit_timestamp[2]); 00153 } PACK_STRUCT_STRUCT; 00154 PACK_STRUCT_END 00155 #ifdef PACK_STRUCT_USE_INCLUDES 00156 # include "arch/epstruct.h" 00157 #endif 00158 00159 /* function prototypes */ 00160 static void sntp_request(void *arg); 00161 00162 /** The operating mode */ 00163 static u8_t sntp_opmode; 00164 00165 /** The UDP pcb used by the SNTP client */ 00166 static struct udp_pcb* sntp_pcb; 00167 /** Names/Addresses of servers */ 00168 struct sntp_server { 00169 #if SNTP_SERVER_DNS 00170 char* name; 00171 #endif /* SNTP_SERVER_DNS */ 00172 ip_addr_t addr; 00173 }; 00174 static struct sntp_server sntp_servers[SNTP_MAX_SERVERS]; 00175 00176 #if SNTP_GET_SERVERS_FROM_DHCP 00177 static u8_t sntp_set_servers_from_dhcp; 00178 #endif /* SNTP_GET_SERVERS_FROM_DHCP */ 00179 #if SNTP_SUPPORT_MULTIPLE_SERVERS 00180 /** The currently used server (initialized to 0) */ 00181 static u8_t sntp_current_server; 00182 #else /* SNTP_SUPPORT_MULTIPLE_SERVERS */ 00183 #define sntp_current_server 0 00184 #endif /* SNTP_SUPPORT_MULTIPLE_SERVERS */ 00185 00186 #if SNTP_RETRY_TIMEOUT_EXP 00187 #define SNTP_RESET_RETRY_TIMEOUT() sntp_retry_timeout = SNTP_RETRY_TIMEOUT 00188 /** Retry time, initialized with SNTP_RETRY_TIMEOUT and doubled with each retry. */ 00189 static u32_t sntp_retry_timeout; 00190 #else /* SNTP_RETRY_TIMEOUT_EXP */ 00191 #define SNTP_RESET_RETRY_TIMEOUT() 00192 #define sntp_retry_timeout SNTP_RETRY_TIMEOUT 00193 #endif /* SNTP_RETRY_TIMEOUT_EXP */ 00194 00195 #if SNTP_CHECK_RESPONSE >= 1 00196 /** Saves the last server address to compare with response */ 00197 static ip_addr_t sntp_last_server_address; 00198 #endif /* SNTP_CHECK_RESPONSE >= 1 */ 00199 00200 #if SNTP_CHECK_RESPONSE >= 2 00201 /** Saves the last timestamp sent (which is sent back by the server) 00202 * to compare against in response */ 00203 static u32_t sntp_last_timestamp_sent[2]; 00204 #endif /* SNTP_CHECK_RESPONSE >= 2 */ 00205 00206 /** 00207 * SNTP processing of received timestamp 00208 */ 00209 static void 00210 sntp_process(u32_t *receive_timestamp) 00211 { 00212 /* convert SNTP time (1900-based) to unix GMT time (1970-based) 00213 * if MSB is 0, SNTP time is 2036-based! 00214 */ 00215 u32_t rx_secs = lwip_ntohl(receive_timestamp[0]); 00216 int is_1900_based = ((rx_secs & 0x80000000) != 0); 00217 u32_t t = is_1900_based ? (rx_secs - DIFF_SEC_1900_1970) : (rx_secs + DIFF_SEC_1970_2036); 00218 time_t tim = t; 00219 00220 #if SNTP_CALC_TIME_US 00221 u32_t us = lwip_ntohl(receive_timestamp[1]) / 4295; 00222 SNTP_SET_SYSTEM_TIME_US(t, us); 00223 /* display local time from GMT time */ 00224 LWIP_DEBUGF(SNTP_DEBUG_TRACE, ("sntp_process: %s, %"U32_F" us", ctime(&tim), us)); 00225 00226 #else /* SNTP_CALC_TIME_US */ 00227 00228 /* change system time and/or the update the RTC clock */ 00229 SNTP_SET_SYSTEM_TIME(t); 00230 /* display local time from GMT time */ 00231 LWIP_DEBUGF(SNTP_DEBUG_TRACE, ("sntp_process: %s", ctime(&tim))); 00232 #endif /* SNTP_CALC_TIME_US */ 00233 LWIP_UNUSED_ARG(tim); 00234 } 00235 00236 /** 00237 * Initialize request struct to be sent to server. 00238 */ 00239 static void 00240 sntp_initialize_request(struct sntp_msg *req) 00241 { 00242 memset(req, 0, SNTP_MSG_LEN); 00243 req->li_vn_mode = SNTP_LI_NO_WARNING | SNTP_VERSION | SNTP_MODE_CLIENT; 00244 00245 #if SNTP_CHECK_RESPONSE >= 2 00246 { 00247 u32_t sntp_time_sec, sntp_time_us; 00248 /* fill in transmit timestamp and save it in 'sntp_last_timestamp_sent' */ 00249 SNTP_GET_SYSTEM_TIME(sntp_time_sec, sntp_time_us); 00250 sntp_last_timestamp_sent[0] = lwip_htonl(sntp_time_sec + DIFF_SEC_1900_1970); 00251 req->transmit_timestamp[0] = sntp_last_timestamp_sent[0]; 00252 /* we send/save us instead of fraction to be faster... */ 00253 sntp_last_timestamp_sent[1] = lwip_htonl(sntp_time_us); 00254 req->transmit_timestamp[1] = sntp_last_timestamp_sent[1]; 00255 } 00256 #endif /* SNTP_CHECK_RESPONSE >= 2 */ 00257 } 00258 00259 /** 00260 * Retry: send a new request (and increase retry timeout). 00261 * 00262 * @param arg is unused (only necessary to conform to sys_timeout) 00263 */ 00264 static void 00265 sntp_retry(void* arg) 00266 { 00267 LWIP_UNUSED_ARG(arg); 00268 00269 LWIP_DEBUGF(SNTP_DEBUG_STATE, ("sntp_retry: Next request will be sent in %"U32_F" ms\n", 00270 sntp_retry_timeout)); 00271 00272 /* set up a timer to send a retry and increase the retry delay */ 00273 sys_timeout(sntp_retry_timeout, sntp_request, NULL); 00274 00275 #if SNTP_RETRY_TIMEOUT_EXP 00276 { 00277 u32_t new_retry_timeout; 00278 /* increase the timeout for next retry */ 00279 new_retry_timeout = sntp_retry_timeout << 1; 00280 /* limit to maximum timeout and prevent overflow */ 00281 if ((new_retry_timeout <= SNTP_RETRY_TIMEOUT_MAX) && 00282 (new_retry_timeout > sntp_retry_timeout)) { 00283 sntp_retry_timeout = new_retry_timeout; 00284 } 00285 } 00286 #endif /* SNTP_RETRY_TIMEOUT_EXP */ 00287 } 00288 00289 #if SNTP_SUPPORT_MULTIPLE_SERVERS 00290 /** 00291 * If Kiss-of-Death is received (or another packet parsing error), 00292 * try the next server or retry the current server and increase the retry 00293 * timeout if only one server is available. 00294 * (implicitly, SNTP_MAX_SERVERS > 1) 00295 * 00296 * @param arg is unused (only necessary to conform to sys_timeout) 00297 */ 00298 static void 00299 sntp_try_next_server(void* arg) 00300 { 00301 u8_t old_server, i; 00302 LWIP_UNUSED_ARG(arg); 00303 00304 old_server = sntp_current_server; 00305 for (i = 0; i < SNTP_MAX_SERVERS - 1; i++) { 00306 sntp_current_server++; 00307 if (sntp_current_server >= SNTP_MAX_SERVERS) { 00308 sntp_current_server = 0; 00309 } 00310 if (!ip_addr_isany(&sntp_servers[sntp_current_server].addr) 00311 #if SNTP_SERVER_DNS 00312 || (sntp_servers[sntp_current_server].name != NULL) 00313 #endif 00314 ) { 00315 LWIP_DEBUGF(SNTP_DEBUG_STATE, ("sntp_try_next_server: Sending request to server %"U16_F"\n", 00316 (u16_t)sntp_current_server)); 00317 /* new server: reset retry timeout */ 00318 SNTP_RESET_RETRY_TIMEOUT(); 00319 /* instantly send a request to the next server */ 00320 sntp_request(NULL); 00321 return; 00322 } 00323 } 00324 /* no other valid server found */ 00325 sntp_current_server = old_server; 00326 sntp_retry(NULL); 00327 } 00328 #else /* SNTP_SUPPORT_MULTIPLE_SERVERS */ 00329 /* Always retry on error if only one server is supported */ 00330 #define sntp_try_next_server sntp_retry 00331 #endif /* SNTP_SUPPORT_MULTIPLE_SERVERS */ 00332 00333 /** UDP recv callback for the sntp pcb */ 00334 static void 00335 sntp_recv(void *arg, struct udp_pcb* pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port) 00336 { 00337 u8_t mode; 00338 u8_t stratum; 00339 u32_t receive_timestamp[SNTP_RECEIVE_TIME_SIZE]; 00340 err_t err; 00341 00342 LWIP_UNUSED_ARG(arg); 00343 LWIP_UNUSED_ARG(pcb); 00344 00345 /* packet received: stop retry timeout */ 00346 sys_untimeout(sntp_try_next_server, NULL); 00347 sys_untimeout(sntp_request, NULL); 00348 00349 err = ERR_ARG; 00350 #if SNTP_CHECK_RESPONSE >= 1 00351 /* check server address and port */ 00352 if (((sntp_opmode != SNTP_OPMODE_POLL) || ip_addr_cmp(addr, &sntp_last_server_address)) && 00353 (port == SNTP_PORT)) 00354 #else /* SNTP_CHECK_RESPONSE >= 1 */ 00355 LWIP_UNUSED_ARG(addr); 00356 LWIP_UNUSED_ARG(port); 00357 #endif /* SNTP_CHECK_RESPONSE >= 1 */ 00358 { 00359 /* process the response */ 00360 if (p->tot_len == SNTP_MSG_LEN) { 00361 pbuf_copy_partial(p, &mode, 1, SNTP_OFFSET_LI_VN_MODE); 00362 mode &= SNTP_MODE_MASK; 00363 /* if this is a SNTP response... */ 00364 if (((sntp_opmode == SNTP_OPMODE_POLL) && (mode == SNTP_MODE_SERVER)) || 00365 ((sntp_opmode == SNTP_OPMODE_LISTENONLY) && (mode == SNTP_MODE_BROADCAST))) { 00366 pbuf_copy_partial(p, &stratum, 1, SNTP_OFFSET_STRATUM); 00367 if (stratum == SNTP_STRATUM_KOD) { 00368 /* Kiss-of-death packet. Use another server or increase UPDATE_DELAY. */ 00369 err = SNTP_ERR_KOD; 00370 LWIP_DEBUGF(SNTP_DEBUG_STATE, ("sntp_recv: Received Kiss-of-Death\n")); 00371 } else { 00372 #if SNTP_CHECK_RESPONSE >= 2 00373 /* check originate_timetamp against sntp_last_timestamp_sent */ 00374 u32_t originate_timestamp[2]; 00375 pbuf_copy_partial(p, &originate_timestamp, 8, SNTP_OFFSET_ORIGINATE_TIME); 00376 if ((originate_timestamp[0] != sntp_last_timestamp_sent[0]) || 00377 (originate_timestamp[1] != sntp_last_timestamp_sent[1])) 00378 { 00379 LWIP_DEBUGF(SNTP_DEBUG_WARN, ("sntp_recv: Invalid originate timestamp in response\n")); 00380 } else 00381 #endif /* SNTP_CHECK_RESPONSE >= 2 */ 00382 /* @todo: add code for SNTP_CHECK_RESPONSE >= 3 and >= 4 here */ 00383 { 00384 /* correct answer */ 00385 err = ERR_OK; 00386 pbuf_copy_partial(p, &receive_timestamp, SNTP_RECEIVE_TIME_SIZE * 4, SNTP_OFFSET_TRANSMIT_TIME); 00387 } 00388 } 00389 } else { 00390 LWIP_DEBUGF(SNTP_DEBUG_WARN, ("sntp_recv: Invalid mode in response: %"U16_F"\n", (u16_t)mode)); 00391 /* wait for correct response */ 00392 err = ERR_TIMEOUT; 00393 } 00394 } else { 00395 LWIP_DEBUGF(SNTP_DEBUG_WARN, ("sntp_recv: Invalid packet length: %"U16_F"\n", p->tot_len)); 00396 } 00397 } 00398 #if SNTP_CHECK_RESPONSE >= 1 00399 else { 00400 /* packet from wrong remote address or port, wait for correct response */ 00401 err = ERR_TIMEOUT; 00402 } 00403 #endif /* SNTP_CHECK_RESPONSE >= 1 */ 00404 pbuf_free(p); 00405 if (err == ERR_OK) { 00406 sntp_process(receive_timestamp); 00407 00408 /* Set up timeout for next request (only if poll response was received)*/ 00409 if (sntp_opmode == SNTP_OPMODE_POLL) { 00410 /* Correct response, reset retry timeout */ 00411 SNTP_RESET_RETRY_TIMEOUT(); 00412 00413 sys_timeout((u32_t)SNTP_UPDATE_DELAY, sntp_request, NULL); 00414 LWIP_DEBUGF(SNTP_DEBUG_STATE, ("sntp_recv: Scheduled next time request: %"U32_F" ms\n", 00415 (u32_t)SNTP_UPDATE_DELAY)); 00416 } 00417 } else if (err != ERR_TIMEOUT) { 00418 /* Errors are only processed in case of an explicit poll response */ 00419 if (sntp_opmode == SNTP_OPMODE_POLL) { 00420 if (err == SNTP_ERR_KOD) { 00421 /* Kiss-of-death packet. Use another server or increase UPDATE_DELAY. */ 00422 sntp_try_next_server(NULL); 00423 } else { 00424 /* another error, try the same server again */ 00425 sntp_retry(NULL); 00426 } 00427 } 00428 } 00429 } 00430 00431 /** Actually send an sntp request to a server. 00432 * 00433 * @param server_addr resolved IP address of the SNTP server 00434 */ 00435 static void 00436 sntp_send_request(const ip_addr_t *server_addr) 00437 { 00438 struct pbuf* p; 00439 p = pbuf_alloc(PBUF_TRANSPORT, SNTP_MSG_LEN, PBUF_RAM); 00440 if (p != NULL) { 00441 struct sntp_msg *sntpmsg = (struct sntp_msg *)p->payload; 00442 LWIP_DEBUGF(SNTP_DEBUG_STATE, ("sntp_send_request: Sending request to server\n")); 00443 /* initialize request message */ 00444 sntp_initialize_request(sntpmsg); 00445 /* send request */ 00446 udp_sendto(sntp_pcb, p, server_addr, SNTP_PORT); 00447 /* free the pbuf after sending it */ 00448 pbuf_free(p); 00449 /* set up receive timeout: try next server or retry on timeout */ 00450 sys_timeout((u32_t)SNTP_RECV_TIMEOUT, sntp_try_next_server, NULL); 00451 #if SNTP_CHECK_RESPONSE >= 1 00452 /* save server address to verify it in sntp_recv */ 00453 ip_addr_set(&sntp_last_server_address, server_addr); 00454 #endif /* SNTP_CHECK_RESPONSE >= 1 */ 00455 } else { 00456 LWIP_DEBUGF(SNTP_DEBUG_SERIOUS, ("sntp_send_request: Out of memory, trying again in %"U32_F" ms\n", 00457 (u32_t)SNTP_RETRY_TIMEOUT)); 00458 /* out of memory: set up a timer to send a retry */ 00459 sys_timeout((u32_t)SNTP_RETRY_TIMEOUT, sntp_request, NULL); 00460 } 00461 } 00462 00463 #if SNTP_SERVER_DNS 00464 /** 00465 * DNS found callback when using DNS names as server address. 00466 */ 00467 static void 00468 sntp_dns_found(const char* hostname, const ip_addr_t *ipaddr, void *arg) 00469 { 00470 LWIP_UNUSED_ARG(hostname); 00471 LWIP_UNUSED_ARG(arg); 00472 00473 if (ipaddr != NULL) { 00474 /* Address resolved, send request */ 00475 LWIP_DEBUGF(SNTP_DEBUG_STATE, ("sntp_dns_found: Server address resolved, sending request\n")); 00476 sntp_send_request(ipaddr); 00477 } else { 00478 /* DNS resolving failed -> try another server */ 00479 LWIP_DEBUGF(SNTP_DEBUG_WARN_STATE, ("sntp_dns_found: Failed to resolve server address resolved, trying next server\n")); 00480 sntp_try_next_server(NULL); 00481 } 00482 } 00483 #endif /* SNTP_SERVER_DNS */ 00484 00485 /** 00486 * Send out an sntp request. 00487 * 00488 * @param arg is unused (only necessary to conform to sys_timeout) 00489 */ 00490 static void 00491 sntp_request(void *arg) 00492 { 00493 ip_addr_t sntp_server_address; 00494 err_t err; 00495 00496 LWIP_UNUSED_ARG(arg); 00497 00498 /* initialize SNTP server address */ 00499 #if SNTP_SERVER_DNS 00500 if (sntp_servers[sntp_current_server].name) { 00501 /* always resolve the name and rely on dns-internal caching & timeout */ 00502 ip_addr_set_zero(&sntp_servers[sntp_current_server].addr); 00503 err = dns_gethostbyname(sntp_servers[sntp_current_server].name, &sntp_server_address, 00504 sntp_dns_found, NULL); 00505 if (err == ERR_INPROGRESS) { 00506 /* DNS request sent, wait for sntp_dns_found being called */ 00507 LWIP_DEBUGF(SNTP_DEBUG_STATE, ("sntp_request: Waiting for server address to be resolved.\n")); 00508 return; 00509 } else if (err == ERR_OK) { 00510 sntp_servers[sntp_current_server].addr = sntp_server_address; 00511 } 00512 } else 00513 #endif /* SNTP_SERVER_DNS */ 00514 { 00515 sntp_server_address = sntp_servers[sntp_current_server].addr; 00516 err = (ip_addr_isany_val(sntp_server_address)) ? ERR_ARG : ERR_OK; 00517 } 00518 00519 if (err == ERR_OK) { 00520 LWIP_DEBUGF(SNTP_DEBUG_TRACE, ("sntp_request: current server address is %s\n", 00521 ipaddr_ntoa(&sntp_server_address))); 00522 sntp_send_request(&sntp_server_address); 00523 } else { 00524 /* address conversion failed, try another server */ 00525 LWIP_DEBUGF(SNTP_DEBUG_WARN_STATE, ("sntp_request: Invalid server address, trying next server.\n")); 00526 sys_timeout((u32_t)SNTP_RETRY_TIMEOUT, sntp_try_next_server, NULL); 00527 } 00528 } 00529 00530 /** 00531 * @ingroup sntp 00532 * Initialize this module. 00533 * Send out request instantly or after SNTP_STARTUP_DELAY(_FUNC). 00534 */ 00535 void 00536 sntp_init(void) 00537 { 00538 #ifdef SNTP_SERVER_ADDRESS 00539 #if SNTP_SERVER_DNS 00540 sntp_setservername(0, SNTP_SERVER_ADDRESS); 00541 #else 00542 #error SNTP_SERVER_ADDRESS string not supported SNTP_SERVER_DNS==0 00543 #endif 00544 #endif /* SNTP_SERVER_ADDRESS */ 00545 00546 if (sntp_pcb == NULL) { 00547 sntp_pcb = udp_new_ip_type(IPADDR_TYPE_ANY); 00548 LWIP_ASSERT("Failed to allocate udp pcb for sntp client", sntp_pcb != NULL); 00549 if (sntp_pcb != NULL) { 00550 udp_recv(sntp_pcb, sntp_recv, NULL); 00551 00552 if (sntp_opmode == SNTP_OPMODE_POLL) { 00553 SNTP_RESET_RETRY_TIMEOUT(); 00554 #if SNTP_STARTUP_DELAY 00555 sys_timeout((u32_t)SNTP_STARTUP_DELAY_FUNC, sntp_request, NULL); 00556 #else 00557 sntp_request(NULL); 00558 #endif 00559 } else if (sntp_opmode == SNTP_OPMODE_LISTENONLY) { 00560 ip_set_option(sntp_pcb, SOF_BROADCAST); 00561 udp_bind(sntp_pcb, IP_ANY_TYPE, SNTP_PORT); 00562 } 00563 } 00564 } 00565 } 00566 00567 /** 00568 * @ingroup sntp 00569 * Stop this module. 00570 */ 00571 void 00572 sntp_stop(void) 00573 { 00574 if (sntp_pcb != NULL) { 00575 sys_untimeout(sntp_request, NULL); 00576 sys_untimeout(sntp_try_next_server, NULL); 00577 udp_remove(sntp_pcb); 00578 sntp_pcb = NULL; 00579 } 00580 } 00581 00582 /** 00583 * @ingroup sntp 00584 * Get enabled state. 00585 */ 00586 u8_t sntp_enabled(void) 00587 { 00588 return (sntp_pcb != NULL)? 1 : 0; 00589 } 00590 00591 /** 00592 * @ingroup sntp 00593 * Sets the operating mode. 00594 * @param operating_mode one of the available operating modes 00595 */ 00596 void 00597 sntp_setoperatingmode(u8_t operating_mode) 00598 { 00599 LWIP_ASSERT("Invalid operating mode", operating_mode <= SNTP_OPMODE_LISTENONLY); 00600 LWIP_ASSERT("Operating mode must not be set while SNTP client is running", sntp_pcb == NULL); 00601 sntp_opmode = operating_mode; 00602 } 00603 00604 /** 00605 * @ingroup sntp 00606 * Gets the operating mode. 00607 */ 00608 u8_t 00609 sntp_getoperatingmode(void) 00610 { 00611 return sntp_opmode; 00612 } 00613 00614 #if SNTP_GET_SERVERS_FROM_DHCP 00615 /** 00616 * Config SNTP server handling by IP address, name, or DHCP; clear table 00617 * @param set_servers_from_dhcp enable or disable getting server addresses from dhcp 00618 */ 00619 void 00620 sntp_servermode_dhcp(int set_servers_from_dhcp) 00621 { 00622 u8_t new_mode = set_servers_from_dhcp ? 1 : 0; 00623 if (sntp_set_servers_from_dhcp != new_mode) { 00624 sntp_set_servers_from_dhcp = new_mode; 00625 } 00626 } 00627 #endif /* SNTP_GET_SERVERS_FROM_DHCP */ 00628 00629 /** 00630 * @ingroup sntp 00631 * Initialize one of the NTP servers by IP address 00632 * 00633 * @param idx the index of the NTP server to set must be < SNTP_MAX_SERVERS 00634 * @param server IP address of the NTP server to set 00635 */ 00636 void 00637 sntp_setserver(u8_t idx, const ip_addr_t *server) 00638 { 00639 if (idx < SNTP_MAX_SERVERS) { 00640 if (server != NULL) { 00641 sntp_servers[idx].addr = (*server); 00642 } else { 00643 ip_addr_set_zero(&sntp_servers[idx].addr); 00644 } 00645 #if SNTP_SERVER_DNS 00646 sntp_servers[idx].name = NULL; 00647 #endif 00648 } 00649 } 00650 00651 #if LWIP_DHCP && SNTP_GET_SERVERS_FROM_DHCP 00652 /** 00653 * Initialize one of the NTP servers by IP address, required by DHCP 00654 * 00655 * @param numdns the index of the NTP server to set must be < SNTP_MAX_SERVERS 00656 * @param dnsserver IP address of the NTP server to set 00657 */ 00658 void 00659 dhcp_set_ntp_servers(u8_t num, const ip4_addr_t *server) 00660 { 00661 LWIP_DEBUGF(SNTP_DEBUG_TRACE, ("sntp: %s %u.%u.%u.%u as NTP server #%u via DHCP\n", 00662 (sntp_set_servers_from_dhcp ? "Got" : "Rejected"), 00663 ip4_addr1(server), ip4_addr2(server), ip4_addr3(server), ip4_addr4(server), num)); 00664 if (sntp_set_servers_from_dhcp && num) { 00665 u8_t i; 00666 for (i = 0; (i < num) && (i < SNTP_MAX_SERVERS); i++) { 00667 ip_addr_t addr; 00668 ip_addr_copy_from_ip4(addr, server[i]); 00669 sntp_setserver(i, &addr); 00670 } 00671 for (i = num; i < SNTP_MAX_SERVERS; i++) { 00672 sntp_setserver(i, NULL); 00673 } 00674 } 00675 } 00676 #endif /* LWIP_DHCP && SNTP_GET_SERVERS_FROM_DHCP */ 00677 00678 /** 00679 * @ingroup sntp 00680 * Obtain one of the currently configured by IP address (or DHCP) NTP servers 00681 * 00682 * @param idx the index of the NTP server 00683 * @return IP address of the indexed NTP server or "ip_addr_any" if the NTP 00684 * server has not been configured by address (or at all). 00685 */ 00686 const ip_addr_t* 00687 sntp_getserver(u8_t idx) 00688 { 00689 if (idx < SNTP_MAX_SERVERS) { 00690 return &sntp_servers[idx].addr; 00691 } 00692 return IP_ADDR_ANY; 00693 } 00694 00695 #if SNTP_SERVER_DNS 00696 /** 00697 * Initialize one of the NTP servers by name 00698 * 00699 * @param numdns the index of the NTP server to set must be < SNTP_MAX_SERVERS 00700 * @param dnsserver DNS name of the NTP server to set, to be resolved at contact time 00701 */ 00702 void 00703 sntp_setservername(u8_t idx, char *server) 00704 { 00705 if (idx < SNTP_MAX_SERVERS) { 00706 sntp_servers[idx].name = server; 00707 } 00708 } 00709 00710 /** 00711 * Obtain one of the currently configured by name NTP servers. 00712 * 00713 * @param numdns the index of the NTP server 00714 * @return IP address of the indexed NTP server or NULL if the NTP 00715 * server has not been configured by name (or at all) 00716 */ 00717 char * 00718 sntp_getservername(u8_t idx) 00719 { 00720 if (idx < SNTP_MAX_SERVERS) { 00721 return sntp_servers[idx].name; 00722 } 00723 return NULL; 00724 } 00725 #endif /* SNTP_SERVER_DNS */ 00726 00727 #endif /* LWIP_UDP */
Generated on Sun Jul 17 2022 08:25:25 by 1.7.2