diff --git a/mongoose.c b/mongoose.c index 5b24e4f9..c0bb23e6 100644 --- a/mongoose.c +++ b/mongoose.c @@ -12901,10 +12901,10 @@ void mg_sha384(uint8_t dst[48], uint8_t *data, size_t datasz) { #define SNTP_TIME_OFFSET 2208988800U // (1970 - 1900) in seconds #define SNTP_MAX_FRAC 4294967295.0 // 2 ** 32 - 1 -static uint64_t s_boot_timestamp = 0; // Updated by SNTP +uint64_t mg_boot_timestamp_ms = 0; // Updated by SNTP uint64_t mg_now(void) { - return mg_millis() + s_boot_timestamp; + return mg_millis() + mg_boot_timestamp_ms; } static int64_t gettimestamp(const uint32_t *data) { @@ -12931,7 +12931,7 @@ int64_t mg_sntp_parse(const unsigned char *buf, size_t len) { int64_t now = (int64_t) mg_millis(); int64_t latency = (now - origin_time) - (transmit_time - receive_time); epoch_milliseconds = transmit_time + latency / 2; - s_boot_timestamp = (uint64_t) (epoch_milliseconds - now); + mg_boot_timestamp_ms = (uint64_t) (epoch_milliseconds - now); } else { MG_ERROR(("unexpected version: %d", version)); } @@ -12947,7 +12947,7 @@ static void sntp_cb(struct mg_connection *c, int ev, void *ev_data) { } else if (ev == MG_EV_READ) { int64_t milliseconds = mg_sntp_parse(c->recv.buf, c->recv.len); if (milliseconds > 0) { - s_boot_timestamp = (uint64_t) milliseconds - mg_millis(); + mg_boot_timestamp_ms = (uint64_t) milliseconds - mg_millis(); mg_call(c, MG_EV_SNTP_TIME, (uint64_t *) &milliseconds); MG_DEBUG(("%lu got time: %lld ms from epoch", c->id, milliseconds)); } @@ -12981,6 +12981,7 @@ struct mg_connection *mg_sntp_connect(struct mg_mgr *mgr, const char *url, return mg_connect_svc(mgr, url, fn, fn_data, sntp_cb, NULL); } + #ifdef MG_ENABLE_LINES #line 1 "src/sock.c" #endif diff --git a/mongoose.h b/mongoose.h index efff41c5..9491e831 100644 --- a/mongoose.h +++ b/mongoose.h @@ -1333,7 +1333,6 @@ void mg_timer_init(struct mg_timer **head, struct mg_timer *timer, void *arg); void mg_timer_free(struct mg_timer **head, struct mg_timer *); void mg_timer_poll(struct mg_timer **head, uint64_t new_ms); -bool mg_timer_expired(uint64_t *expiration, uint64_t period, uint64_t now); @@ -1424,7 +1423,6 @@ void mg_bzero(volatile unsigned char *buf, size_t len); bool mg_random(void *buf, size_t len); char *mg_random_str(char *buf, size_t len); uint32_t mg_crc32(uint32_t crc, const char *buf, size_t len); -uint64_t mg_millis(void); // Return milliseconds since boot bool mg_path_is_sane(const struct mg_str path); void mg_delayms(unsigned int ms); @@ -2904,17 +2902,62 @@ size_t mg_ws_wrap(struct mg_connection *, size_t len, int op); size_t mg_ws_printf(struct mg_connection *c, int op, const char *fmt, ...); size_t mg_ws_vprintf(struct mg_connection *c, int op, const char *fmt, va_list *); +// Time / SNTP functions + +// Return milliseconds since boot (uptime). Never goes backwards. +// On RTOS targets (FreeRTOS, ThreadX, Zephyr, etc.) uses the RTOS tick count. +// On STM32/Cube uses HAL_GetTick(). On Arduino uses millis(). +// On Linux/macOS uses CLOCK_MONOTONIC_RAW or CLOCK_MONOTONIC; falls back to +// CLOCK_REALTIME if neither is available. +uint64_t mg_millis(void); + +// Boot timestamp in ms since Epoch. Updated by successful SNTP request +extern uint64_t mg_boot_timestamp_ms; + +// Return milliseconds since Epoch: mg_millis() + mg_boot_timestamp_ms. +// Until a successful SNTP request completes, this is identical to mg_millis(). +uint64_t mg_now(void); + +// Check whether a periodic timer has expired. +// +// - `expiration` holds the next expiry time in ms +// - `period` is a interval in ms +// - `now` - a current time in ms +// +// Return value: true if expired, in which case a function advances the +// `expiration` by one period. Handles millisecond counter wrap-around. +// See mg_sntp_connect() for usage example. +bool mg_timer_expired(uint64_t *expiration, uint64_t period, uint64_t now); + +// Connect to an SNTP server and send a time request. +// `url` defaults to "udp://time.google.com:123" when NULL. +// On success the internal boot timestamp is updated so that mg_now() returns +// the correct wall-clock time, and MG_EV_SNTP_TIME is fired on `fn` (if not +// NULL) with a pointer to the int64_t epoch in milliseconds. +// Pass fn == NULL and fn_data == NULL for a fire-and-forget sync that only +// updates mg_boot_timestamp_ms. Typical polling usage: +// +// ```c +// uint64_t timer = 0; +// for (;;) { +// uint64_t period = mg_boot_timestamp_ms == 0 ? 1000 : 3600 * 1000; +// if (mg_timer_expired(&timer, period, mg_millis())) { +// mg_sntp_connect(&mgr, NULL, NULL, NULL); +// } +// mg_mgr_poll(&mgr, 1000); +// } +// ``` struct mg_connection *mg_sntp_connect(struct mg_mgr *mgr, const char *url, mg_event_handler_t fn, void *fn_data); + +// Private API, do not expose void mg_sntp_request(struct mg_connection *c); int64_t mg_sntp_parse(const unsigned char *buf, size_t len); -uint64_t mg_now(void); // Return milliseconds since Epoch - diff --git a/src/sntp.c b/src/sntp.c index 2e22bbc9..6646acb9 100644 --- a/src/sntp.c +++ b/src/sntp.c @@ -7,10 +7,10 @@ #define SNTP_TIME_OFFSET 2208988800U // (1970 - 1900) in seconds #define SNTP_MAX_FRAC 4294967295.0 // 2 ** 32 - 1 -static uint64_t s_boot_timestamp = 0; // Updated by SNTP +uint64_t mg_boot_timestamp_ms = 0; // Updated by SNTP uint64_t mg_now(void) { - return mg_millis() + s_boot_timestamp; + return mg_millis() + mg_boot_timestamp_ms; } static int64_t gettimestamp(const uint32_t *data) { @@ -37,7 +37,7 @@ int64_t mg_sntp_parse(const unsigned char *buf, size_t len) { int64_t now = (int64_t) mg_millis(); int64_t latency = (now - origin_time) - (transmit_time - receive_time); epoch_milliseconds = transmit_time + latency / 2; - s_boot_timestamp = (uint64_t) (epoch_milliseconds - now); + mg_boot_timestamp_ms = (uint64_t) (epoch_milliseconds - now); } else { MG_ERROR(("unexpected version: %d", version)); } @@ -53,7 +53,7 @@ static void sntp_cb(struct mg_connection *c, int ev, void *ev_data) { } else if (ev == MG_EV_READ) { int64_t milliseconds = mg_sntp_parse(c->recv.buf, c->recv.len); if (milliseconds > 0) { - s_boot_timestamp = (uint64_t) milliseconds - mg_millis(); + mg_boot_timestamp_ms = (uint64_t) milliseconds - mg_millis(); mg_call(c, MG_EV_SNTP_TIME, (uint64_t *) &milliseconds); MG_DEBUG(("%lu got time: %lld ms from epoch", c->id, milliseconds)); } @@ -86,3 +86,4 @@ struct mg_connection *mg_sntp_connect(struct mg_mgr *mgr, const char *url, if (url == NULL) url = "udp://time.google.com:123"; return mg_connect_svc(mgr, url, fn, fn_data, sntp_cb, NULL); } + diff --git a/src/sntp.h b/src/sntp.h index 99cbbe03..8aa0d351 100644 --- a/src/sntp.h +++ b/src/sntp.h @@ -1,10 +1,58 @@ +// Time / SNTP functions + #pragma once #include "net.h" +// Return milliseconds since boot (uptime). Never goes backwards. +// On RTOS targets (FreeRTOS, ThreadX, Zephyr, etc.) uses the RTOS tick count. +// On STM32/Cube uses HAL_GetTick(). On Arduino uses millis(). +// On Linux/macOS uses CLOCK_MONOTONIC_RAW or CLOCK_MONOTONIC; falls back to +// CLOCK_REALTIME if neither is available. +uint64_t mg_millis(void); + +// Boot timestamp in ms since Epoch. Updated by successful SNTP request +extern uint64_t mg_boot_timestamp_ms; + +// Return milliseconds since Epoch: mg_millis() + mg_boot_timestamp_ms. +// Until a successful SNTP request completes, this is identical to mg_millis(). +uint64_t mg_now(void); + +// Return true if the periodic timer has fired; advance `expiration` by one +// `period`. Handles wrap-around. Usage example: +// +// ```c +// uint64_t timer = 0; +// for (;;) { +// if (mg_timer_expired(&timer, 1000, mg_millis())) { +// MG_INFO(("Hi")); // Print a message every second +// } +// mg_mgr_poll(&mgr, 10); +// } +// ``` +bool mg_timer_expired(uint64_t *expiration, uint64_t period, uint64_t now); + +// Connect to an SNTP server and send a time request. +// `url` defaults to "udp://time.google.com:123" when NULL. +// On success the internal boot timestamp is updated so that mg_now() returns +// the correct wall-clock time, and MG_EV_SNTP_TIME is fired on `fn` (if not +// NULL) with a pointer to the int64_t epoch in milliseconds. +// Pass fn == NULL and fn_data == NULL for a fire-and-forget sync that only +// updates mg_boot_timestamp_ms. Typical polling usage: +// +// ```c +// uint64_t timer = 0; +// for (;;) { +// uint64_t period = mg_boot_timestamp_ms == 0 ? 1000 : 3600 * 1000; +// if (mg_timer_expired(&timer, period, mg_millis())) { +// mg_sntp_connect(&mgr, NULL, NULL, NULL); +// } +// mg_mgr_poll(&mgr, 1000); +// } +// ``` struct mg_connection *mg_sntp_connect(struct mg_mgr *mgr, const char *url, mg_event_handler_t fn, void *fn_data); + +// Private API, do not expose void mg_sntp_request(struct mg_connection *c); int64_t mg_sntp_parse(const unsigned char *buf, size_t len); - -uint64_t mg_now(void); // Return milliseconds since Epoch diff --git a/src/timer.h b/src/timer.h index e022f156..6df74de2 100644 --- a/src/timer.h +++ b/src/timer.h @@ -21,4 +21,3 @@ void mg_timer_init(struct mg_timer **head, struct mg_timer *timer, void *arg); void mg_timer_free(struct mg_timer **head, struct mg_timer *); void mg_timer_poll(struct mg_timer **head, uint64_t new_ms); -bool mg_timer_expired(uint64_t *expiration, uint64_t period, uint64_t now); diff --git a/src/util.h b/src/util.h index cb14c1ce..2e6c121d 100644 --- a/src/util.h +++ b/src/util.h @@ -17,7 +17,6 @@ void mg_bzero(volatile unsigned char *buf, size_t len); bool mg_random(void *buf, size_t len); char *mg_random_str(char *buf, size_t len); uint32_t mg_crc32(uint32_t crc, const char *buf, size_t len); -uint64_t mg_millis(void); // Return milliseconds since boot bool mg_path_is_sane(const struct mg_str path); void mg_delayms(unsigned int ms); diff --git a/tutorials/udp/sntp-time-sync/main.c b/tutorials/udp/sntp-time-sync/main.c index 5f38f116..e7999aee 100644 --- a/tutorials/udp/sntp-time-sync/main.c +++ b/tutorials/udp/sntp-time-sync/main.c @@ -1,62 +1,32 @@ // Copyright (c) 2022 Cesanta Software Limited // All rights reserved // -// Synchronize time with remote SNTP server -// A working time() call is required by TLS, so an embedded device without -// a clock that wants to use TLS, must sync time via SNTP. +// Synchronize time with a remote SNTP server. +// After a successful sync, mg_now() returns wall-clock time in milliseconds +// since Unix epoch and mg_boot_timestamp_ms is set to a non-zero value. +// Useful on embedded devices that lack a real-time clock but need accurate +// time for TLS certificate validation or timestamping. #include "mongoose.h" -// The UNIX epoch of the boot time. Initially, we set it to 0. But then after -// SNTP response, we update it to the correct value, which will allow us to -// use time(). Uptime in milliseconds is returned by mg_millis(). -static time_t s_boot_timestamp = 0; - -// SNTP client connection -static struct mg_connection *s_sntp_conn = NULL; - -// On embedded systems, rename to time() -time_t my_time(time_t *tp) { - // you can just return mg_now() / 1000; - time_t t = s_boot_timestamp + mg_millis() / 1000; - if (tp != NULL) *tp = t; - return t; -} - -// SNTP client callback -static void sfn(struct mg_connection *c, int ev, void *ev_data) { - if (ev == MG_EV_SNTP_TIME) { - // Time received, the internal protocol handler updates what mg_now() returns - uint64_t curtime = mg_now(); - MG_INFO(("SNTP-updated current time is: %llu ms from epoch", curtime)); - // otherwise, you can process the server returned data yourself - { - uint64_t t = *(uint64_t *) ev_data; - s_boot_timestamp = (time_t) ((t - mg_millis()) / 1000); - MG_INFO(("Got SNTP time: %llu ms from epoch, ", t)); - } - } else if (ev == MG_EV_CLOSE) { - s_sntp_conn = NULL; - } - (void) c; -} - -// Called every 5 seconds. Increase that for production case. -static void timer_fn(void *arg) { - struct mg_mgr *mgr = (struct mg_mgr *) arg; - if (s_sntp_conn == NULL) { // connection issues a request - s_sntp_conn = mg_sntp_connect(mgr, NULL, sfn, NULL); - } else { - mg_sntp_request(s_sntp_conn); - } -} - int main(void) { - struct mg_mgr mgr; // Event manager - mg_mgr_init(&mgr); // Initialise event manager - mg_log_set(MG_LL_DEBUG); // Set log level - mg_timer_add(&mgr, 5000, MG_TIMER_REPEAT | MG_TIMER_RUN_NOW, timer_fn, &mgr); - for (;;) mg_mgr_poll(&mgr, 300); // Infinite event loop - mg_mgr_free(&mgr); // Free manager resources + struct mg_mgr mgr; + mg_mgr_init(&mgr); + mg_log_set(MG_LL_DEBUG); + + uint64_t timer = 0; + for (;;) { + // Retry every second until we have a valid time, then sync once per hour + uint64_t period = mg_boot_timestamp_ms == 0 ? 1000 : 3600 * 1000; + if (mg_timer_expired(&timer, period, mg_millis())) { + mg_sntp_connect(&mgr, NULL, NULL, NULL); + } + if (mg_boot_timestamp_ms > 0) { + MG_INFO(("Current time: %llu ms from epoch", mg_now())); + } + mg_mgr_poll(&mgr, 1000); + } + + mg_mgr_free(&mgr); return 0; } diff --git a/tutorials/zephyr/http-client/src/main.c b/tutorials/zephyr/http-client/src/main.c index d6bbf67c..afa7f942 100644 --- a/tutorials/zephyr/http-client/src/main.c +++ b/tutorials/zephyr/http-client/src/main.c @@ -5,8 +5,6 @@ #include "mongoose.h" #include -static time_t s_boot_timestamp = 0; -static struct mg_connection *s_sntp_conn = NULL; static const char *s_url = "https://example.org/"; static const char *s_post_data = NULL; // POST data static const int64_t s_timeout_ms = 1500; // Connect timeout in milliseconds @@ -56,37 +54,6 @@ static void fn(struct mg_connection *c, int ev, void *ev_data) { } } -// example system time()-like function -time_t ourtime(time_t *tp) { - time_t t = s_boot_timestamp + mg_millis() / 1000; - if (tp != NULL) *tp = t; - return t; -} - -// SNTP callback. Modifies s_boot_timestamp, to make ourtime() correct -static void sfn(struct mg_connection *c, int ev, void *ev_data) { - if (ev == MG_EV_SNTP_TIME) { - int64_t t = *(int64_t *) ev_data; - MG_INFO(("Got SNTP time: %lld ms from epoch", t)); - s_boot_timestamp = (time_t) ((t - mg_millis()) / 1000); - - if (!s_connected) { - MG_INFO(("Connecting to : [%s]", s_url)); - mg_http_connect(&s_mgr, s_url, fn, &done); // Create client connection - s_connected = 1; - } - } else if (ev == MG_EV_CLOSE) { - s_sntp_conn = NULL; - } -} - -// Periodic timer syncs time via SNTP -static void timer_fn(void *arg) { - struct mg_mgr *mgr = (struct mg_mgr *) arg; - if (s_sntp_conn == NULL) s_sntp_conn = mg_sntp_connect(mgr, NULL, sfn, NULL); - if (s_boot_timestamp < 9999) mg_sntp_request(s_sntp_conn); -} - // Zephyr: Define a semaphore and network management callback to be able to wait // until our IP address is ready. The main function will start and block on this // semaphore until this event handler releases it when the network is ready @@ -111,15 +78,24 @@ int main(int argc, char *argv[]) { k_sem_take(&run, K_FOREVER); mg_log_set(MG_LL_DEBUG); - mg_mgr_init(&s_mgr); - mg_timer_add(&s_mgr, 5000, MG_TIMER_REPEAT | MG_TIMER_RUN_NOW, timer_fn, - &s_mgr); - // Start event loop, exit when client is done MG_INFO(("Mongoose version : v%s", MG_VERSION)); - while (!done) mg_mgr_poll(&s_mgr, 1000); + uint64_t sntp_timer = 0; + while (!done) { + uint64_t period = mg_boot_timestamp_ms == 0 ? 1000 : 24 * 3600 * 1000; + if (mg_timer_expired(&sntp_timer, period, mg_millis())) { + mg_sntp_connect(&s_mgr, NULL, NULL, NULL); + } + // Initiate the HTTPS request once we have a valid time (needed for TLS) + if (mg_boot_timestamp_ms > 0 && !s_connected) { + MG_INFO(("Connecting to : [%s]", s_url)); + mg_http_connect(&s_mgr, s_url, fn, &done); + s_connected = 1; + } + mg_mgr_poll(&s_mgr, 1000); + } mg_mgr_free(&s_mgr); return 0; diff --git a/tutorials/zephyr/http-server/src/main.c b/tutorials/zephyr/http-server/src/main.c index 85f147e7..d20ae76f 100644 --- a/tutorials/zephyr/http-server/src/main.c +++ b/tutorials/zephyr/http-server/src/main.c @@ -8,8 +8,6 @@ static const char *s_web_dir = "/"; static const char *s_http_addr = "http://0.0.0.0:8000"; static const char *s_https_addr = "https://0.0.0.0:8443"; -static time_t s_boot_timestamp = 0; -static struct mg_connection *s_sntp_conn = NULL; // Event handler for the listening HTTP/HTTPS connection. static void wcb(struct mg_connection *c, int ev, void *ev_data) { @@ -42,31 +40,6 @@ static void wcb(struct mg_connection *c, int ev, void *ev_data) { } } -// example system time()-like function -time_t ourtime(time_t *tp) { - time_t t = s_boot_timestamp + mg_millis() / 1000; - if (tp != NULL) *tp = t; - return t; -} - -// SNTP callback. Modifies s_boot_timestamp, to make ourtime() correct -static void sfn(struct mg_connection *c, int ev, void *ev_data) { - if (ev == MG_EV_SNTP_TIME) { - int64_t t = *(int64_t *) ev_data; - MG_INFO(("Got SNTP time: %lld ms from epoch", t)); - s_boot_timestamp = (time_t) ((t - mg_millis()) / 1000); - } else if (ev == MG_EV_CLOSE) { - s_sntp_conn = NULL; - } -} - -// Periodic timer syncs time via SNTP -static void timer_fn(void *arg) { - struct mg_mgr *mgr = (struct mg_mgr *) arg; - if (s_sntp_conn == NULL) s_sntp_conn = mg_sntp_connect(mgr, NULL, sfn, NULL); - if (s_boot_timestamp < 9999) mg_sntp_request(s_sntp_conn); -} - // Zephyr: Define a semaphore and network management callback to be able to wait // until our IP address is ready. The main function will start and block on this // semaphore until this event handler releases it when the network is ready @@ -97,14 +70,20 @@ int main(int argc, char *argv[]) { mg_http_listen(&mgr, s_http_addr, wcb, NULL); mg_http_listen(&mgr, s_https_addr, wcb, NULL); - mg_timer_add(&mgr, 5000, MG_TIMER_REPEAT | MG_TIMER_RUN_NOW, timer_fn, &mgr); - // Start infinite event loop MG_INFO(("Mongoose version : v%s", MG_VERSION)); MG_INFO(("Listening on : %s", s_http_addr)); MG_INFO(("Listening on : %s", s_https_addr)); MG_INFO(("Web root : [%s]", s_web_dir)); - for (;;) mg_mgr_poll(&mgr, 1000); + + uint64_t sntp_timer = 0; + for (;;) { + uint64_t period = mg_boot_timestamp_ms == 0 ? 1000 : 24 * 3600 * 1000; + if (mg_timer_expired(&sntp_timer, period, mg_millis())) { + mg_sntp_connect(&mgr, NULL, NULL, NULL); + } + mg_mgr_poll(&mgr, 1000); + } mg_mgr_free(&mgr); return 0; } diff --git a/tutorials/zephyr/mqtt-aws-client/src/main.c b/tutorials/zephyr/mqtt-aws-client/src/main.c index 430bc327..7707cfa4 100644 --- a/tutorials/zephyr/mqtt-aws-client/src/main.c +++ b/tutorials/zephyr/mqtt-aws-client/src/main.c @@ -7,8 +7,6 @@ struct mg_mgr mgr; -static time_t s_boot_timestamp = 0; -static struct mg_connection *s_sntp_conn = NULL; static const char *s_url = "mqtts://a3nkain3cvvy7l-ats.iot.us-east-1.amazonaws.com"; static const char *s_rx_topic = "d/rx"; @@ -59,41 +57,6 @@ static void fn(struct mg_connection *c, int ev, void *ev_data) { } } -// example system time()-like function -time_t ourtime(time_t *tp) { - time_t t = s_boot_timestamp + mg_millis() / 1000; - if (tp != NULL) *tp = t; - return t; -} - -// SNTP callback. Modifies s_boot_timestamp, to make ourtime() correct -static void sfn(struct mg_connection *c, int ev, void *ev_data) { - if (ev == MG_EV_SNTP_TIME) { - int64_t t = *(int64_t *) ev_data; - MG_INFO(("Got SNTP time: %lld ms from epoch", t)); - s_boot_timestamp = (time_t) ((t - mg_millis()) / 1000); - - // We need correct time in order to get HTTPs working, therefore, - // making https request from SMTP callback - if (!s_connected) { - MG_INFO(("Connecting to : [%s]", s_url)); - struct mg_mqtt_opts opts = {.clean = true}; - mg_mqtt_connect(&mgr, s_url, &opts, fn, - NULL); // Create client connection - s_connected = 1; - } - } else if (ev == MG_EV_CLOSE) { - s_sntp_conn = NULL; - } -} - -// Periodic timer syncs time via SNTP -static void timer_fn(void *arg) { - struct mg_mgr *mgr = (struct mg_mgr *) arg; - if (s_sntp_conn == NULL) s_sntp_conn = mg_sntp_connect(mgr, NULL, sfn, NULL); - if (s_boot_timestamp < 9999) mg_sntp_request(s_sntp_conn); -} - // Zephyr: Define a semaphore and network management callback to be able to wait // until our IP address is ready. The main function will start and block on this // semaphore until this event handler releases it when the network is ready @@ -118,15 +81,26 @@ int main(int argc, char *argv[]) { k_sem_take(&run, K_FOREVER); mg_log_set(MG_LL_DEBUG); - mg_mgr_init(&mgr); - mg_timer_add(&mgr, 5000, MG_TIMER_REPEAT | MG_TIMER_RUN_NOW, timer_fn, &mgr); // Start infinite event loop MG_INFO(("Mongoose version : v%s", MG_VERSION)); - mg_http_connect(&mgr, s_url, fn, NULL); // Create client connection - for (;;) mg_mgr_poll(&mgr, 1000); + uint64_t sntp_timer = 0; + for (;;) { + uint64_t period = mg_boot_timestamp_ms == 0 ? 1000 : 24 * 3600 * 1000; + if (mg_timer_expired(&sntp_timer, period, mg_millis())) { + mg_sntp_connect(&mgr, NULL, NULL, NULL); + } + // Connect to AWS IoT once we have a valid time (needed for mutual TLS) + if (mg_boot_timestamp_ms > 0 && !s_connected) { + MG_INFO(("Connecting to : [%s]", s_url)); + struct mg_mqtt_opts opts = {.clean = true}; + mg_mqtt_connect(&mgr, s_url, &opts, fn, NULL); + s_connected = 1; + } + mg_mgr_poll(&mgr, 1000); + } mg_mgr_free(&mgr); return 0; } diff --git a/tutorials/zephyr/websocket-server/src/main.c b/tutorials/zephyr/websocket-server/src/main.c index 974187dc..bd1881fd 100644 --- a/tutorials/zephyr/websocket-server/src/main.c +++ b/tutorials/zephyr/websocket-server/src/main.c @@ -8,8 +8,6 @@ static const char *s_web_dir = "/"; static const char *s_ws_addr = "ws://0.0.0.0:8000"; static const char *s_wss_addr = "wss://0.0.0.0:8443"; -static time_t s_boot_timestamp = 0; -static struct mg_connection *s_sntp_conn = NULL; // This RESTful server implements the following endpoints: // /websocket - upgrade to Websocket, and implement websocket echo server @@ -38,31 +36,6 @@ static void fn(struct mg_connection *c, int ev, void *ev_data) { } } -// example system time()-like function -time_t ourtime(time_t *tp) { - time_t t = s_boot_timestamp + mg_millis() / 1000; - if (tp != NULL) *tp = t; - return t; -} - -// SNTP callback. Modifies s_boot_timestamp, to make ourtime() correct -static void sfn(struct mg_connection *c, int ev, void *ev_data) { - if (ev == MG_EV_SNTP_TIME) { - int64_t t = *(int64_t *) ev_data; - MG_INFO(("Got SNTP time: %lld ms from epoch", t)); - s_boot_timestamp = (time_t) ((t - mg_millis()) / 1000); - } else if (ev == MG_EV_CLOSE) { - s_sntp_conn = NULL; - } -} - -// Periodic timer syncs time via SNTP -static void timer_fn(void *arg) { - struct mg_mgr *mgr = (struct mg_mgr *) arg; - if (s_sntp_conn == NULL) s_sntp_conn = mg_sntp_connect(mgr, NULL, sfn, NULL); - if (s_boot_timestamp < 9999) mg_sntp_request(s_sntp_conn); -} - // Zephyr: Define a semaphore and network management callback to be able to wait // until our IP address is ready. The main function will start and block on this // semaphore until this event handler releases it when the network is ready @@ -92,14 +65,21 @@ int main(int argc, char *argv[]) { mg_log_set(MG_LL_DEBUG); mg_http_listen(&mgr, s_ws_addr, fn, NULL); mg_http_listen(&mgr, s_wss_addr, fn, NULL); - mg_timer_add(&mgr, 5000, MG_TIMER_REPEAT | MG_TIMER_RUN_NOW, timer_fn, &mgr); // Start infinite event loop MG_INFO(("Mongoose version : v%s", MG_VERSION)); MG_INFO(("Listening on : %s", s_ws_addr)); MG_INFO(("Listening on : %s", s_wss_addr)); MG_INFO(("Web root : [%s]", s_web_dir)); - for (;;) mg_mgr_poll(&mgr, 1000); + + uint64_t sntp_timer = 0; + for (;;) { + uint64_t period = mg_boot_timestamp_ms == 0 ? 1000 : 24 * 3600 * 1000; + if (mg_timer_expired(&sntp_timer, period, mg_millis())) { + mg_sntp_connect(&mgr, NULL, NULL, NULL); + } + mg_mgr_poll(&mgr, 1000); + } mg_mgr_free(&mgr); return 0; }