From d5f086f43233c01d8ba7cb967b7167a08940e99a Mon Sep 17 00:00:00 2001 From: David Cermak Date: Tue, 23 Jan 2024 17:10:19 +0100 Subject: [PATCH 1/2] fix(netif): Add missing SNTP get-reachablitiy API --- components/esp_netif/include/esp_netif_sntp.h | 13 ++++++++- components/esp_netif/lwip/esp_netif_sntp.c | 14 +++++++++- .../test_app_esp_netif/main/esp_netif_test.c | 15 ++++++++++- components/lwip/apps/sntp/sntp.c | 16 ++++++++++- components/lwip/include/apps/esp_sntp.h | 27 ++++++++++++++++++- components/lwip/test_apps/main/lwip_test.c | 10 ++++++- 6 files changed, 89 insertions(+), 6 deletions(-) diff --git a/components/esp_netif/include/esp_netif_sntp.h b/components/esp_netif/include/esp_netif_sntp.h index 87f1245d5a..51d7e42bd4 100644 --- a/components/esp_netif/include/esp_netif_sntp.h +++ b/components/esp_netif/include/esp_netif_sntp.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -107,6 +107,17 @@ void esp_netif_sntp_deinit(void); */ esp_err_t esp_netif_sntp_sync_wait(TickType_t tout); +/** + * @brief Returns SNTP server's reachability shift register as described in RFC 5905. + * + * @param index Index of the SERVER + * @param reachability reachability shift register + * @return ESP_OK on success, + * ESP_ERR_INVALID_STATE if SNTP not initialized + * ESP_ERR_INVALID_ARG if invalid arguments + */ +esp_err_t esp_netif_sntp_reachability(unsigned int index, unsigned int *reachability); + /** * @} */ diff --git a/components/esp_netif/lwip/esp_netif_sntp.c b/components/esp_netif/lwip/esp_netif_sntp.c index 1aadcbef69..e6fe54f37f 100644 --- a/components/esp_netif/lwip/esp_netif_sntp.c +++ b/components/esp_netif/lwip/esp_netif_sntp.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -177,3 +177,15 @@ esp_err_t esp_netif_sntp_start(void) { return esp_netif_tcpip_exec(sntp_start_api, NULL); } + +esp_err_t esp_netif_sntp_reachability(unsigned int index, unsigned int *reachability) +{ + if (index >= SNTP_MAX_SERVERS || reachability == NULL) { + return ESP_ERR_INVALID_ARG; + } + if (s_storage == NULL || sntp_enabled() == 0) { + return ESP_ERR_INVALID_STATE; + } + *reachability = sntp_getreachability(index); + return ESP_OK; +} diff --git a/components/esp_netif/test_apps/test_app_esp_netif/main/esp_netif_test.c b/components/esp_netif/test_apps/test_app_esp_netif/main/esp_netif_test.c index 472a8de7ad..79f70ac27a 100644 --- a/components/esp_netif/test_apps/test_app_esp_netif/main/esp_netif_test.c +++ b/components/esp_netif/test_apps/test_app_esp_netif/main/esp_netif_test.c @@ -48,7 +48,20 @@ TEST(esp_netif, init_and_destroy_sntp) { esp_sntp_config_t config = ESP_NETIF_SNTP_DEFAULT_CONFIG("127.0.0.1"); config.start = false; - esp_netif_sntp_init(&config); + TEST_ESP_OK(esp_netif_sntp_init(&config)); + // Cannot initialize multiple times + TEST_ASSERT_NOT_EQUAL(ESP_OK, esp_netif_sntp_init(&config)); + // Try again to see that the state didn't change + TEST_ASSERT_NOT_EQUAL(ESP_OK, esp_netif_sntp_init(&config)); + esp_netif_sntp_deinit(); + + // Can initialize again once it's destroyed + TEST_ESP_OK(esp_netif_sntp_init(&config)); + + // Test the reachability API + size_t reachability = 0; + // Invalid state is expected since SNTP service didn't start + TEST_ASSERT_EQUAL(ESP_ERR_INVALID_STATE, esp_netif_sntp_reachability(0, &reachability)); esp_netif_sntp_deinit(); } diff --git a/components/lwip/apps/sntp/sntp.c b/components/lwip/apps/sntp/sntp.c index 3b8cf283ae..8d8fbfbe90 100644 --- a/components/lwip/apps/sntp/sntp.c +++ b/components/lwip/apps/sntp/sntp.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -243,6 +243,20 @@ const ip_addr_t* esp_sntp_getserver(u8_t idx) return sntp_getserver(idx); } +uint8_t esp_sntp_getreachability(uint8_t idx) +{ +#if SNTP_MONITOR_SERVER_REACHABILITY + return sntp_getreachability(idx); +#endif + LWIP_ERROR("sntp_getreachability() in not enabled in lwipopts", false, ); + return 0; +} + +esp_sntp_operatingmode_t esp_sntp_getoperatingmode(void) +{ + return (esp_sntp_operatingmode_t)sntp_getoperatingmode(); +} + #if LWIP_DHCP_GET_NTP_SRV static void do_servermode_dhcp(void* ctx) { diff --git a/components/lwip/include/apps/esp_sntp.h b/components/lwip/include/apps/esp_sntp.h index 80d2a88129..6aad345d00 100644 --- a/components/lwip/include/apps/esp_sntp.h +++ b/components/lwip/include/apps/esp_sntp.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -218,6 +218,20 @@ const ip_addr_t* esp_sntp_getserver(u8_t idx); */ bool esp_sntp_enabled(void); +/** + * @brief Gets the server reachability shift register as described in RFC 5905. + * @param idx Index of the SNTP server + * @return reachability shift register + */ +uint8_t esp_sntp_getreachability(uint8_t idx); + +/** + * @brief Get the configured operating mode + * + * @return operating mode enum + */ +esp_sntp_operatingmode_t esp_sntp_getoperatingmode(void); + #if LWIP_DHCP_GET_NTP_SRV /** * @brief Enable acquiring SNTP server from DHCP @@ -269,6 +283,17 @@ const ip_addr_t* sntp_getserver(u8_t idx) return esp_sntp_getserver(idx); } +static inline uint8_t sntp_getreachability(uint8_t idx) +{ + return esp_sntp_getreachability(idx); +} + +static inline __attribute__((deprecated("use esp_sntp_getoperatingmode() instead"))) +esp_sntp_operatingmode_t sntp_getoperatingmode(void) +{ + return esp_sntp_getoperatingmode(); +} + #endif /* ESP_LWIP_COMPONENT_BUILD */ diff --git a/components/lwip/test_apps/main/lwip_test.c b/components/lwip/test_apps/main/lwip_test.c index 6a34edeb43..a738c87611 100644 --- a/components/lwip/test_apps/main/lwip_test.c +++ b/components/lwip/test_apps/main/lwip_test.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -294,8 +294,16 @@ void test_sntp_timestamps(int year, bool msb_flag) localtime_r(&now, &timeinfo); TEST_ASSERT_EQUAL(year, 1900 + timeinfo.tm_year); + // Check that the server 0 was reachable + TEST_ASSERT_EQUAL(1, esp_sntp_getreachability(0)); // close the SNTP and the fake server esp_sntp_stop(); + + // Test some other SNTP APIs + TEST_ASSERT_EQUAL(0, esp_sntp_getreachability(0)); + TEST_ASSERT_EQUAL(ESP_SNTP_OPMODE_POLL, esp_sntp_getoperatingmode()); + const ip_addr_t *server_ip = esp_sntp_getserver(0); + TEST_ASSERT_EQUAL(PP_HTONL(IPADDR_LOOPBACK), server_ip->u_addr.ip4.addr); close(sock); } From d750d067e512cdc1b275516ea922bc1016f09741 Mon Sep 17 00:00:00 2001 From: David Cermak Date: Mon, 8 Jan 2024 11:09:35 +0100 Subject: [PATCH 2/2] fix(esp_netif): Prevent running esp_netif_sntp_init() multiple times Closes https://github.com/espressif/esp-idf/issues/12854 --- components/esp_netif/lwip/esp_netif_sntp.c | 1 + .../test_apps/test_app_esp_netif/main/esp_netif_test.c | 2 +- docs/en/api-reference/network/esp_netif.rst | 2 +- docs/zh_CN/api-reference/network/esp_netif.rst | 2 +- 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/components/esp_netif/lwip/esp_netif_sntp.c b/components/esp_netif/lwip/esp_netif_sntp.c index e6fe54f37f..1a7da5e442 100644 --- a/components/esp_netif/lwip/esp_netif_sntp.c +++ b/components/esp_netif/lwip/esp_netif_sntp.c @@ -91,6 +91,7 @@ void esp_netif_sntp_renew_servers(void *handler_args, esp_event_base_t base, int esp_err_t esp_netif_sntp_init(const esp_sntp_config_t * config) { esp_err_t ret = ESP_OK; + ESP_RETURN_ON_FALSE(s_storage == NULL, ESP_ERR_INVALID_STATE, TAG, "esp_netif_sntp already initialized"); s_storage = calloc(1, sizeof(sntp_storage_t) + // allocate space for servers only if we are supposed to refresh the settings (config->renew_servers_after_new_IP ? config->num_of_servers * sizeof(char*) : 0)); ESP_GOTO_ON_FALSE(s_storage != NULL, ESP_ERR_NO_MEM, err, TAG, "Failed to allocate SNTP storage"); diff --git a/components/esp_netif/test_apps/test_app_esp_netif/main/esp_netif_test.c b/components/esp_netif/test_apps/test_app_esp_netif/main/esp_netif_test.c index 79f70ac27a..84705bc784 100644 --- a/components/esp_netif/test_apps/test_app_esp_netif/main/esp_netif_test.c +++ b/components/esp_netif/test_apps/test_app_esp_netif/main/esp_netif_test.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Unlicense OR CC0-1.0 */ diff --git a/docs/en/api-reference/network/esp_netif.rst b/docs/en/api-reference/network/esp_netif.rst index 2ff9b9f3ff..d1fff7e542 100644 --- a/docs/en/api-reference/network/esp_netif.rst +++ b/docs/en/api-reference/network/esp_netif.rst @@ -264,7 +264,7 @@ You can find a brief introduction to SNTP in general, its initialization code, a This section provides more details about specific use cases of the SNTP service, with statically configured servers, or use the DHCP-provided servers, or both. The workflow is usually very simple: -1) Initialize and configure the service using :cpp:func:`esp_netif_sntp_init()`. +1) Initialize and configure the service using :cpp:func:`esp_netif_sntp_init()`. This operations can only be called once (unless the SNTP service has been destroyed by :cpp:func:`esp_netif_sntp_deinit()`) 2) Start the service via :cpp:func:`esp_netif_sntp_start()`. This step is not needed if we auto-started the service in the previous step (default). It is useful to start the service explicitly after connecting if we want to use the DHCP-obtained NTP servers. Please note, this option needs to be enabled before connecting, but the SNTP service should be started after. 3) Wait for the system time to synchronize using :cpp:func:`esp_netif_sntp_sync_wait()` (only if needed). 4) Stop and destroy the service using :cpp:func:`esp_netif_sntp_deinit()`. diff --git a/docs/zh_CN/api-reference/network/esp_netif.rst b/docs/zh_CN/api-reference/network/esp_netif.rst index 3eb9bfe3e8..0b6a9a34fd 100644 --- a/docs/zh_CN/api-reference/network/esp_netif.rst +++ b/docs/zh_CN/api-reference/network/esp_netif.rst @@ -264,7 +264,7 @@ SNTP 的简要介绍、初始化代码和基本模式请参阅 :doc:`系统时 本节介绍了使用 SNTP 服务特定用例的详细信息,包括静态配置的服务器、使用 DHCP 提供的服务器或两者兼备的情况,操作流程如下: -1) 调用 :cpp:func:`esp_netif_sntp_init()` 初始化服务并完成配置。 +1) 调用 :cpp:func:`esp_netif_sntp_init()` 初始化服务并完成配置。此操作只能执行一次(除非已调用 :cpp:func:`esp_netif_sntp_deinit()` 销毁 SNTP 服务)。 2) 调用 :cpp:func:`esp_netif_sntp_start()` 启动服务。如果在前一步中已经默认启动了服务,则不需要此步骤。如果需使用通过 DHCP 获取的 NTP 服务器,推荐在完成连接后显式启动该服务。注意,应在连接前启用通过 DHCP 获取的 NTP 服务器选项,并在连接后再启用 SNTP 服务。 3) 需要时,可调用 :cpp:func:`esp_netif_sntp_sync_wait()` 等待系统时间同步。 4) 调用 :cpp:func:`esp_netif_sntp_deinit()` 停止并销毁服务。