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

Dependencies:   mbed

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers sntp.c Source File

sntp.c

Go to the documentation of this file.
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 */