From d7a488fcb665e782d6a5fb65eb37d3e404d0481b Mon Sep 17 00:00:00 2001 From: mkardous-silabs <84793247+mkardous-silabs@users.noreply.github.com> Date: Mon, 29 Apr 2024 20:26:57 -0400 Subject: [PATCH 01/33] [Silabs] Update Silabs SDK versions (#33229) * Update SDK to latest versions * Update docker version * Update slcp with new gsdk version * Update gitmodules * Update matter support submodule * Refactor Sleepy APIs for 917 * restyle * update cloud build --------- Co-authored-by: Rohan Sahay --- .github/workflows/examples-efr32.yaml | 2 +- .github/workflows/release_artifacts.yaml | 11 +-- .gitmodules | 5 +- examples/platform/silabs/FreeRTOSConfig.h | 17 +++- examples/platform/silabs/MatterConfig.cpp | 66 ++++++++++++-- .../silabs/SiWx917/SiWx917/sl_wifi_if.cpp | 86 ++++++++++++------- .../silabs/ldscripts/SiWx917-common.ld | 10 ++- examples/platform/silabs/matter-platform.slcp | 2 +- integrations/cloudbuild/smoke-test.yaml | 2 +- src/platform/silabs/SiWx917/BUILD.gn | 5 +- .../silabs/SiWx917/wifi/wfx_notify.cpp | 26 +----- .../platformAbstraction/WiseMcuSpam.cpp | 24 ++++-- third_party/silabs/SiWx917_sdk.gni | 23 +++-- third_party/silabs/gecko_sdk | 2 +- third_party/silabs/matter_support | 2 +- third_party/silabs/wifi_sdk | 2 +- 16 files changed, 190 insertions(+), 95 deletions(-) diff --git a/.github/workflows/examples-efr32.yaml b/.github/workflows/examples-efr32.yaml index 019807f32164c0..b160b8ed5e2df8 100644 --- a/.github/workflows/examples-efr32.yaml +++ b/.github/workflows/examples-efr32.yaml @@ -40,7 +40,7 @@ jobs: if: github.actor != 'restyled-io[bot]' container: - image: ghcr.io/project-chip/chip-build-efr32:47 + image: ghcr.io/project-chip/chip-build-efr32:49 volumes: - "/tmp/bloat_reports:/tmp/bloat_reports" steps: diff --git a/.github/workflows/release_artifacts.yaml b/.github/workflows/release_artifacts.yaml index 1622808396cee8..435ab054dc3ad5 100644 --- a/.github/workflows/release_artifacts.yaml +++ b/.github/workflows/release_artifacts.yaml @@ -23,7 +23,7 @@ on: env: CHIP_NO_LOG_TIMESTAMPS: true - + jobs: esp32: name: ESP32 @@ -38,7 +38,7 @@ jobs: - name: Checkout uses: actions/checkout@v4 with: - ref: "${{ github.event.inputs.releaseTag }}" + ref: "${{ github.event.inputs.releaseTag }}" - name: Bootstrap uses: ./.github/actions/bootstrap @@ -64,17 +64,18 @@ jobs: runs-on: ubuntu-latest container: - image: ghcr.io/project-chip/chip-build-efr32:47 + image: ghcr.io/project-chip/chip-build-efr32:49 steps: - name: Checkout uses: actions/checkout@v4 with: - ref: "${{ github.event.inputs.releaseTag }}" + ref: "${{ github.event.inputs.releaseTag }}" - name: Bootstrap uses: ./.github/actions/bootstrap - name: Build example EFR32 Lock App - run: scripts/examples/gn_silabs_example.sh examples/lock-app/efr32/ + run: + scripts/examples/gn_silabs_example.sh examples/lock-app/efr32/ out/lock_app_debug $SILABS_BOARD - name: Upload artifact diff --git a/.gitmodules b/.gitmodules index be8c70fb160cba..c372f58f4402b6 100644 --- a/.gitmodules +++ b/.gitmodules @@ -244,7 +244,7 @@ [submodule "third_party/silabs/gecko_sdk"] path = third_party/silabs/gecko_sdk url = https://github.com/SiliconLabs/gecko_sdk.git - branch = v4.4.1 + branch = v4.4.2 platforms = silabs [submodule "third_party/silabs/wiseconnect-wifi-bt-sdk"] path = third_party/silabs/wiseconnect-wifi-bt-sdk @@ -254,7 +254,7 @@ [submodule "third_party/silabs/wifi_sdk"] path = third_party/silabs/wifi_sdk url = https://github.com/SiliconLabs/wiseconnect.git - branch = v3.1.3 + branch = v3.1.3-matter-hotfix.4 platforms = silabs [submodule "editline"] path = third_party/editline/repo @@ -334,4 +334,3 @@ url = https://github.com/Infineon/optiga-trust-m.git branch = matter_support platforms = infineon - diff --git a/examples/platform/silabs/FreeRTOSConfig.h b/examples/platform/silabs/FreeRTOSConfig.h index fd6658c7af35e2..ec926f4bbbeb94 100644 --- a/examples/platform/silabs/FreeRTOSConfig.h +++ b/examples/platform/silabs/FreeRTOSConfig.h @@ -141,11 +141,21 @@ extern uint32_t SystemCoreClock; /* Energy saving modes. */ #if defined(SL_CATALOG_POWER_MANAGER_PRESENT) #define configUSE_TICKLESS_IDLE 1 +#elif SL_ICD_ENABLED && SI917_M4_SLEEP_ENABLED +#define configUSE_TICKLESS_IDLE 1 +#define configEXPECTED_IDLE_TIME_BEFORE_SLEEP 70 +#define configPRE_SUPPRESS_TICKS_AND_SLEEP_PROCESSING(x) vTaskPreSuppressTicksAndSleepProcessing(&x) +#define configPRE_SLEEP_PROCESSING(x) sl_wfx_host_si91x_sleep(&x) +#define configPOST_SLEEP_PROCESSING(x) sl_si91x_post_sleep_update_ticks(&x) #else #define configUSE_TICKLESS_IDLE 0 #endif // SL_CATALOG_POWER_MANAGER_PRESENT +#if defined(SLI_SI91X_MCU_INTERFACE) +#define configTICK_RATE_HZ (1000) +#else #define configTICK_RATE_HZ (1024) +#endif // SLI_SI91X_MCU_INTERFACE /* Definition used by Keil to replace default system clock source. */ #define configOVERRIDE_DEFAULT_TICK_CONFIGURATION 1 @@ -201,8 +211,11 @@ See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html. */ #define configUSE_PORT_OPTIMISED_TASK_SELECTION (0) #define configUSE_TICKLESS_IDLE_SIMPLE_DEBUG (1) /* See into vPortSuppressTicksAndSleep source code for explanation */ #define configMAX_PRIORITIES (56) -#define configMINIMAL_STACK_SIZE (320) /* Number of words to use for Idle and Timer stacks */ - +#if SLI_SI91X_MCU_INTERFACE && SL_ICD_ENABLED +#define configMINIMAL_STACK_SIZE (1024) /* Number of words to use for Idle and Timer stacks */ +#else // For EFR32 +#define configMINIMAL_STACK_SIZE (320) /* Number of words to use for Idle and Timer stacks */ +#endif // SLI_SI91X_MCU_INTERFACE && SL_ICD_ENABLED #ifdef HEAP_MONITORING #define configMAX_TASK_NAME_LEN (24) #else diff --git a/examples/platform/silabs/MatterConfig.cpp b/examples/platform/silabs/MatterConfig.cpp index d85f10d0612ea1..9cc030557ab0f3 100644 --- a/examples/platform/silabs/MatterConfig.cpp +++ b/examples/platform/silabs/MatterConfig.cpp @@ -43,7 +43,10 @@ #ifdef SLI_SI91X_MCU_INTERFACE #include "wfx_rsi.h" -#endif /* SLI_SI91X_MCU_INTERFACE */ +#if CHIP_CONFIG_ENABLE_ICD_SERVER && SI917_M4_SLEEP_ENABLED +#include "rsi_m4.h" +#endif // CHIP_CONFIG_ENABLE_ICD_SERVER && SI917_M4_SLEEP_ENABLED +#endif // SLI_SI91X_MCU_INTERFACE #include // If building with the EFR32-provided crypto backend, we can use the @@ -342,7 +345,6 @@ CHIP_ERROR SilabsMatterConfig::InitWiFi(void) sl_status_t status; if ((status = wfx_wifi_rsi_init()) != SL_STATUS_OK) { - SILABS_LOG("wfx_wifi_rsi_init failed with status: %x", status); ReturnErrorOnFailure((CHIP_ERROR) status); } #endif // SLI_SI91X_MCU_INTERFACE @@ -354,9 +356,63 @@ CHIP_ERROR SilabsMatterConfig::InitWiFi(void) // ================================================================================ // FreeRTOS Callbacks // ================================================================================ -extern "C" void vApplicationIdleHook(void) +#if CHIP_CONFIG_ENABLE_ICD_SERVER && SI917_M4_SLEEP_ENABLED +static bool is_sleep_ready = false; +void vTaskPreSuppressTicksAndSleepProcessing(uint16_t * xExpectedIdleTime) { -#if SLI_SI91X_MCU_INTERFACE && CHIP_CONFIG_ENABLE_ICD_SERVER - sl_wfx_host_si91x_sleep_wakeup(); + // pointer check + if (xExpectedIdleTime == NULL) + { + return; + } + + if (!is_sleep_ready) + { + *xExpectedIdleTime = 0; + } + else + { + // a preliminary check of the expected idle time is performed without making M4 inactive + if (*xExpectedIdleTime >= configEXPECTED_IDLE_TIME_BEFORE_SLEEP) + { + // Indicate M4 is Inactive + P2P_STATUS_REG &= ~M4_is_active; + // Waiting for one more clock cycle to make sure M4 H/W Register is updated + P2P_STATUS_REG; + + // TODO: This delay is added to sync between M4 and TA. It should be removed once the logic is moved to wifi SDK + for (uint8_t delay = 0; delay < 10; delay++) + { + __ASM("NOP"); + } + // Checking if TA has already triggered a packet to M4 + // RX_BUFFER_VALID will be cleared by TA if any packet is triggered + if ((P2P_STATUS_REG & TA_wakeup_M4) || (P2P_STATUS_REG & M4_wakeup_TA) || (!(M4SS_P2P_INTR_SET_REG & RX_BUFFER_VALID))) + { + P2P_STATUS_REG |= M4_is_active; + *xExpectedIdleTime = 0; + } + else + { + M4SS_P2P_INTR_CLR_REG = RX_BUFFER_VALID; + M4SS_P2P_INTR_CLR_REG; + + TASS_P2P_INTR_MASK_SET = (TX_PKT_TRANSFER_DONE_INTERRUPT | RX_PKT_TRANSFER_DONE_INTERRUPT | + TA_WRITING_ON_COMM_FLASH | NWP_DEINIT_IN_COMM_FLASH +#ifdef SL_SI91X_SIDE_BAND_CRYPTO + | SIDE_BAND_CRYPTO_DONE #endif + ); + } + } + } +} +#endif // CHIP_CONFIG_ENABLE_ICD_SERVER && SI917_M4_SLEEP_ENABLED +extern "C" void vApplicationIdleHook(void) +{ +#if CHIP_CONFIG_ENABLE_ICD_SERVER && SI917_M4_SLEEP_ENABLED + invoke_btn_press_event(); + // is_sleep_ready is required since wfx_is_sleep_ready() is not FreeRTOS scheduler agnostic + is_sleep_ready = wfx_is_sleep_ready(); +#endif // CHIP_CONFIG_ENABLE_ICD_SERVER && SI917_M4_SLEEP_ENABLED } diff --git a/examples/platform/silabs/SiWx917/SiWx917/sl_wifi_if.cpp b/examples/platform/silabs/SiWx917/SiWx917/sl_wifi_if.cpp index a8dc13c1eacec9..1759d2df9e6e53 100644 --- a/examples/platform/silabs/SiWx917/SiWx917/sl_wifi_if.cpp +++ b/examples/platform/silabs/SiWx917/SiWx917/sl_wifi_if.cpp @@ -78,6 +78,11 @@ extern "C" { WfxRsi_t wfx_rsi; +// TODO: remove this. Added only to monitor how many watch dog reset have happened during testing. +#ifdef SLI_SI91X_MCU_INTERFACE +volatile uint32_t watchdog_reset = 0; +#endif // SLI_SI91X_MCU_INTERFACE + /* Declare a variable to hold the data associated with the created event group. */ StaticEventGroup_t rsiDriverEventGroup; @@ -274,42 +279,52 @@ sl_status_t join_callback_handler(sl_wifi_event_t event, char * result, uint32_t #if SL_ICD_ENABLED -#if SLI_SI91X_MCU_INTERFACE -/****************************************************************** - * @fn sl_wfx_host_si91x_sleep_wakeup() - * @brief - * M4 going to sleep - * - * @param[in] None - * @return - * None - *********************************************************************/ -void sl_wfx_host_si91x_sleep_wakeup() +#if SI917_M4_SLEEP_ENABLED +// Required to invoke button press event during sleep as falling edge is not detected +void invoke_btn_press_event() { - if (wfx_rsi.dev_state & WFX_RSI_ST_SLEEP_READY) + // TODO: should be removed once we are getting the press interrupt for button 0 with sleep + if (!RSI_NPSSGPIO_GetPin(SL_BUTTON_BTN0_PIN) && !btn0_pressed) { - // TODO: should be removed once we are getting the press interrupt for button 0 with sleep - if (!RSI_NPSSGPIO_GetPin(SL_BUTTON_BTN0_PIN) && !btn0_pressed) - { - sl_button_on_change(SL_BUTTON_BTN0_NUMBER, BUTTON_PRESSED); - btn0_pressed = true; - } - if (RSI_NPSSGPIO_GetPin(SL_BUTTON_BTN0_PIN)) - { -#ifdef DISPLAY_ENABLED - // if LCD is enabled, power down the lcd before setting the M4 to sleep - sl_si91x_hardware_setup(); -#endif - btn0_pressed = false; - /* Configure RAM Usage and Retention Size */ - sl_si91x_m4_sleep_wakeup(); -#if SILABS_LOG_ENABLED - silabsInitLog(); -#endif - } + sl_button_on_change(SL_BUTTON_BTN0_NUMBER, BUTTON_PRESSED); + btn0_pressed = true; + } + if (RSI_NPSSGPIO_GetPin(SL_BUTTON_BTN0_PIN)) + { + btn0_pressed = false; } } -#endif // SLI_SI91X_MCU_INTERFACE + +/** + * @brief Checks if the Wi-Fi module is ready for sleep. + * + * This function checks if the Wi-Fi module is ready to enter sleep mode. + * + * @return true if the Wi-Fi module is ready for sleep, false otherwise. + */ +bool wfx_is_sleep_ready() +{ + // BRD4002A board BTN_PRESS is 0 when pressed, release is 1 + // sli_si91x_is_sleep_ready requires OS Scheduler to be active + return ((RSI_NPSSGPIO_GetPin(SL_BUTTON_BTN0_PIN) != 0) && (wfx_rsi.dev_state & WFX_RSI_ST_SLEEP_READY) && + sli_si91x_is_sleep_ready()); +} + +/** + * @brief Sleeps for a specified duration and then wakes up. + * + * This function puts the SI91x host into sleep mode for the specified duration + * in milliseconds and then wakes it up. + * + * @param sleep_time_ms The duration in milliseconds to sleep. + */ +void sl_wfx_host_si91x_sleep(uint16_t * sleep_time_ms) +{ + SL_ASSERT(sleep_time_ms != NULL); + sl_si91x_m4_sleep_wakeup(sleep_time_ms); +} + +#endif // SI917_M4_SLEEP_ENABLED /****************************************************************** * @fn wfx_rsi_power_save() @@ -363,6 +378,13 @@ int32_t wfx_wifi_rsi_init(void) SILABS_LOG("wfx_wifi_rsi_init started"); sl_status_t status; status = sl_wifi_init(&config, NULL, sl_wifi_default_event_handler); +#ifdef SLI_SI91X_MCU_INTERFACE + // TODO: remove this. Added only to monitor how many watch dog reset have happened during testing. + if ((MCU_FSM->MCU_FSM_WAKEUP_STATUS_REG) & BIT(5)) + { + watchdog_reset++; + } +#endif // SLI_SI91X_MCU_INTERFACE if (status != SL_STATUS_OK) { return status; diff --git a/examples/platform/silabs/ldscripts/SiWx917-common.ld b/examples/platform/silabs/ldscripts/SiWx917-common.ld index b0168a06ecf235..f23fecf8950d4c 100644 --- a/examples/platform/silabs/ldscripts/SiWx917-common.ld +++ b/examples/platform/silabs/ldscripts/SiWx917-common.ld @@ -40,7 +40,7 @@ SECTIONS { KEEP(*(.isr_vector)) KEEP(*(.reset_handler)) - *(EXCLUDE_FILE(*sl_si91x_bus.c.o *sl_si91x_driver.c.o *sli_si91x_multithreaded.c.o *rsi_hal_mcu_m4_ram.c.o *rsi_deepsleep_soc.c.o *croutine.c.o *event_groups.c.o *list.c.o *queue.c.o *stream_buffer.c.o *tasks.c.o *timers.c.o *cmsis_os2.c.o *freertos_umm_malloc_host.c.o *malloc_buffers.c.o *sl_rsi_utility.c.o *port.c.o *heap_*.c.o) .text*) + *(EXCLUDE_FILE(*sl_si91x_bus.c.o *sl_si91x_driver.c.o *sli_si91x_multithreaded.c.o *rsi_hal_mcu_m4_ram.c.o *rsi_hal_mcu_m4_rom.c.o *rsi_deepsleep_soc.c.o *croutine.c.o *event_groups.c.o *list.c.o *queue.c.o *stream_buffer.c.o *tasks.c.o *timers.c.o *cmsis_os2.c.o *freertos_umm_malloc_host.c.o *malloc_buffers.c.o *sl_rsi_utility.c.o *port.c.o *heap_*.c.o *os_systick.c.o *sl_wifi_if.c.o *sl_si91x_m4_ps.c.o *sl_platform_wireless.c.o) .text*) /* .ctors */ *crtbegin.o(.ctors) @@ -131,7 +131,8 @@ SECTIONS *sl_si91x_driver.c.o(.text*) *sli_si91x_multithreaded.c.o(.text*) *rsi_hal_mcu_m4_ram.c.o(.text*) - *rsi_deepsleep_soc.c.o(.text*) + *rsi_hal_mcu_m4_rom.c.o(.text*) + *rsi_deepsleep_soc.c.o(.text*) *croutine.c.o(.text*) *event_groups.c.o(.text*) *list.c.o(.text*) @@ -145,6 +146,10 @@ SECTIONS *sl_rsi_utility.c.o(.text*) *port.c.o(.text*) *heap_*.c.o(.text*) + *os_systick.c.o(.text*) + *sl_wifi_if.c.o(.text*) + *sl_si91x_m4_ps.c.o(.text*) + *sl_platform_wireless.c.o(.text*) . = ALIGN(4); /* preinit data */ @@ -252,4 +257,3 @@ SECTIONS app_flash_end = 0x8202000 + 0x1fe000; ASSERT( (linker_nvm_begin + SIZEOF(.nvm)) <= app_flash_end, "NVM3 is excessing the flash size !") } - diff --git a/examples/platform/silabs/matter-platform.slcp b/examples/platform/silabs/matter-platform.slcp index 3e1c52a6ec66f5..4f5d1ef2c05064 100644 --- a/examples/platform/silabs/matter-platform.slcp +++ b/examples/platform/silabs/matter-platform.slcp @@ -27,7 +27,7 @@ include: file_list: - {path: app.h} - {path: reset_util.h} -sdk: {id: gecko_sdk, version: 4.3.1} +sdk: {id: gecko_sdk, version: 4.4.2} toolchain_settings: [] component: diff --git a/integrations/cloudbuild/smoke-test.yaml b/integrations/cloudbuild/smoke-test.yaml index 5003d089257366..de4d5d9b36e3fe 100644 --- a/integrations/cloudbuild/smoke-test.yaml +++ b/integrations/cloudbuild/smoke-test.yaml @@ -66,7 +66,7 @@ steps: - name: pwenv path: /pwenv - - name: "ghcr.io/project-chip/chip-build-vscode:47" + - name: "ghcr.io/project-chip/chip-build-vscode:49" id: EFR32 env: - PW_ENVIRONMENT_ROOT=/pwenv diff --git a/src/platform/silabs/SiWx917/BUILD.gn b/src/platform/silabs/SiWx917/BUILD.gn index c0efdd6eab6a97..2eee75de7ba3bd 100644 --- a/src/platform/silabs/SiWx917/BUILD.gn +++ b/src/platform/silabs/SiWx917/BUILD.gn @@ -73,7 +73,10 @@ static_library("SiWx917") { ] } - public_deps = [ "${chip_root}/src/platform:platform_base" ] + public_deps = [ + "${chip_root}/src/app/icd/server:icd-server-config", + "${chip_root}/src/platform:platform_base", + ] deps = [ "${chip_root}/src/platform/logging:headers" ] # Add platform crypto implementation diff --git a/src/platform/silabs/SiWx917/wifi/wfx_notify.cpp b/src/platform/silabs/SiWx917/wifi/wfx_notify.cpp index ac5e8c304f5dcf..60ee45dee13e99 100644 --- a/src/platform/silabs/SiWx917/wifi/wfx_notify.cpp +++ b/src/platform/silabs/SiWx917/wifi/wfx_notify.cpp @@ -35,9 +35,7 @@ #ifdef __cplusplus extern "C" { #endif -#include "sl_si91x_m4_ps.h" -extern "C" uint8_t m4_alarm_initialization_done; -extern "C" void set_alarm_interrupt_timer(uint16_t interval); + #ifdef __cplusplus } #endif @@ -203,12 +201,6 @@ void wfx_ip_changed_notify(int got_ip) ********************************************************************************************/ void wfx_retry_interval_handler(bool is_wifi_disconnection_event, uint16_t retryJoin) { -#if SL_ICD_ENABLED - if (m4_alarm_initialization_done == false) - { - initialize_m4_alarm(); - } -#endif // SL_ICD_ENABLED if (!is_wifi_disconnection_event) { /* After the reboot or a commissioning time device failed to connect with AP. @@ -221,18 +213,10 @@ void wfx_retry_interval_handler(bool is_wifi_disconnection_event, uint16_t retry // TODO: cleanup the retry logic MATTER-1921 if (!chip::Server::GetInstance().GetCommissioningWindowManager().IsCommissioningWindowOpen()) { - set_alarm_interrupt_timer(WLAN_RETRY_TIMER_MS / 1000); wfx_rsi_power_save(RSI_SLEEP_MODE_8, STANDBY_POWER_SAVE_WITH_RAM_RETENTION); - // TODO: remove this once TICKLESS_IDLE is applied. MATTER-3134 - sl_wfx_host_si91x_sleep_wakeup(); } - else - { - vTaskDelay(pdMS_TO_TICKS(WLAN_RETRY_TIMER_MS)); - } -#else - vTaskDelay(pdMS_TO_TICKS(WLAN_RETRY_TIMER_MS)); #endif // SL_ICD_ENABLED + vTaskDelay(pdMS_TO_TICKS(WLAN_RETRY_TIMER_MS)); } else { @@ -252,13 +236,9 @@ void wfx_retry_interval_handler(bool is_wifi_disconnection_event, uint16_t retry } SILABS_LOG("wfx_retry_interval_handler : Next attempt after %d Seconds", CONVERT_MS_TO_SEC(retryInterval)); #if SL_ICD_ENABLED - set_alarm_interrupt_timer(retryInterval / 1000); wfx_rsi_power_save(RSI_SLEEP_MODE_8, STANDBY_POWER_SAVE_WITH_RAM_RETENTION); - // TODO: remove this once TICKLESS_IDLE is applied. MATTER-3134 - sl_wfx_host_si91x_sleep_wakeup(); -#else - vTaskDelay(pdMS_TO_TICKS(retryInterval)); #endif // SL_ICD_ENABLED + vTaskDelay(pdMS_TO_TICKS(retryInterval)); retryInterval += retryInterval; } } diff --git a/src/platform/silabs/platformAbstraction/WiseMcuSpam.cpp b/src/platform/silabs/platformAbstraction/WiseMcuSpam.cpp index ba957671e6c166..1d4456a53868d3 100644 --- a/src/platform/silabs/platformAbstraction/WiseMcuSpam.cpp +++ b/src/platform/silabs/platformAbstraction/WiseMcuSpam.cpp @@ -20,9 +20,11 @@ #include #include +#include + #if SILABS_LOG_ENABLED #include "silabs_utils.h" -#endif +#endif // SILABS_LOG_ENABLED // TODO add includes ? extern "C" { @@ -33,13 +35,12 @@ extern "C" { #include "sl_si91x_button_pin_config.h" #include "sl_si91x_led.h" #include "sl_si91x_led_config.h" + +#if CHIP_CONFIG_ENABLE_ICD_SERVER == 0 void soc_pll_config(void); +#endif // CHIP_CONFIG_ENABLE_ICD_SERVER } -#if SILABS_LOG_ENABLED -#include "silabs_utils.h" -#endif - #ifdef SL_CATALOG_SYSTEMVIEW_TRACE_PRESENT #include "SEGGER_SYSVIEW.h" #endif @@ -47,11 +48,12 @@ void soc_pll_config(void); namespace chip { namespace DeviceLayer { namespace Silabs { -#if SL_ICD_ENABLED namespace { +uint8_t sButtonStates[SL_SI91x_BUTTON_COUNT] = { 0 }; +#if CHIP_CONFIG_ENABLE_ICD_SERVER bool btn0_pressed = false; -} #endif /* SL_ICD_ENABLED */ +} // namespace SilabsPlatform SilabsPlatform::sSilabsPlatformAbstractionManager; SilabsPlatform::SilabsButtonCb SilabsPlatform::mButtonCallback = nullptr; @@ -63,10 +65,10 @@ CHIP_ERROR SilabsPlatform::Init(void) // TODO: Setting the highest priority for SVCall_IRQn to avoid the HardFault issue NVIC_SetPriority(SVCall_IRQn, CORE_INTERRUPT_HIGHEST_PRIORITY); -#ifndef SL_ICD_ENABLED +#if CHIP_CONFIG_ENABLE_ICD_SERVER == 0 // Configuration the clock rate soc_pll_config(); -#endif +#endif // CHIP_CONFIG_ENABLE_ICD_SERVER #if SILABS_LOG_ENABLED silabsInitLog(); @@ -143,6 +145,10 @@ void sl_button_on_change(uint8_t btn, uint8_t btnAction) return; } + if (btn < SL_SI91x_BUTTON_COUNT) + { + sButtonStates[btn] = btnAction; + } Silabs::GetPlatform().mButtonCallback(btn, btnAction); } } diff --git a/third_party/silabs/SiWx917_sdk.gni b/third_party/silabs/SiWx917_sdk.gni index 00e077d41da221..48abc728a4bf50 100644 --- a/third_party/silabs/SiWx917_sdk.gni +++ b/third_party/silabs/SiWx917_sdk.gni @@ -26,10 +26,13 @@ examples_plat_dir = "${chip_root}/examples/platform/silabs/SiWx917" declare_args() { # Enable the Alarm Based Wakeup for 917 SoC when sleep is enabled - si91x_alarm_based_wakeup = false + si91x_alarm_based_periodic_wakeup = false # Periodic time at which the 917 SoC should wakeup si91x_alarm_periodic_time = 30 + + # enable 917 SoC M4 sleep wakeup + si917_m4_sleep_enabled = false } # Defines an siwx917 SDK build target. @@ -206,7 +209,7 @@ template("siwx917_sdk") { "SPI_MULTI_SLAVE=1", "SYSCALLS_WRITE=1", "__STATIC_INLINE=static inline", - "SL_SI91X_SI917_RAM_MEM_CONFIG=2", + "SL_SI91X_SI917_RAM_MEM_CONFIG=3", "SL_SI91x_DUAL_INTERRUPTS_ERRATA=1", "EXT_IRQ_COUNT=75", "FLASH_PAGE_SIZE=1", @@ -221,6 +224,7 @@ template("siwx917_sdk") { "SLI_SI91X_MCU_ENABLE_IPMU_APIS=1", "RADIO_CONFIG_DMP_SUPPORT=1", "configUSE_POSIX_ERRNO=1", + "NVM3_LOCK_OVERRIDE=1", ] if (silabs_log_enabled && chip_logging) { @@ -271,6 +275,8 @@ template("siwx917_sdk") { "SI91X_SYSRTC_COUNT=1", "SYSCALLS_WRITE", "SPI_MULTI_SLAVE", + "SL_ULP_TIMER", + "SL_SLEEP_TIMER", ] } @@ -288,12 +294,17 @@ template("siwx917_sdk") { "SL_ICD_SUPPORTED_CLIENTS_PER_FABRIC=${sl_icd_supported_clients_per_fabric}", "SL_SI91X_MCU_WIRELESS_BASED_WAKEUP=1", "SL_SI91X_MCU_BUTTON_BASED_WAKEUP=1", + "SL_SI91X_MCU_ALARM_BASED_WAKEUP=1", ] - if (si91x_alarm_based_wakeup) { + if (si91x_alarm_based_periodic_wakeup) { + defines += [ "ALARM_PERIODIC_TIME=${si91x_alarm_periodic_time}" ] + } + + if (si917_m4_sleep_enabled) { defines += [ - "SL_SI91X_MCU_ALARM_BASED_WAKEUP=1", - "ALARM_PERIODIC_TIME=${si91x_alarm_periodic_time}", + "SI917_M4_SLEEP_ENABLED=1", + "XTAL_OFF", ] } } @@ -532,7 +543,7 @@ template("siwx917_sdk") { if (chip_enable_icd_server) { sources += [ - "${sdk_support_root}/matter/si91x/siwx917/BRD4338A/support/src/sl_si91x_m4_ps.c", + "${wifi_sdk_root}/components/device/silabs/si91x/mcu/drivers/peripheral_drivers/src/sl_si91x_m4_ps.c", "${wifi_sdk_root}/components/device/silabs/si91x/mcu/drivers/systemlevel/src/rsi_rtc.c", "${wifi_sdk_root}/components/device/silabs/si91x/mcu/drivers/systemlevel/src/rsi_time_period.c", ] diff --git a/third_party/silabs/gecko_sdk b/third_party/silabs/gecko_sdk index 911f6cdefccbae..e359ba40a2ba5b 160000 --- a/third_party/silabs/gecko_sdk +++ b/third_party/silabs/gecko_sdk @@ -1 +1 @@ -Subproject commit 911f6cdefccbae03bc66e8c790ceb7e67ca07417 +Subproject commit e359ba40a2ba5b127964a6e7afe9e70ff5f9a1cf diff --git a/third_party/silabs/matter_support b/third_party/silabs/matter_support index 0dbd0dd89fa90d..56d4d4ec0dea03 160000 --- a/third_party/silabs/matter_support +++ b/third_party/silabs/matter_support @@ -1 +1 @@ -Subproject commit 0dbd0dd89fa90dc6e0d1d2636563ea980c010c19 +Subproject commit 56d4d4ec0dea032302f52632c15d4d7813f8e9f5 diff --git a/third_party/silabs/wifi_sdk b/third_party/silabs/wifi_sdk index 00dd57a85e0982..aa514d4fac4b56 160000 --- a/third_party/silabs/wifi_sdk +++ b/third_party/silabs/wifi_sdk @@ -1 +1 @@ -Subproject commit 00dd57a85e0982f85a41d029e15050479f69256b +Subproject commit aa514d4fac4b568d03e1f6d3d19c7811034d5077 From ee53359d97a9eb6a83738425617ed3df239c2909 Mon Sep 17 00:00:00 2001 From: cdj <45139296+DejinChen@users.noreply.github.com> Date: Tue, 30 Apr 2024 08:33:10 +0800 Subject: [PATCH 02/33] Add custom MRP configs for the esp platform (#33215) --- config/esp32/components/chip/Kconfig | 58 +++++++++++++++++++++++++ src/platform/ESP32/CHIPPlatformConfig.h | 34 +++++++++++++++ 2 files changed, 92 insertions(+) diff --git a/config/esp32/components/chip/Kconfig b/config/esp32/components/chip/Kconfig index 47ceceffe2f94d..5998b220ba2fe5 100644 --- a/config/esp32/components/chip/Kconfig +++ b/config/esp32/components/chip/Kconfig @@ -1229,4 +1229,62 @@ menu "CHIP Device Layer" endmenu + menu "Message Reliable Protocol Options" + config MRP_LOCAL_ACTIVE_RETRY_INTERVAL_FOR_THREAD + int "MRP local active retry interval for Thread network in milliseconds" + depends on OPENTHREAD_ENABLED + range 0 3600000 + default 800 + help + Base retry interval of the present Thread node when it is in the active state. + + config MRP_LOCAL_ACTIVE_RETRY_INTERVAL_FOR_WIFI_ETHERNET + int "MRP local active retry interval for WIFI or ETHERNET network in milliseconds" + depends on !OPENTHREAD_ENABLED + range 0 3600000 + default 300 + help + Base retry interval of the present node (WIFI or ETHERNET) when it is in the active state. + + config MRP_LOCAL_IDLE_RETRY_INTERVAL_FOR_THREAD + int "MRP local idle retry interval for Thread network in milliseconds" + depends on OPENTHREAD_ENABLED + range 0 3600000 + default 800 + help + Base retry interval of the present Thread node when it is in the idle state. + + config MRP_LOCAL_IDLE_RETRY_INTERVAL_FOR_WIFI_ETHERNET + int "MRP local idle retry interval for WIFI or ETHERNET network in milliseconds" + depends on !OPENTHREAD_ENABLED + range 0 3600000 + default 500 + help + Base retry interval of the present node (WIFI or ETHERNET) when it is in the idle state. + + config MRP_RETRY_INTERVAL_SENDER_BOOST_FOR_THREAD + int "MRP retransmission delta timeout for Thread network in milliseconds" + depends on OPENTHREAD_ENABLED + range 0 3600000 + default 500 + help + A constant value added to the calculated retransmission timeout. + + config MRP_RETRY_INTERVAL_SENDER_BOOST_FOR_WIFI_ETHERNET + int "MRP retransmission delta timeout for WIFI or ETHERNET network in milliseconds" + depends on !OPENTHREAD_ENABLED + range 0 3600000 + default 0 + help + A constant value added to the calculated retransmission timeout. + + config MRP_MAX_RETRANS + int "MRP retransmission maximum count" + range 1 10 + default 4 + help + The maximum number of retransmissions before giving up. + + endmenu + endmenu diff --git a/src/platform/ESP32/CHIPPlatformConfig.h b/src/platform/ESP32/CHIPPlatformConfig.h index d9012d41da58a8..bed7cb02357b3e 100644 --- a/src/platform/ESP32/CHIPPlatformConfig.h +++ b/src/platform/ESP32/CHIPPlatformConfig.h @@ -107,3 +107,37 @@ // Enable CONFIG_BUILD_FOR_HOST_UNIT_TEST when building CHIP test binaries #define CONFIG_BUILD_FOR_HOST_UNIT_TEST 1 #endif + +#ifndef CHIP_CONFIG_MRP_LOCAL_ACTIVE_RETRY_INTERVAL +#if CHIP_ENABLE_OPENTHREAD +#define CHIP_CONFIG_MRP_LOCAL_ACTIVE_RETRY_INTERVAL \ + chip::System::Clock::Milliseconds32(CONFIG_MRP_LOCAL_ACTIVE_RETRY_INTERVAL_FOR_THREAD) +#else +#define CHIP_CONFIG_MRP_LOCAL_ACTIVE_RETRY_INTERVAL \ + chip::System::Clock::Milliseconds32(CONFIG_MRP_LOCAL_ACTIVE_RETRY_INTERVAL_FOR_WIFI_ETHERNET) +#endif // CHIP_ENABLE_OPENTHREAD +#endif // CHIP_CONFIG_MRP_LOCAL_ACTIVE_RETRY_INTERVAL + +#ifndef CHIP_CONFIG_MRP_LOCAL_IDLE_RETRY_INTERVAL +#if CHIP_ENABLE_OPENTHREAD +#define CHIP_CONFIG_MRP_LOCAL_IDLE_RETRY_INTERVAL \ + chip::System::Clock::Milliseconds32(CONFIG_MRP_LOCAL_IDLE_RETRY_INTERVAL_FOR_THREAD) +#else +#define CHIP_CONFIG_MRP_LOCAL_IDLE_RETRY_INTERVAL \ + chip::System::Clock::Milliseconds32(CONFIG_MRP_LOCAL_IDLE_RETRY_INTERVAL_FOR_WIFI_ETHERNET) +#endif // CHIP_ENABLE_OPENTHREAD +#endif // CHIP_CONFIG_MRP_LOCAL_IDLE_RETRY_INTERVAL + +#ifndef CHIP_CONFIG_MRP_RETRY_INTERVAL_SENDER_BOOST +#if CHIP_ENABLE_OPENTHREAD +#define CHIP_CONFIG_MRP_RETRY_INTERVAL_SENDER_BOOST \ + chip::System::Clock::Milliseconds32(CONFIG_MRP_RETRY_INTERVAL_SENDER_BOOST_FOR_THREAD) +#else +#define CHIP_CONFIG_MRP_RETRY_INTERVAL_SENDER_BOOST \ + chip::System::Clock::Milliseconds32(CONFIG_MRP_RETRY_INTERVAL_SENDER_BOOST_FOR_WIFI_ETHERNET) +#endif // CHIP_ENABLE_OPENTHREAD +#endif // CHIP_CONFIG_MRP_RETRY_INTERVAL_SENDER_BOOST + +#ifndef CHIP_CONFIG_RMP_DEFAULT_MAX_RETRANS +#define CHIP_CONFIG_RMP_DEFAULT_MAX_RETRANS CONFIG_MRP_MAX_RETRANS +#endif // CHIP_CONFIG_RMP_DEFAULT_MAX_RETRANS From 85d4114162e5d293c71d6840c8115d7d61d8a111 Mon Sep 17 00:00:00 2001 From: Karsten Sperling <113487422+ksperling-apple@users.noreply.github.com> Date: Tue, 30 Apr 2024 12:47:13 +1200 Subject: [PATCH 03/33] Darwin: Add more tests and tidy up MTRSetupPayload (#33234) * Darwin Tests: Make MTRSetupPayload initialization test reliable Also rename the tests to more conventional names. * Add regression test for #31129 * Add regression test for #23357 * Add test for NSSecureCoding support * Darwin: Tidy up MTRSetupPayload headers / includes * Darwin: return nil on error in MTRSetupPayload getAllOptionalVendorData --- src/darwin/Framework/CHIP/MTRSetupPayload.mm | 17 ++-- .../Framework/CHIP/MTRSetupPayload_Internal.h | 27 ++++-- ...m => MTRSetupPayloadInitializationTests.m} | 23 ++--- ...adParserTests.m => MTRSetupPayloadTests.m} | 90 ++++++++++++++++--- .../Matter.xcodeproj/project.pbxproj | 16 ++-- 5 files changed, 129 insertions(+), 44 deletions(-) rename src/darwin/Framework/CHIPTests/{MTRSetupPayloadSerializerTests.m => MTRSetupPayloadInitializationTests.m} (72%) rename src/darwin/Framework/CHIPTests/{MTRSetupPayloadParserTests.m => MTRSetupPayloadTests.m} (72%) diff --git a/src/darwin/Framework/CHIP/MTRSetupPayload.mm b/src/darwin/Framework/CHIP/MTRSetupPayload.mm index 309494e3a01922..11afc2a15c1cde 100644 --- a/src/darwin/Framework/CHIP/MTRSetupPayload.mm +++ b/src/darwin/Framework/CHIP/MTRSetupPayload.mm @@ -1,6 +1,6 @@ /** * - * Copyright (c) 2020 Project CHIP Authors + * Copyright (c) 2020-2024 Project CHIP Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,20 +15,21 @@ * limitations under the License. */ -#import "MTRError.h" +#import "MTRSetupPayload_Internal.h" + #import "MTRError_Internal.h" #import "MTRFramework.h" #import "MTROnboardingPayloadParser.h" -#import "MTRSetupPayload_Internal.h" -#import "setup_payload/ManualSetupPayloadGenerator.h" -#import "setup_payload/QRCodeSetupPayloadGenerator.h" -#import +#include +#include +#include #include @implementation MTROptionalQRCodeInfo @end +MTR_DIRECT_MEMBERS @implementation MTRSetupPayload { chip::SetupPayload _chipSetupPayload; } @@ -182,7 +183,7 @@ - (void)getSerialNumber:(chip::SetupPayload)setupPayload if (error) { *error = [NSError errorWithDomain:MTRErrorDomain code:MTRErrorCodeInvalidArgument userInfo:nil]; } - return @[]; + return nil; } [allOptionalData addObject:info]; } @@ -418,6 +419,7 @@ + (MTRDiscoveryCapabilities)_unboxDiscoveryCapabilities:(nullable NSNumber *)box @end +MTR_DIRECT_MEMBERS @implementation MTROptionalQRCodeInfo (Deprecated) - (NSNumber *)infoType @@ -432,6 +434,7 @@ - (void)setInfoType:(NSNumber *)infoType @end +MTR_DIRECT_MEMBERS @implementation MTRSetupPayload (Deprecated) - (nullable NSNumber *)rendezvousInformation diff --git a/src/darwin/Framework/CHIP/MTRSetupPayload_Internal.h b/src/darwin/Framework/CHIP/MTRSetupPayload_Internal.h index 6cac43e7d5ea4b..a119a4b6e2059f 100644 --- a/src/darwin/Framework/CHIP/MTRSetupPayload_Internal.h +++ b/src/darwin/Framework/CHIP/MTRSetupPayload_Internal.h @@ -1,19 +1,30 @@ -// -// MTRSetupPayload_Internal.h -// MTR -// -// Copyright © 2021 CHIP. All rights reserved. -// - -#import +/** + * + * Copyright (c) 2021-2024 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ #import "MTRSetupPayload.h" +#import "MTRDefines_Internal.h" + #ifdef __cplusplus #import #import #endif +MTR_DIRECT_MEMBERS @interface MTRSetupPayload () #ifdef __cplusplus diff --git a/src/darwin/Framework/CHIPTests/MTRSetupPayloadSerializerTests.m b/src/darwin/Framework/CHIPTests/MTRSetupPayloadInitializationTests.m similarity index 72% rename from src/darwin/Framework/CHIPTests/MTRSetupPayloadSerializerTests.m rename to src/darwin/Framework/CHIPTests/MTRSetupPayloadInitializationTests.m index 61a819f33b961f..ce1f49929f0483 100644 --- a/src/darwin/Framework/CHIPTests/MTRSetupPayloadSerializerTests.m +++ b/src/darwin/Framework/CHIPTests/MTRSetupPayloadInitializationTests.m @@ -13,20 +13,25 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -// module headers -#import "MTRSetupPayload.h" -// additional includes -#import "MTRError.h" - -// system dependencies +#import #import -@interface MTRSetupPayloadSerializerTests : XCTestCase +@interface MTRSetupPayloadInitializationTests : XCTestCase @end -@implementation MTRSetupPayloadSerializerTests +@implementation MTRSetupPayloadInitializationTests + +- (BOOL)shouldRelaunchBeforeRunningTest +{ + // By having xctest restart the process before each test case we + // ensure that the relevant MTRSetupPayload code paths correctly + // call chip::Platform::MemoryInit(). + // Tests that are not specifically designed to test this should + // be added to MTRSetupPayloadTests to avoid this extra overhead. + return YES; +} - (void)testSetupPayloadBasicQRCodeSerialize { @@ -49,6 +54,4 @@ - (void)testSetupPayloadBasicQRCodeSerialize XCTAssertEqualObjects(qrCode, @"MT:-24J06.H14BK9C7R900"); } -// Make sure to not add any tests that involve parsing setup payloads to this -// file. Those should go in MTRSetupPayloadParserTests.m. @end diff --git a/src/darwin/Framework/CHIPTests/MTRSetupPayloadParserTests.m b/src/darwin/Framework/CHIPTests/MTRSetupPayloadTests.m similarity index 72% rename from src/darwin/Framework/CHIPTests/MTRSetupPayloadParserTests.m rename to src/darwin/Framework/CHIPTests/MTRSetupPayloadTests.m index 8da233967cab33..7060c3ba11599c 100644 --- a/src/darwin/Framework/CHIPTests/MTRSetupPayloadParserTests.m +++ b/src/darwin/Framework/CHIPTests/MTRSetupPayloadTests.m @@ -1,6 +1,3 @@ -// -// MTRSetupPayloadParserTests.m -// MTRQRCodeReaderTests /** * * Copyright (c) 2020 Project CHIP Authors @@ -17,20 +14,15 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -// module headers -#import "MTRSetupPayload.h" -// additional includes -#import "MTRError.h" - -// system dependencies +#import #import -@interface MTRSetupPayloadParserTests : XCTestCase +@interface MTRSetupPayloadTests : XCTestCase @end -@implementation MTRSetupPayloadParserTests +@implementation MTRSetupPayloadTests - (void)testOnboardingPayloadParser_Manual_NoError { @@ -275,4 +267,80 @@ - (void)testSerialNumberRoundTrip XCTAssertEqualObjects(newPayload.serialNumber, serialNumber); } +- (void)test31129 // https://github.com/project-chip/connectedhomeip/issues/31129 +{ + MTRSetupPayload * payload = [[MTRSetupPayload alloc] initWithSetupPasscode:@99999998 discriminator:@3840]; + XCTAssertNotNil(payload); + // The payload should be representable in at least one of manual or QR format. + XCTAssert(payload.manualEntryCode != nil || [payload qrCodeString:NULL] != nil); +} + +- (void)test23357 // https://github.com/project-chip/connectedhomeip/pull/23357 +{ + // Should return nil for invalid payloads (e.g. invalid passcode "@11111111") + XCTAssertNil([MTRSetupPayload setupPayloadWithOnboardingPayload:@"MT:-24J042C00KMSP0Z800" error:NULL]); + XCTAssertNil([MTRSetupPayload setupPayloadWithOnboardingPayload:@"35191106788" error:NULL]); +} + +- (void)testSecureCodingRoundtrip +{ + NSError * error; + NSMutableArray * payloads = [[NSMutableArray alloc] init]; + for (NSString * string in @[ + @"34970112332", + @"641286075300001000016", + @"MT:M5L90MP500K64J00000", + @"MT:M5L90MP500K64J0A33P0SET70.QT52B.E23-WZE0WISA0DK5N1K8SQ1RYCU1O0" + ]) { + MTRSetupPayload * payload = [MTRSetupPayload setupPayloadWithOnboardingPayload:string error:&error]; + XCTAssertNotNil(payload, @"Error: %@", error); + [payloads addObject:payload]; + } + + // Also test some other payloads that don't have a valid QR / MPC representation + [payloads addObject:[[MTRSetupPayload alloc] init]]; + [payloads addObject:[[MTRSetupPayload alloc] initWithSetupPasscode:@22222222 discriminator:@42]]; + + for (MTRSetupPayload * payload in payloads) { + NSData * data = [NSKeyedArchiver archivedDataWithRootObject:payload requiringSecureCoding:YES error:&error]; + XCTAssertNotNil(data, @"Error: %@", error); + MTRSetupPayload * decoded = [NSKeyedUnarchiver unarchivedObjectOfClass:MTRSetupPayload.class fromData:data error:&error]; + XCTAssertNotNil(decoded, @"Error: %@", error); + + XCTAssertEqualObjects(decoded.version, payload.version); + XCTAssertEqualObjects(decoded.vendorID, payload.vendorID); + XCTAssertEqualObjects(decoded.productID, payload.productID); + XCTAssertEqual(decoded.commissioningFlow, payload.commissioningFlow); + XCTAssertEqual(decoded.discoveryCapabilities, payload.discoveryCapabilities); + XCTAssertEqual(decoded.hasShortDiscriminator, payload.hasShortDiscriminator); + XCTAssertEqualObjects(decoded.discriminator, payload.discriminator); + XCTAssertEqualObjects(decoded.setupPasscode, payload.setupPasscode); + XCTAssertEqualObjects(decoded.serialNumber, payload.serialNumber); + + NSArray * payloadVDs = [payload getAllOptionalVendorData:&error]; + XCTAssertNotNil(payloadVDs, @"Error: %@", error); + NSArray * decodedVDs = [decoded getAllOptionalVendorData:&error]; + XCTAssertNotNil(decodedVDs, @"Error: %@", error); + +#if 0 // TODO: Encode / decode optional vendor data + // MTROptionalQRCodeInfo does not implement isEqual (yet) + XCTAssertEqual(decodedVDs.count, payloadVDs.count); + for (int i = 0; i < decodedVDs.count; i++){ + MTROptionalQRCodeInfo * decodedVD = decodedVDs[i]; + MTROptionalQRCodeInfo * payloadVD = payloadVDs[i]; + XCTAssertEqual(decodedVD.type, payloadVD.type); + XCTAssertEqualObjects(decodedVD.tag, payloadVD.tag); + XCTAssertEqualObjects(decodedVD.integerValue, payloadVD.integerValue); + XCTAssertEqualObjects(decodedVD.stringValue, payloadVD.stringValue); + } +#endif + + // Note that we can't necessarily expect the manualEntryCode and qrCode strings + // we generate here to match the original string, but we should get the same + // output from the decoded and original objects. + XCTAssertEqualObjects([decoded qrCodeString:NULL], [payload qrCodeString:NULL]); + XCTAssertEqualObjects(decoded.manualEntryCode, payload.manualEntryCode); + } +} + @end diff --git a/src/darwin/Framework/Matter.xcodeproj/project.pbxproj b/src/darwin/Framework/Matter.xcodeproj/project.pbxproj index 78ff18793ebd5c..03b0b105f30feb 100644 --- a/src/darwin/Framework/Matter.xcodeproj/project.pbxproj +++ b/src/darwin/Framework/Matter.xcodeproj/project.pbxproj @@ -108,6 +108,7 @@ 3CF134AF289D90FF0017A19E /* MTROperationalCertificateIssuer.h in Headers */ = {isa = PBXBuildFile; fileRef = 3CF134AE289D90FF0017A19E /* MTROperationalCertificateIssuer.h */; settings = {ATTRIBUTES = (Public, ); }; }; 3D0C484B29DA4FA0006D811F /* MTRErrorTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 3D0C484A29DA4FA0006D811F /* MTRErrorTests.m */; }; 3D3928D72BBCEA3D00CDEBB2 /* MTRAvailabilityTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 3D3928D62BBCEA3D00CDEBB2 /* MTRAvailabilityTests.m */; settings = {COMPILER_FLAGS = "-UMTR_NO_AVAILABILITY -Wno-unguarded-availability-new"; }; }; + 3D4733AF2BDF1B80003DC19B /* MTRSetupPayloadTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 3D4733AE2BDF1B80003DC19B /* MTRSetupPayloadTests.m */; }; 3D69868529383096007314E7 /* com.csa.matter.plist in Copy Logging Preferences */ = {isa = PBXBuildFile; fileRef = 3D69868029382EF4007314E7 /* com.csa.matter.plist */; }; 3D843711294977000070D20A /* NSStringSpanConversion.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D84370E294977000070D20A /* NSStringSpanConversion.h */; }; 3D843712294977000070D20A /* MTRCallbackBridgeBase.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D84370F294977000070D20A /* MTRCallbackBridgeBase.h */; }; @@ -193,7 +194,7 @@ 517BF3F3282B62CB00A8B7DB /* MTRCertificateTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 517BF3F2282B62CB00A8B7DB /* MTRCertificateTests.m */; }; 518D3F832AA132DC008E0007 /* MTRTestPerControllerStorage.m in Sources */ = {isa = PBXBuildFile; fileRef = 518D3F812AA132DC008E0007 /* MTRTestPerControllerStorage.m */; }; 518D3F852AA14006008E0007 /* MTRControllerAdvertisingTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 518D3F842AA14006008E0007 /* MTRControllerAdvertisingTests.m */; }; - 519498322A25581C00B3BABE /* MTRSetupPayloadSerializerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 519498312A25581C00B3BABE /* MTRSetupPayloadSerializerTests.m */; }; + 519498322A25581C00B3BABE /* MTRSetupPayloadInitializationTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 519498312A25581C00B3BABE /* MTRSetupPayloadInitializationTests.m */; }; 51A2F1322A00402A00F03298 /* MTRDataValueParserTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 51A2F1312A00402A00F03298 /* MTRDataValueParserTests.m */; }; 51B22C1E2740CB0A008D5055 /* MTRStructsObjc.h in Headers */ = {isa = PBXBuildFile; fileRef = 51B22C1D2740CB0A008D5055 /* MTRStructsObjc.h */; settings = {ATTRIBUTES = (Public, ); }; }; 51B22C222740CB1D008D5055 /* MTRCommandPayloadsObjc.h in Headers */ = {isa = PBXBuildFile; fileRef = 51B22C212740CB1D008D5055 /* MTRCommandPayloadsObjc.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -309,7 +310,6 @@ B2E0D7B7245B0B5C003C5B48 /* MTRQRCodeSetupPayloadParser.mm in Sources */ = {isa = PBXBuildFile; fileRef = B2E0D7AE245B0B5C003C5B48 /* MTRQRCodeSetupPayloadParser.mm */; }; B2E0D7B8245B0B5C003C5B48 /* MTRSetupPayload.h in Headers */ = {isa = PBXBuildFile; fileRef = B2E0D7AF245B0B5C003C5B48 /* MTRSetupPayload.h */; settings = {ATTRIBUTES = (Public, ); }; }; B2E0D7B9245B0B5C003C5B48 /* MTRSetupPayload.mm in Sources */ = {isa = PBXBuildFile; fileRef = B2E0D7B0245B0B5C003C5B48 /* MTRSetupPayload.mm */; }; - B2F53AF2245B0DCF0010745E /* MTRSetupPayloadParserTests.m in Sources */ = {isa = PBXBuildFile; fileRef = B2F53AF1245B0DCF0010745E /* MTRSetupPayloadParserTests.m */; }; B45373AA2A9FE73400807602 /* WebSocketServer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B45373A92A9FE73400807602 /* WebSocketServer.cpp */; }; B45373BD2A9FEA9100807602 /* service.c in Sources */ = {isa = PBXBuildFile; fileRef = B45373B22A9FEA9000807602 /* service.c */; settings = {COMPILER_FLAGS = "-Wno-error -Wno-unreachable-code -Wno-conversion -Wno-format-nonliteral"; }; }; B45373BE2A9FEA9100807602 /* network.c in Sources */ = {isa = PBXBuildFile; fileRef = B45373B32A9FEA9000807602 /* network.c */; settings = {COMPILER_FLAGS = "-Wno-error -Wno-unreachable-code -Wno-conversion -Wno-format-nonliteral"; }; }; @@ -498,6 +498,7 @@ 3CF134AE289D90FF0017A19E /* MTROperationalCertificateIssuer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MTROperationalCertificateIssuer.h; sourceTree = ""; }; 3D0C484A29DA4FA0006D811F /* MTRErrorTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MTRErrorTests.m; sourceTree = ""; }; 3D3928D62BBCEA3D00CDEBB2 /* MTRAvailabilityTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MTRAvailabilityTests.m; sourceTree = ""; }; + 3D4733AE2BDF1B80003DC19B /* MTRSetupPayloadTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MTRSetupPayloadTests.m; sourceTree = ""; }; 3D69868029382EF4007314E7 /* com.csa.matter.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = com.csa.matter.plist; sourceTree = ""; }; 3D84370E294977000070D20A /* NSStringSpanConversion.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NSStringSpanConversion.h; sourceTree = ""; }; 3D84370F294977000070D20A /* MTRCallbackBridgeBase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MTRCallbackBridgeBase.h; sourceTree = ""; }; @@ -601,7 +602,7 @@ 518D3F812AA132DC008E0007 /* MTRTestPerControllerStorage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MTRTestPerControllerStorage.m; sourceTree = ""; }; 518D3F822AA132DC008E0007 /* MTRTestPerControllerStorage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MTRTestPerControllerStorage.h; sourceTree = ""; }; 518D3F842AA14006008E0007 /* MTRControllerAdvertisingTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MTRControllerAdvertisingTests.m; sourceTree = ""; }; - 519498312A25581C00B3BABE /* MTRSetupPayloadSerializerTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MTRSetupPayloadSerializerTests.m; sourceTree = ""; }; + 519498312A25581C00B3BABE /* MTRSetupPayloadInitializationTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MTRSetupPayloadInitializationTests.m; sourceTree = ""; }; 51A2F1312A00402A00F03298 /* MTRDataValueParserTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MTRDataValueParserTests.m; sourceTree = ""; }; 51B22C1D2740CB0A008D5055 /* MTRStructsObjc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MTRStructsObjc.h; sourceTree = ""; }; 51B22C212740CB1D008D5055 /* MTRCommandPayloadsObjc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MTRCommandPayloadsObjc.h; sourceTree = ""; }; @@ -725,7 +726,6 @@ B2E0D7AE245B0B5C003C5B48 /* MTRQRCodeSetupPayloadParser.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MTRQRCodeSetupPayloadParser.mm; sourceTree = ""; }; B2E0D7AF245B0B5C003C5B48 /* MTRSetupPayload.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MTRSetupPayload.h; sourceTree = ""; }; B2E0D7B0245B0B5C003C5B48 /* MTRSetupPayload.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MTRSetupPayload.mm; sourceTree = ""; }; - B2F53AF1245B0DCF0010745E /* MTRSetupPayloadParserTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MTRSetupPayloadParserTests.m; sourceTree = ""; }; B45373A92A9FE73400807602 /* WebSocketServer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WebSocketServer.cpp; sourceTree = ""; }; B45373B22A9FEA9000807602 /* service.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = service.c; path = "repo/lib/core-net/service.c"; sourceTree = ""; }; B45373B32A9FEA9000807602 /* network.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = network.c; path = "repo/lib/core-net/network.c"; sourceTree = ""; }; @@ -1390,8 +1390,8 @@ 51742B4D29CB6B88009974FE /* MTRPairingTests.m */, 51E95DF72A78110900A434F0 /* MTRPerControllerStorageTests.m */, 51D0B1292B61766F006E3511 /* MTRServerEndpointTests.m */, - B2F53AF1245B0DCF0010745E /* MTRSetupPayloadParserTests.m */, - 519498312A25581C00B3BABE /* MTRSetupPayloadSerializerTests.m */, + 3D4733AE2BDF1B80003DC19B /* MTRSetupPayloadTests.m */, + 519498312A25581C00B3BABE /* MTRSetupPayloadInitializationTests.m */, 51E0FC0F2ACBBF230001E197 /* MTRSwiftDeviceTests.swift */, 5143851D2A65885500EDC8E6 /* MTRSwiftPairingTests.swift */, 997DED1926955D0200975E97 /* MTRThreadOperationalDatasetTests.mm */, @@ -2000,13 +2000,13 @@ 5AE6D4E427A99041001F2493 /* MTRDeviceTests.m in Sources */, 510CECA8297F72970064E0B3 /* MTROperationalCertificateIssuerTests.m in Sources */, 5A7947DE27BEC3F500434CF2 /* MTRXPCListenerSampleTests.m in Sources */, - B2F53AF2245B0DCF0010745E /* MTRSetupPayloadParserTests.m in Sources */, 3DFCB3292966684500332B35 /* MTRCertificateInfoTests.m in Sources */, 517BF3F3282B62CB00A8B7DB /* MTRCertificateTests.m in Sources */, 5142E39829D377F000A206F0 /* MTROTAProviderTests.m in Sources */, 51E0FC102ACBBF230001E197 /* MTRSwiftDeviceTests.swift in Sources */, + 3D4733AF2BDF1B80003DC19B /* MTRSetupPayloadTests.m in Sources */, 51E24E73274E0DAC007CCF6E /* MTRErrorTestUtils.mm in Sources */, - 519498322A25581C00B3BABE /* MTRSetupPayloadSerializerTests.m in Sources */, + 519498322A25581C00B3BABE /* MTRSetupPayloadInitializationTests.m in Sources */, 51A2F1322A00402A00F03298 /* MTRDataValueParserTests.m in Sources */, 51E95DF82A78110900A434F0 /* MTRPerControllerStorageTests.m in Sources */, 51D9CB0B2BA37DCE0049D6DB /* MTRDSTOffsetTests.m in Sources */, From 3c9f101f793a4ff81b6f32424686a33fe08977af Mon Sep 17 00:00:00 2001 From: Pradip De Date: Tue, 30 Apr 2024 01:51:50 +0000 Subject: [PATCH 04/33] Disable TCP on the MCU based platforms by default. (#33232) Some of the MCU based platforms had TCP enabled on them without having to use it. Disabling the flag before landing the TCP PR #30339 to avoid increase in code size. We can assess the need to enable TCP on these platforms later. --- config/ameba/args.gni | 2 +- config/beken/args.gni | 2 +- config/esp32/args.gni | 2 +- config/genio/args.gni | 2 +- config/mbed/chip-gn/args.gni | 2 +- examples/lighting-app/beken/args.gni | 2 +- src/platform/ASR/args.gni | 2 +- src/platform/Ameba/args.gni | 2 +- src/platform/Beken/args.gni | 2 +- src/platform/bouffalolab/BL602/args.gni | 2 +- 10 files changed, 10 insertions(+), 10 deletions(-) diff --git a/config/ameba/args.gni b/config/ameba/args.gni index a60eee6db2887c..3be47a85291024 100755 --- a/config/ameba/args.gni +++ b/config/ameba/args.gni @@ -28,7 +28,7 @@ lwip_platform = "external" chip_build_tests = false -chip_inet_config_enable_tcp_endpoint = true +chip_inet_config_enable_tcp_endpoint = false chip_inet_config_enable_udp_endpoint = true chip_config_network_layer_ble = true diff --git a/config/beken/args.gni b/config/beken/args.gni index d9bbba606df7ba..018c3e99ad22bc 100755 --- a/config/beken/args.gni +++ b/config/beken/args.gni @@ -26,7 +26,7 @@ lwip_platform = "external" chip_build_tests = false -chip_inet_config_enable_tcp_endpoint = true +chip_inet_config_enable_tcp_endpoint = false chip_inet_config_enable_udp_endpoint = true chip_config_network_layer_ble = true diff --git a/config/esp32/args.gni b/config/esp32/args.gni index c8de67ddc87506..f818a37f258e49 100644 --- a/config/esp32/args.gni +++ b/config/esp32/args.gni @@ -26,7 +26,7 @@ lwip_platform = "external" #Enabling this causes some error #chip_inet_config_enable_tun_endpoint = false -chip_inet_config_enable_tcp_endpoint = true +chip_inet_config_enable_tcp_endpoint = false chip_inet_config_enable_udp_endpoint = true custom_toolchain = "//third_party/connectedhomeip/config/esp32/toolchain:esp32" diff --git a/config/genio/args.gni b/config/genio/args.gni index 50d0a514c10616..c2012d61d0905a 100644 --- a/config/genio/args.gni +++ b/config/genio/args.gni @@ -24,7 +24,7 @@ lwip_platform = "external" chip_build_tests = true -chip_inet_config_enable_tcp_endpoint = true +chip_inet_config_enable_tcp_endpoint = false chip_inet_config_enable_udp_endpoint = true custom_toolchain = "//third_party/connectedhomeip/config/genio/toolchain:genio" diff --git a/config/mbed/chip-gn/args.gni b/config/mbed/chip-gn/args.gni index 83753bc7ca8012..804e9efaea74f6 100644 --- a/config/mbed/chip-gn/args.gni +++ b/config/mbed/chip-gn/args.gni @@ -21,7 +21,7 @@ chip_system_project_config_include = "" chip_device_project_config_include = "" chip_inet_config_enable_udp_endpoint = true -chip_inet_config_enable_tcp_endpoint = true +chip_inet_config_enable_tcp_endpoint = false custom_toolchain = "${chip_root}/config/mbed/chip-gn/toolchain:mbed" mbedtls_target = "${chip_root}/config/mbed/chip-gn/mbedtls:mbedtls" diff --git a/examples/lighting-app/beken/args.gni b/examples/lighting-app/beken/args.gni index 79a52c9890eaca..a999e3ed08f897 100755 --- a/examples/lighting-app/beken/args.gni +++ b/examples/lighting-app/beken/args.gni @@ -29,7 +29,7 @@ lwip_platform = "external" chip_build_tests = false -chip_inet_config_enable_tcp_endpoint = true +chip_inet_config_enable_tcp_endpoint = false chip_inet_config_enable_udp_endpoint = true chip_config_network_layer_ble = true diff --git a/src/platform/ASR/args.gni b/src/platform/ASR/args.gni index 4301315205975a..246fed39f99bb4 100755 --- a/src/platform/ASR/args.gni +++ b/src/platform/ASR/args.gni @@ -25,5 +25,5 @@ lwip_platform = "asr" chip_build_tests = false chip_inet_config_enable_ipv4 = true -chip_inet_config_enable_tcp_endpoint = true +chip_inet_config_enable_tcp_endpoint = false chip_inet_config_enable_udp_endpoint = true diff --git a/src/platform/Ameba/args.gni b/src/platform/Ameba/args.gni index dd6b1bcdb9ca8f..bcda3812b8d781 100755 --- a/src/platform/Ameba/args.gni +++ b/src/platform/Ameba/args.gni @@ -21,5 +21,5 @@ mbedtls_target = "//mbedtls:mbedtls" chip_build_tests = false chip_inet_config_enable_tun_endpoint = false -chip_inet_config_enable_tcp_endpoint = true +chip_inet_config_enable_tcp_endpoint = false chip_inet_config_enable_udp_endpoint = true diff --git a/src/platform/Beken/args.gni b/src/platform/Beken/args.gni index fbc11f681de7aa..6556eaf714d692 100755 --- a/src/platform/Beken/args.gni +++ b/src/platform/Beken/args.gni @@ -21,5 +21,5 @@ mbedtls_target = "//mbedtls:mbedtls" chip_build_tests = false chip_inet_config_enable_tun_endpoint = false -chip_inet_config_enable_tcp_endpoint = true +chip_inet_config_enable_tcp_endpoint = false chip_inet_config_enable_udp_endpoint = true diff --git a/src/platform/bouffalolab/BL602/args.gni b/src/platform/bouffalolab/BL602/args.gni index fbabcea74083b7..7ceb33e9ed68ca 100644 --- a/src/platform/bouffalolab/BL602/args.gni +++ b/src/platform/bouffalolab/BL602/args.gni @@ -29,5 +29,5 @@ lwip_platform = "bl602" chip_build_tests = false chip_inet_config_enable_dns_resolver = false chip_inet_config_enable_tun_endpoint = false -chip_inet_config_enable_tcp_endpoint = true +chip_inet_config_enable_tcp_endpoint = false chip_inet_config_enable_udp_endpoint = true From aec50d4084c97c193074b5a62cc3d3db37f94c15 Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Mon, 29 Apr 2024 22:00:37 -0400 Subject: [PATCH 05/33] Stop talking about "pairing" in logs. (#33233) "Pairing" means "PASE establishment" sometimes, "commissioning" sometimes. We should not use the term, and just be clearer about which process we mean so people reading logs don't get confused. --- src/controller/SetUpCodePairer.cpp | 2 +- .../Framework/CHIP/MTRDeviceControllerDelegateBridge.mm | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/controller/SetUpCodePairer.cpp b/src/controller/SetUpCodePairer.cpp index cf7ba2abd43d89..4eb107a3711c10 100644 --- a/src/controller/SetUpCodePairer.cpp +++ b/src/controller/SetUpCodePairer.cpp @@ -533,7 +533,7 @@ void SetUpCodePairer::OnPairingComplete(CHIP_ERROR error) if (CHIP_NO_ERROR == error) { - ChipLogProgress(Controller, "Pairing with commissionee successful, stopping discovery"); + ChipLogProgress(Controller, "PASE session established with commissionee. Stopping discovery."); ResetDiscoveryState(); mRemoteId = kUndefinedNodeId; if (pairingDelegate != nullptr) diff --git a/src/darwin/Framework/CHIP/MTRDeviceControllerDelegateBridge.mm b/src/darwin/Framework/CHIP/MTRDeviceControllerDelegateBridge.mm index b90921e1924275..4c50f7fd2a7fa4 100644 --- a/src/darwin/Framework/CHIP/MTRDeviceControllerDelegateBridge.mm +++ b/src/darwin/Framework/CHIP/MTRDeviceControllerDelegateBridge.mm @@ -93,7 +93,11 @@ void MTRDeviceControllerDelegateBridge::OnPairingComplete(CHIP_ERROR error) { - MTR_LOG_DEFAULT("DeviceControllerDelegate Pairing complete. Status %s", chip::ErrorStr(error)); + if (error == CHIP_NO_ERROR) { + MTR_LOG_DEFAULT("MTRDeviceControllerDelegate PASE session establishment succeeded."); + } else { + MTR_LOG_ERROR("MTRDeviceControllerDelegate PASE session establishment failed: %" CHIP_ERROR_FORMAT, error.Format()); + } MATTER_LOG_METRIC_END(kMetricSetupPASESession, error); id strongDelegate = mDelegate; From ffaeaa1827813a1284ff20f9b34898314303df30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damian=20Kr=C3=B3lik?= <66667989+Damian-Nordic@users.noreply.github.com> Date: Tue, 30 Apr 2024 08:59:22 +0200 Subject: [PATCH 06/33] [mrp] Make GetBackoff() use Timeout instead of Timestamp type (#33093) * [mrp] Make GetBackoff() use Timeout instead of Timestamp type All users of ReliableMessageMgr::GetBackoff() seem to assume it takes and returns 32-bit Timeout while it actually takes and returns 64-bit Timestamp. Hence all the users do implicit casts. Replace Timestamp with Timeout in the function's signature and only use 64-bit type for internal calculations to prevent overflowing the underlying integer type. * Restyled by clang-format * Code review --------- Co-authored-by: Restyled.io --- src/messaging/ReliableMessageMgr.cpp | 26 +-- src/messaging/ReliableMessageMgr.h | 4 +- .../ReliableMessageProtocolConfig.cpp | 5 +- src/messaging/ReliableMessageProtocolConfig.h | 5 +- .../tests/TestReliableMessageProtocol.cpp | 177 +++++++++--------- 5 files changed, 111 insertions(+), 106 deletions(-) diff --git a/src/messaging/ReliableMessageMgr.cpp b/src/messaging/ReliableMessageMgr.cpp index 53e292c9b32b00..3827fd096d5072 100644 --- a/src/messaging/ReliableMessageMgr.cpp +++ b/src/messaging/ReliableMessageMgr.cpp @@ -213,8 +213,8 @@ CHIP_ERROR ReliableMessageMgr::AddToRetransTable(ReliableMessageContext * rc, Re return CHIP_NO_ERROR; } -System::Clock::Timestamp ReliableMessageMgr::GetBackoff(System::Clock::Timestamp baseInterval, uint8_t sendCount, - bool computeMaxPossible) +System::Clock::Timeout ReliableMessageMgr::GetBackoff(System::Clock::Timeout baseInterval, uint8_t sendCount, + bool computeMaxPossible) { // See section "4.11.8. Parameters and Constants" for the parameters below: // MRP_BACKOFF_JITTER = 0.25 @@ -227,14 +227,16 @@ System::Clock::Timestamp ReliableMessageMgr::GetBackoff(System::Clock::Timestamp constexpr uint32_t MRP_BACKOFF_BASE_DENOMINATOR = 10; constexpr int MRP_BACKOFF_THRESHOLD = 1; - // Implement `i = MRP_BACKOFF_MARGIN * i` from section "4.11.2.1. Retransmissions", where: - // i == baseInterval - baseInterval = baseInterval * MRP_BACKOFF_MARGIN_NUMERATOR / MRP_BACKOFF_MARGIN_DENOMINATOR; + // Implement `i = MRP_BACKOFF_MARGIN * i` from section "4.12.2.1. Retransmissions", where: + // i == interval + System::Clock::Milliseconds64 interval = baseInterval; + interval *= MRP_BACKOFF_MARGIN_NUMERATOR; + interval /= MRP_BACKOFF_MARGIN_DENOMINATOR; // Implement: // mrpBackoffTime = i * MRP_BACKOFF_BASE^(max(0,n-MRP_BACKOFF_THRESHOLD)) * (1.0 + random(0,1) * MRP_BACKOFF_JITTER) - // from section "4.11.2.1. Retransmissions", where: - // i == baseInterval + // from section "4.12.2.1. Retransmissions", where: + // i == interval // n == sendCount // 1. Calculate exponent `max(0,n−MRP_BACKOFF_THRESHOLD)` @@ -254,7 +256,7 @@ System::Clock::Timestamp ReliableMessageMgr::GetBackoff(System::Clock::Timestamp backoffDenom *= MRP_BACKOFF_BASE_DENOMINATOR; } - System::Clock::Timestamp mrpBackoffTime = baseInterval * backoffNum / backoffDenom; + System::Clock::Milliseconds64 mrpBackoffTime = interval * backoffNum / backoffDenom; // 3. Calculate `mrpBackoffTime *= (1.0 + random(0,1) * MRP_BACKOFF_JITTER)` uint32_t jitter = MRP_BACKOFF_JITTER_BASE + (computeMaxPossible ? UINT8_MAX : Crypto::GetRandU8()); @@ -273,7 +275,7 @@ System::Clock::Timestamp ReliableMessageMgr::GetBackoff(System::Clock::Timestamp mrpBackoffTime += CHIP_CONFIG_MRP_RETRY_INTERVAL_SENDER_BOOST; #endif // CHIP_DEVICE_CONFIG_ENABLE_DYNAMIC_MRP_CONFIG - return mrpBackoffTime; + return std::chrono::duration_cast(mrpBackoffTime); } void ReliableMessageMgr::StartRetransmision(RetransTableEntry * entry) @@ -463,7 +465,7 @@ CHIP_ERROR ReliableMessageMgr::MapSendError(CHIP_ERROR error, uint16_t exchangeI void ReliableMessageMgr::CalculateNextRetransTime(RetransTableEntry & entry) { - System::Clock::Timestamp baseTimeout = System::Clock::Milliseconds64(0); + System::Clock::Timeout baseTimeout = System::Clock::Timeout(0); // Check if we have received at least one application-level message if (entry.ec->HasReceivedAtLeastOneMessage()) @@ -478,8 +480,8 @@ void ReliableMessageMgr::CalculateNextRetransTime(RetransTableEntry & entry) baseTimeout = entry.ec->GetSessionHandle()->GetMRPBaseTimeout(); } - System::Clock::Timestamp backoff = ReliableMessageMgr::GetBackoff(baseTimeout, entry.sendCount); - entry.nextRetransTime = System::SystemClock().GetMonotonicTimestamp() + backoff; + System::Clock::Timeout backoff = ReliableMessageMgr::GetBackoff(baseTimeout, entry.sendCount); + entry.nextRetransTime = System::SystemClock().GetMonotonicTimestamp() + backoff; } #if CHIP_CONFIG_TEST diff --git a/src/messaging/ReliableMessageMgr.h b/src/messaging/ReliableMessageMgr.h index ae953cbddd5ad5..953de1db0aea40 100644 --- a/src/messaging/ReliableMessageMgr.h +++ b/src/messaging/ReliableMessageMgr.h @@ -112,8 +112,8 @@ class ReliableMessageMgr * * @retval The backoff time value, including jitter. */ - static System::Clock::Timestamp GetBackoff(System::Clock::Timestamp baseInterval, uint8_t sendCount, - bool computeMaxPossible = false); + static System::Clock::Timeout GetBackoff(System::Clock::Timeout baseInterval, uint8_t sendCount, + bool computeMaxPossible = false); /** * Start retranmisttion of cached encryped packet for current entry. diff --git a/src/messaging/ReliableMessageProtocolConfig.cpp b/src/messaging/ReliableMessageProtocolConfig.cpp index e635e91940e0ef..352e89cf4576c1 100644 --- a/src/messaging/ReliableMessageProtocolConfig.cpp +++ b/src/messaging/ReliableMessageProtocolConfig.cpp @@ -125,9 +125,8 @@ Optional GetLocalMRPConfig() : Optional::Value(config); } -System::Clock::Timestamp GetRetransmissionTimeout(System::Clock::Timestamp activeInterval, System::Clock::Timestamp idleInterval, - System::Clock::Timestamp lastActivityTime, - System::Clock::Timestamp activityThreshold) +System::Clock::Timeout GetRetransmissionTimeout(System::Clock::Timeout activeInterval, System::Clock::Timeout idleInterval, + System::Clock::Timeout lastActivityTime, System::Clock::Timeout activityThreshold) { auto timeSinceLastActivity = (System::SystemClock().GetMonotonicTimestamp() - lastActivityTime); diff --git a/src/messaging/ReliableMessageProtocolConfig.h b/src/messaging/ReliableMessageProtocolConfig.h index 2ab1c139657fc6..e3255a780b7b70 100644 --- a/src/messaging/ReliableMessageProtocolConfig.h +++ b/src/messaging/ReliableMessageProtocolConfig.h @@ -257,9 +257,8 @@ Optional GetLocalMRPConfig(); * * @return The maximum transmission time */ -System::Clock::Timestamp GetRetransmissionTimeout(System::Clock::Timestamp activeInterval, System::Clock::Timestamp idleInterval, - System::Clock::Timestamp lastActivityTime, - System::Clock::Timestamp activityThreshold); +System::Clock::Timeout GetRetransmissionTimeout(System::Clock::Timeout activeInterval, System::Clock::Timeout idleInterval, + System::Clock::Timeout lastActivityTime, System::Clock::Timeout activityThreshold); #if CONFIG_BUILD_FOR_HOST_UNIT_TEST diff --git a/src/messaging/tests/TestReliableMessageProtocol.cpp b/src/messaging/tests/TestReliableMessageProtocol.cpp index 7233e45fd846b5..4636193bb06378 100644 --- a/src/messaging/tests/TestReliableMessageProtocol.cpp +++ b/src/messaging/tests/TestReliableMessageProtocol.cpp @@ -232,92 +232,97 @@ struct BackoffComplianceTestVector System::Clock::Timeout backoffMax; }; -struct BackoffComplianceTestVector theBackoffComplianceTestVector[] = { - { - .sendCount = 0, - .backoffBase = System::Clock::Timeout(300), - .backoffMin = System::Clock::Timeout(330), - .backoffMax = System::Clock::Timeout(413), - }, - { - .sendCount = 1, - .backoffBase = System::Clock::Timeout(300), - .backoffMin = System::Clock::Timeout(330), - .backoffMax = System::Clock::Timeout(413), - }, - { - .sendCount = 2, - .backoffBase = System::Clock::Timeout(300), - .backoffMin = System::Clock::Timeout(528), - .backoffMax = System::Clock::Timeout(660), - }, - { - .sendCount = 3, - .backoffBase = System::Clock::Timeout(300), - .backoffMin = System::Clock::Timeout(844), - .backoffMax = System::Clock::Timeout(1057), - }, - { - .sendCount = 4, - .backoffBase = System::Clock::Timeout(300), - .backoffMin = System::Clock::Timeout(1351), - .backoffMax = System::Clock::Timeout(1690), - }, - { - .sendCount = 5, - .backoffBase = System::Clock::Timeout(300), - .backoffMin = System::Clock::Timeout(2162), - .backoffMax = System::Clock::Timeout(2704), - }, - { - .sendCount = 6, - .backoffBase = System::Clock::Timeout(300), - .backoffMin = System::Clock::Timeout(2162), - .backoffMax = System::Clock::Timeout(2704), - }, - { - .sendCount = 0, - .backoffBase = System::Clock::Timeout(4000), - .backoffMin = System::Clock::Timeout(4400), - .backoffMax = System::Clock::Timeout(5500), - }, - { - .sendCount = 1, - .backoffBase = System::Clock::Timeout(4000), - .backoffMin = System::Clock::Timeout(4400), - .backoffMax = System::Clock::Timeout(5500), - }, - { - .sendCount = 2, - .backoffBase = System::Clock::Timeout(4000), - .backoffMin = System::Clock::Timeout(7040), - .backoffMax = System::Clock::Timeout(8800), - }, - { - .sendCount = 3, - .backoffBase = System::Clock::Timeout(4000), - .backoffMin = System::Clock::Timeout(11264), - .backoffMax = System::Clock::Timeout(14081), - }, - { - .sendCount = 4, - .backoffBase = System::Clock::Timeout(4000), - .backoffMin = System::Clock::Timeout(18022), - .backoffMax = System::Clock::Timeout(22529), - }, - { - .sendCount = 5, - .backoffBase = System::Clock::Timeout(4000), - .backoffMin = System::Clock::Timeout(28835), - .backoffMax = System::Clock::Timeout(36045), - }, - { - .sendCount = 6, - .backoffBase = System::Clock::Timeout(4000), - .backoffMin = System::Clock::Timeout(28835), - .backoffMax = System::Clock::Timeout(36045), - }, -}; +struct BackoffComplianceTestVector theBackoffComplianceTestVector[] = { { + .sendCount = 0, + .backoffBase = System::Clock::Timeout(300), + .backoffMin = System::Clock::Timeout(330), + .backoffMax = System::Clock::Timeout(413), + }, + { + .sendCount = 1, + .backoffBase = System::Clock::Timeout(300), + .backoffMin = System::Clock::Timeout(330), + .backoffMax = System::Clock::Timeout(413), + }, + { + .sendCount = 2, + .backoffBase = System::Clock::Timeout(300), + .backoffMin = System::Clock::Timeout(528), + .backoffMax = System::Clock::Timeout(661), + }, + { + .sendCount = 3, + .backoffBase = System::Clock::Timeout(300), + .backoffMin = System::Clock::Timeout(844), + .backoffMax = System::Clock::Timeout(1057), + }, + { + .sendCount = 4, + .backoffBase = System::Clock::Timeout(300), + .backoffMin = System::Clock::Timeout(1351), + .backoffMax = System::Clock::Timeout(1691), + }, + { + .sendCount = 5, + .backoffBase = System::Clock::Timeout(300), + .backoffMin = System::Clock::Timeout(2162), + .backoffMax = System::Clock::Timeout(2705), + }, + { + .sendCount = 6, + .backoffBase = System::Clock::Timeout(300), + .backoffMin = System::Clock::Timeout(2162), + .backoffMax = System::Clock::Timeout(2705), + }, + { + .sendCount = 0, + .backoffBase = System::Clock::Timeout(4000), + .backoffMin = System::Clock::Timeout(4400), + .backoffMax = System::Clock::Timeout(5503), + }, + { + .sendCount = 1, + .backoffBase = System::Clock::Timeout(4000), + .backoffMin = System::Clock::Timeout(4400), + .backoffMax = System::Clock::Timeout(5503), + }, + { + .sendCount = 2, + .backoffBase = System::Clock::Timeout(4000), + .backoffMin = System::Clock::Timeout(7040), + .backoffMax = System::Clock::Timeout(8805), + }, + { + .sendCount = 3, + .backoffBase = System::Clock::Timeout(4000), + .backoffMin = System::Clock::Timeout(11264), + .backoffMax = System::Clock::Timeout(14088), + }, + { + .sendCount = 4, + .backoffBase = System::Clock::Timeout(4000), + .backoffMin = System::Clock::Timeout(18022), + .backoffMax = System::Clock::Timeout(22541), + }, + { + .sendCount = 5, + .backoffBase = System::Clock::Timeout(4000), + .backoffMin = System::Clock::Timeout(28835), + .backoffMax = System::Clock::Timeout(36065), + }, + { + .sendCount = 6, + .backoffBase = System::Clock::Timeout(4000), + .backoffMin = System::Clock::Timeout(28835), + .backoffMax = System::Clock::Timeout(36065), + }, + { + // test theoretical worst-case 1-hour interval + .sendCount = 4, + .backoffBase = System::Clock::Timeout(3'600'000), + .backoffMin = System::Clock::Timeout(16'220'160), + .backoffMax = System::Clock::Timeout(20'286'001), + } }; } // namespace From 416f6a315f286a242e78048039b6525cafaabd74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arkadiusz=20Ba=C5=82ys?= Date: Tue, 30 Apr 2024 15:06:04 +0200 Subject: [PATCH 07/33] [OpenThread] Disable IPv6 interface during erasing persistent info. (#33170) Apart from disabling Thread, and erasing Persistent Info, we should disable the IPv6 interface as well and block receiving further packets. Otherwise, if we don't reboot the device after erasing Thread persistent data, we can get a packet and as a result, it causes an assert during processing AES_ECB (because crypto keys have been removed). --- .../OpenThread/GenericThreadStackManagerImpl_OpenThread.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/platform/OpenThread/GenericThreadStackManagerImpl_OpenThread.hpp b/src/platform/OpenThread/GenericThreadStackManagerImpl_OpenThread.hpp index f62b82b4f2d112..1c14aeb91dd21d 100644 --- a/src/platform/OpenThread/GenericThreadStackManagerImpl_OpenThread.hpp +++ b/src/platform/OpenThread/GenericThreadStackManagerImpl_OpenThread.hpp @@ -1219,6 +1219,7 @@ void GenericThreadStackManagerImpl_OpenThread::_ErasePersistentInfo(v ChipLogProgress(DeviceLayer, "Erasing Thread persistent info..."); Impl()->LockThreadStack(); otThreadSetEnabled(mOTInst, false); + otIp6SetEnabled(mOTInst, false); otInstanceErasePersistentInfo(mOTInst); Impl()->UnlockThreadStack(); } From 80c19cd805cd8aa5c6e5b2ebccd164fa245a084b Mon Sep 17 00:00:00 2001 From: ying-css <71699179+ying-css@users.noreply.github.com> Date: Tue, 30 Apr 2024 23:05:05 +0800 Subject: [PATCH 08/33] Updated guide for Infineon Trust M provisioning (#33132) * 1)Updated guide for Infineon Trust M provisioning * Update docs/guides/infineon_trustm_provisioning.md Co-authored-by: Andrei Litvin * Restyled by prettier-markdown --------- Co-authored-by: Andrei Litvin Co-authored-by: Restyled.io --- .github/.wordlist.txt | 1 + docs/guides/infineon_trustm_provisioning.md | 20 +++++++++++++------- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/.github/.wordlist.txt b/.github/.wordlist.txt index f62685f566c407..33889f519989be 100644 --- a/.github/.wordlist.txt +++ b/.github/.wordlist.txt @@ -905,6 +905,7 @@ MoveWithOnOff MPSL MRP MTD +MTR MTU Multiband Multicast diff --git a/docs/guides/infineon_trustm_provisioning.md b/docs/guides/infineon_trustm_provisioning.md index 1493d75e4a2165..a514c04adcfee8 100644 --- a/docs/guides/infineon_trustm_provisioning.md +++ b/docs/guides/infineon_trustm_provisioning.md @@ -30,7 +30,9 @@ can be used to perform provisioning by following the steps mentioned below. ``` $ cd linux-optiga-trust-m/ - $ ./trustm_installation_aarch64_script.sh + $ git checkout provider_dev + $ git submodule update -f + $ ./provider_installation_script.sh ``` - Run the script to generate Matter test DAC for lock-app using the public key @@ -39,13 +41,13 @@ can be used to perform provisioning by following the steps mentioned below. ``` $ cd scripts/matter_provisioning/ -$ ./matter_dac_provisioning.sh +$ ./matter_test_provisioning.sh ``` _Note:_ -_By running this example matter_dac_provisioning.sh, the steps shown below are -executed:_ +_By running this example `matter_test_provisioning.sh`, the steps shown below +are executed:_ _Step1: Extract the public key from the Infineon pre-provisioned Certificate(0xE0E0) using openssl command._ @@ -55,7 +57,11 @@ _Step2: Generate DAC test certificate using the extracted public key, Signed by Please note that production devices cannot re-use these test keys/certificates. _Step3: Write DAC test certificate into OPTIGA™ Trust M certificate slot -0xE0E0_ +0xE0E0._ -\_Step4: Write Matter test PAI into OPTIGA™ Trust M certificate slot -0xE0E8 and test CD into OPTIGA™ Trust M Arbitrary OID 0xF1E0. +_Step4: Write Matter test PAI into OPTIGA™ Trust M certificate slot 0xE0E8 +and test CD into OPTIGA™ Trust M Arbitrary OID 0xF1E0._ + +For certificate claim and OPTIGA™ Trust M MTR provisioning, please refer +to our +[README for Late-stage Provisioning](https://github.com/Infineon/linux-optiga-trust-m/blob/provider_dev/scripts/matter_provisioning/README.md#certificate-claiming) From 7489e022c0c37d0c88bef732352565bf22266f44 Mon Sep 17 00:00:00 2001 From: feasel <120589145+feasel0@users.noreply.github.com> Date: Tue, 30 Apr 2024 11:08:42 -0400 Subject: [PATCH 09/33] Updated unit tests in src/transport/raw/tests/ to use PW instead of NL. (#33099) * Updated unit tests in src/transport/tests/ to use PW instead of NL. * Updated unit tests in src/protocols/bdx/tests/ to use PW instead of NL * Updated unit tests in src/transport/raw/tests/ to use PW instead of NL. * Undid the accidental reformatting of the comments at the top. * Update src/transport/raw/tests/TestTCP.cpp Co-authored-by: Arkadiusz Bokowy * Update src/transport/raw/tests/TestUDP.cpp Co-authored-by: Arkadiusz Bokowy * Changed some EXPECT_ to ASSERT_. Changed C-casts to unsigned literals. Chagned strcmp to EXPECT_STREQ. * Resolved merge conflicts in test_components[_nl].txt * Added a destructor to TestUDP to delete the TestContext. * Added destructor to TestTCP to delete the TestContext. * Added destructor to TestTCP to delete TestContext. * Fixed issue with SystemLayerTests being listed multiple times. * Changed MemoryInit line to ASSERT instead of EXPECT. Added corresponding MemoryShutdown. * Inherited TCP test from IOContext so we don't have to create a new context. * Moved ChckSimpleInitTest and CheckMessageTest into the test context class. --------- Co-authored-by: Arkadiusz Bokowy --- .../openiotsdk/unit-tests/test_components.txt | 1 + .../unit-tests/test_components_nl.txt | 1 - src/transport/raw/tests/BUILD.gn | 7 +- src/transport/raw/tests/TestMessageHeader.cpp | 300 ++++++++--------- src/transport/raw/tests/TestPeerAddress.cpp | 60 +--- src/transport/raw/tests/TestTCP.cpp | 307 +++++++----------- src/transport/raw/tests/TestUDP.cpp | 140 +++----- 7 files changed, 316 insertions(+), 500 deletions(-) diff --git a/src/test_driver/openiotsdk/unit-tests/test_components.txt b/src/test_driver/openiotsdk/unit-tests/test_components.txt index 2694c2a5afd8fb..e6e64c61106c9a 100644 --- a/src/test_driver/openiotsdk/unit-tests/test_components.txt +++ b/src/test_driver/openiotsdk/unit-tests/test_components.txt @@ -10,6 +10,7 @@ CoreTests MdnsTests CredentialsTest PlatformTests +RawTransportTests RetransmitTests TestShell SetupPayloadTests diff --git a/src/test_driver/openiotsdk/unit-tests/test_components_nl.txt b/src/test_driver/openiotsdk/unit-tests/test_components_nl.txt index d30358d4353c85..93c9c1389e0a5b 100644 --- a/src/test_driver/openiotsdk/unit-tests/test_components_nl.txt +++ b/src/test_driver/openiotsdk/unit-tests/test_components_nl.txt @@ -2,7 +2,6 @@ AppTests DataModelTests InetLayerTests MessagingLayerTests -RawTransportTests SecureChannelTestsNL SupportTestsNL TransportLayerTests diff --git a/src/transport/raw/tests/BUILD.gn b/src/transport/raw/tests/BUILD.gn index 8adcb9beb7eeee..c655586c5a0e35 100644 --- a/src/transport/raw/tests/BUILD.gn +++ b/src/transport/raw/tests/BUILD.gn @@ -14,10 +14,9 @@ import("//build_overrides/build.gni") import("//build_overrides/chip.gni") -import("//build_overrides/nlunit_test.gni") +import("//build_overrides/pigweed.gni") import("${chip_root}/build/chip/chip_test_suite.gni") - static_library("helpers") { output_name = "libNetworkTestHelpers" output_dir = "${root_out_dir}/lib" @@ -35,7 +34,7 @@ static_library("helpers") { ] } -chip_test_suite_using_nltest("tests") { +chip_test_suite("tests") { output_name = "libRawTransportTests" test_sources = [ @@ -51,10 +50,8 @@ chip_test_suite_using_nltest("tests") { "${chip_root}/src/lib/core", "${chip_root}/src/lib/support", "${chip_root}/src/lib/support:test_utils", - "${chip_root}/src/lib/support:testing_nlunit", "${chip_root}/src/transport", "${chip_root}/src/transport/raw", - "${nlunit_test_root}:nlunit-test", ] cflags = [ "-Wconversion" ] diff --git a/src/transport/raw/tests/TestMessageHeader.cpp b/src/transport/raw/tests/TestMessageHeader.cpp index 93b1ef65ad6389..436bb887f4616e 100644 --- a/src/transport/raw/tests/TestMessageHeader.cpp +++ b/src/transport/raw/tests/TestMessageHeader.cpp @@ -26,41 +26,40 @@ #include #include #include -#include #include #include -#include +#include namespace { using namespace chip; -void TestPacketHeaderInitialState(nlTestSuite * inSuite, void * inContext) +TEST(TestMessageHeader, TestPacketHeaderInitialState) { PacketHeader header; - NL_TEST_ASSERT(inSuite, !header.IsSecureSessionControlMsg()); - NL_TEST_ASSERT(inSuite, header.GetMessageCounter() == 0); - NL_TEST_ASSERT(inSuite, header.GetSessionId() == 0); - NL_TEST_ASSERT(inSuite, header.GetSessionType() == Header::SessionType::kUnicastSession); - NL_TEST_ASSERT(inSuite, header.IsSessionTypeValid()); - NL_TEST_ASSERT(inSuite, !header.IsEncrypted()); - NL_TEST_ASSERT(inSuite, !header.GetDestinationNodeId().HasValue()); - NL_TEST_ASSERT(inSuite, !header.GetDestinationGroupId().HasValue()); - NL_TEST_ASSERT(inSuite, !header.GetSourceNodeId().HasValue()); + EXPECT_FALSE(header.IsSecureSessionControlMsg()); + EXPECT_EQ(header.GetMessageCounter(), 0u); + EXPECT_EQ(header.GetSessionId(), 0); + EXPECT_EQ(header.GetSessionType(), Header::SessionType::kUnicastSession); + EXPECT_TRUE(header.IsSessionTypeValid()); + EXPECT_FALSE(header.IsEncrypted()); + EXPECT_FALSE(header.GetDestinationNodeId().HasValue()); + EXPECT_FALSE(header.GetDestinationGroupId().HasValue()); + EXPECT_FALSE(header.GetSourceNodeId().HasValue()); } -void TestPayloadHeaderInitialState(nlTestSuite * inSuite, void * inContext) +TEST(TestMessageHeader, TestPayloadHeaderInitialState) { PayloadHeader header; - NL_TEST_ASSERT(inSuite, header.GetMessageType() == 0); - NL_TEST_ASSERT(inSuite, header.GetExchangeID() == 0); - NL_TEST_ASSERT(inSuite, header.HasProtocol(Protocols::NotSpecified)); + EXPECT_EQ(header.GetMessageType(), 0); + EXPECT_EQ(header.GetExchangeID(), 0); + EXPECT_TRUE(header.HasProtocol(Protocols::NotSpecified)); } -void TestPacketHeaderEncodeDecode(nlTestSuite * inSuite, void * inContext) +TEST(TestMessageHeader, TestPacketHeaderEncodeDecode) { PacketHeader header; uint8_t buffer[64]; @@ -68,117 +67,117 @@ void TestPacketHeaderEncodeDecode(nlTestSuite * inSuite, void * inContext) uint16_t decodeLen; header.SetMessageCounter(123); - NL_TEST_ASSERT(inSuite, header.Encode(buffer, &encodeLen) == CHIP_NO_ERROR); + EXPECT_EQ(header.Encode(buffer, &encodeLen), CHIP_NO_ERROR); // change it to verify decoding header.SetMessageCounter(222).SetSourceNodeId(1).SetDestinationNodeId(2); - NL_TEST_ASSERT(inSuite, header.Decode(buffer, &decodeLen) == CHIP_NO_ERROR); - NL_TEST_ASSERT(inSuite, encodeLen == decodeLen); - NL_TEST_ASSERT(inSuite, header.GetMessageCounter() == 123); - NL_TEST_ASSERT(inSuite, !header.GetDestinationNodeId().HasValue()); + EXPECT_EQ(header.Decode(buffer, &decodeLen), CHIP_NO_ERROR); + EXPECT_EQ(encodeLen, decodeLen); + EXPECT_EQ(header.GetMessageCounter(), 123u); + EXPECT_FALSE(header.GetDestinationNodeId().HasValue()); header.SetSourceNodeId(55); - NL_TEST_ASSERT(inSuite, header.Encode(buffer, &encodeLen) == CHIP_NO_ERROR); + EXPECT_EQ(header.Encode(buffer, &encodeLen), CHIP_NO_ERROR); // change it to verify decoding header.SetMessageCounter(222).SetSourceNodeId(1).SetDestinationNodeId(2); - NL_TEST_ASSERT(inSuite, header.Decode(buffer, &decodeLen) == CHIP_NO_ERROR); - NL_TEST_ASSERT(inSuite, encodeLen == decodeLen); - NL_TEST_ASSERT(inSuite, header.GetMessageCounter() == 123); - NL_TEST_ASSERT(inSuite, !header.GetDestinationNodeId().HasValue()); - NL_TEST_ASSERT(inSuite, header.GetSourceNodeId() == Optional::Value(55ull)); + EXPECT_EQ(header.Decode(buffer, &decodeLen), CHIP_NO_ERROR); + EXPECT_EQ(encodeLen, decodeLen); + EXPECT_EQ(header.GetMessageCounter(), 123u); + EXPECT_FALSE(header.GetDestinationNodeId().HasValue()); + EXPECT_EQ(header.GetSourceNodeId(), Optional::Value(55ull)); header.ClearSourceNodeId().SetDestinationNodeId(11); - NL_TEST_ASSERT(inSuite, header.Encode(buffer, &encodeLen) == CHIP_NO_ERROR); + EXPECT_EQ(header.Encode(buffer, &encodeLen), CHIP_NO_ERROR); // change it to verify decoding header.SetMessageCounter(222).SetSourceNodeId(1).SetDestinationNodeId(2); - NL_TEST_ASSERT(inSuite, header.Decode(buffer, &decodeLen) == CHIP_NO_ERROR); - NL_TEST_ASSERT(inSuite, encodeLen == decodeLen); - NL_TEST_ASSERT(inSuite, header.GetMessageCounter() == 123); - NL_TEST_ASSERT(inSuite, header.GetDestinationNodeId() == Optional::Value(11ull)); - NL_TEST_ASSERT(inSuite, !header.GetSourceNodeId().HasValue()); + EXPECT_EQ(header.Decode(buffer, &decodeLen), CHIP_NO_ERROR); + EXPECT_EQ(encodeLen, decodeLen); + EXPECT_EQ(header.GetMessageCounter(), 123u); + EXPECT_EQ(header.GetDestinationNodeId(), Optional::Value(11ull)); + EXPECT_FALSE(header.GetSourceNodeId().HasValue()); header.SetMessageCounter(234).SetSourceNodeId(77).SetDestinationNodeId(88); - NL_TEST_ASSERT(inSuite, header.Encode(buffer, &encodeLen) == CHIP_NO_ERROR); + EXPECT_EQ(header.Encode(buffer, &encodeLen), CHIP_NO_ERROR); // change it to verify decoding header.SetMessageCounter(222).SetSourceNodeId(1).SetDestinationNodeId(2); - NL_TEST_ASSERT(inSuite, header.Decode(buffer, &decodeLen) == CHIP_NO_ERROR); - NL_TEST_ASSERT(inSuite, encodeLen == decodeLen); - NL_TEST_ASSERT(inSuite, header.GetMessageCounter() == 234); - NL_TEST_ASSERT(inSuite, header.GetDestinationNodeId() == Optional::Value(88ull)); - NL_TEST_ASSERT(inSuite, header.GetSourceNodeId() == Optional::Value(77ull)); + EXPECT_EQ(header.Decode(buffer, &decodeLen), CHIP_NO_ERROR); + EXPECT_EQ(encodeLen, decodeLen); + EXPECT_EQ(header.GetMessageCounter(), 234u); + EXPECT_EQ(header.GetDestinationNodeId(), Optional::Value(88ull)); + EXPECT_EQ(header.GetSourceNodeId(), Optional::Value(77ull)); header.SetMessageCounter(234).SetSourceNodeId(77).SetDestinationNodeId(88).SetSecureSessionControlMsg(true); - NL_TEST_ASSERT(inSuite, header.Encode(buffer, &encodeLen) == CHIP_NO_ERROR); + EXPECT_EQ(header.Encode(buffer, &encodeLen), CHIP_NO_ERROR); // change it to verify decoding header.SetMessageCounter(222).SetSourceNodeId(1).SetDestinationNodeId(2); - NL_TEST_ASSERT(inSuite, header.Decode(buffer, &decodeLen) == CHIP_NO_ERROR); - NL_TEST_ASSERT(inSuite, header.GetMessageCounter() == 234); - NL_TEST_ASSERT(inSuite, header.GetDestinationNodeId() == Optional::Value(88ull)); - NL_TEST_ASSERT(inSuite, header.GetSourceNodeId() == Optional::Value(77ull)); - NL_TEST_ASSERT(inSuite, header.IsSecureSessionControlMsg()); + EXPECT_EQ(header.Decode(buffer, &decodeLen), CHIP_NO_ERROR); + EXPECT_EQ(header.GetMessageCounter(), 234u); + EXPECT_EQ(header.GetDestinationNodeId(), Optional::Value(88ull)); + EXPECT_EQ(header.GetSourceNodeId(), Optional::Value(77ull)); + EXPECT_TRUE(header.IsSecureSessionControlMsg()); header.SetMessageCounter(234).SetSourceNodeId(77).SetDestinationNodeId(88).SetSessionId(2); - NL_TEST_ASSERT(inSuite, header.Encode(buffer, &encodeLen) == CHIP_NO_ERROR); + EXPECT_EQ(header.Encode(buffer, &encodeLen), CHIP_NO_ERROR); // change it to verify decoding header.SetMessageCounter(222).SetSourceNodeId(1).SetDestinationNodeId(2); - NL_TEST_ASSERT(inSuite, header.Decode(buffer, &decodeLen) == CHIP_NO_ERROR); - NL_TEST_ASSERT(inSuite, header.GetMessageCounter() == 234); - NL_TEST_ASSERT(inSuite, header.GetDestinationNodeId() == Optional::Value(88ull)); - NL_TEST_ASSERT(inSuite, header.GetSourceNodeId() == Optional::Value(77ull)); - NL_TEST_ASSERT(inSuite, header.IsEncrypted()); - NL_TEST_ASSERT(inSuite, header.GetSessionId() == 2); + EXPECT_EQ(header.Decode(buffer, &decodeLen), CHIP_NO_ERROR); + EXPECT_EQ(header.GetMessageCounter(), 234u); + EXPECT_EQ(header.GetDestinationNodeId(), Optional::Value(88ull)); + EXPECT_EQ(header.GetSourceNodeId(), Optional::Value(77ull)); + EXPECT_TRUE(header.IsEncrypted()); + EXPECT_EQ(header.GetSessionId(), 2); header.SetMessageCounter(234).SetSourceNodeId(77).SetDestinationNodeId(88); - NL_TEST_ASSERT(inSuite, header.Encode(buffer, &encodeLen) == CHIP_NO_ERROR); + EXPECT_EQ(header.Encode(buffer, &encodeLen), CHIP_NO_ERROR); // change it to verify decoding header.SetMessageCounter(222).SetSourceNodeId(1).SetDestinationNodeId(2); - NL_TEST_ASSERT(inSuite, header.Decode(buffer, &decodeLen) == CHIP_NO_ERROR); - NL_TEST_ASSERT(inSuite, header.GetMessageCounter() == 234); - NL_TEST_ASSERT(inSuite, header.GetDestinationNodeId() == Optional::Value(88ull)); - NL_TEST_ASSERT(inSuite, header.GetSourceNodeId() == Optional::Value(77ull)); + EXPECT_EQ(header.Decode(buffer, &decodeLen), CHIP_NO_ERROR); + EXPECT_EQ(header.GetMessageCounter(), 234u); + EXPECT_EQ(header.GetDestinationNodeId(), Optional::Value(88ull)); + EXPECT_EQ(header.GetSourceNodeId(), Optional::Value(77ull)); // Verify Group Id helpers header.SetMessageCounter(234).SetSourceNodeId(77).SetDestinationGroupId(45); - NL_TEST_ASSERT(inSuite, header.Encode(buffer, &encodeLen) == CHIP_ERROR_INTERNAL); + EXPECT_EQ(header.Encode(buffer, &encodeLen), CHIP_ERROR_INTERNAL); header.ClearDestinationNodeId(); header.SetSessionType(Header::SessionType::kGroupSession); header.SetFlags(Header::SecFlagValues::kPrivacyFlag); header.SetSecureSessionControlMsg(false); - NL_TEST_ASSERT(inSuite, header.Encode(buffer, &encodeLen) == CHIP_NO_ERROR); + EXPECT_EQ(header.Encode(buffer, &encodeLen), CHIP_NO_ERROR); // change it to verify decoding header.SetMessageCounter(222).SetSourceNodeId(1).SetDestinationGroupId(2); - NL_TEST_ASSERT(inSuite, header.Decode(buffer, &decodeLen) == CHIP_NO_ERROR); - NL_TEST_ASSERT(inSuite, header.GetMessageCounter() == 234); - NL_TEST_ASSERT(inSuite, header.GetDestinationGroupId() == Optional::Value((uint16_t) 45)); - NL_TEST_ASSERT(inSuite, header.GetSourceNodeId() == Optional::Value(77ull)); - NL_TEST_ASSERT(inSuite, !header.IsSecureSessionControlMsg()); - NL_TEST_ASSERT(inSuite, header.IsValidGroupMsg()); + EXPECT_EQ(header.Decode(buffer, &decodeLen), CHIP_NO_ERROR); + EXPECT_EQ(header.GetMessageCounter(), 234u); + EXPECT_EQ(header.GetDestinationGroupId(), Optional::Value((uint16_t) 45)); + EXPECT_EQ(header.GetSourceNodeId(), Optional::Value(77ull)); + EXPECT_FALSE(header.IsSecureSessionControlMsg()); + EXPECT_TRUE(header.IsValidGroupMsg()); // Verify MCSP state header.ClearDestinationGroupId().SetDestinationNodeId(42).SetFlags(Header::SecFlagValues::kPrivacyFlag); header.SetSecureSessionControlMsg(true); - NL_TEST_ASSERT(inSuite, header.Encode(buffer, &encodeLen) == CHIP_NO_ERROR); + EXPECT_EQ(header.Encode(buffer, &encodeLen), CHIP_NO_ERROR); // change it to verify decoding header.SetMessageCounter(222).SetSourceNodeId(1).SetDestinationGroupId(2); - NL_TEST_ASSERT(inSuite, header.Decode(buffer, &decodeLen) == CHIP_NO_ERROR); - NL_TEST_ASSERT(inSuite, header.GetDestinationNodeId() == Optional::Value(42ull)); - NL_TEST_ASSERT(inSuite, !header.HasDestinationGroupId()); - NL_TEST_ASSERT(inSuite, header.HasPrivacyFlag()); - NL_TEST_ASSERT(inSuite, header.IsValidMCSPMsg()); + EXPECT_EQ(header.Decode(buffer, &decodeLen), CHIP_NO_ERROR); + EXPECT_EQ(header.GetDestinationNodeId(), Optional::Value(42ull)); + EXPECT_FALSE(header.HasDestinationGroupId()); + EXPECT_TRUE(header.HasPrivacyFlag()); + EXPECT_TRUE(header.IsValidMCSPMsg()); } -void TestPayloadHeaderEncodeDecode(nlTestSuite * inSuite, void * inContext) +TEST(TestMessageHeader, TestPayloadHeaderEncodeDecode) { PayloadHeader header; uint8_t buffer[64]; @@ -186,39 +185,39 @@ void TestPayloadHeaderEncodeDecode(nlTestSuite * inSuite, void * inContext) uint16_t decodeLen; header.SetMessageType(Protocols::Id(VendorId::Common, 0), 112).SetExchangeID(2233); - NL_TEST_ASSERT(inSuite, header.GetProtocolID() == Protocols::Id(VendorId::Common, 0)); + EXPECT_EQ(header.GetProtocolID(), Protocols::Id(VendorId::Common, 0)); header.SetMessageType(Protocols::Id(VendorId::Common, 1221), 112).SetExchangeID(2233).SetInitiator(true); - NL_TEST_ASSERT(inSuite, header.Encode(buffer, &encodeLen) == CHIP_NO_ERROR); + EXPECT_EQ(header.Encode(buffer, &encodeLen), CHIP_NO_ERROR); header.SetMessageType(Protocols::Id(VendorId::Common, 4567), 221).SetExchangeID(3322); - NL_TEST_ASSERT(inSuite, header.Decode(buffer, &decodeLen) == CHIP_NO_ERROR); - NL_TEST_ASSERT(inSuite, encodeLen == decodeLen); - NL_TEST_ASSERT(inSuite, header.GetMessageType() == 112); - NL_TEST_ASSERT(inSuite, header.GetExchangeID() == 2233); - NL_TEST_ASSERT(inSuite, header.GetProtocolID() == Protocols::Id(VendorId::Common, 1221)); - NL_TEST_ASSERT(inSuite, header.IsInitiator()); + EXPECT_EQ(header.Decode(buffer, &decodeLen), CHIP_NO_ERROR); + EXPECT_EQ(encodeLen, decodeLen); + EXPECT_EQ(header.GetMessageType(), 112); + EXPECT_EQ(header.GetExchangeID(), 2233); + EXPECT_EQ(header.GetProtocolID(), Protocols::Id(VendorId::Common, 1221)); + EXPECT_TRUE(header.IsInitiator()); header.SetMessageType(Protocols::Id(VendorId::Common, 1221), 112).SetExchangeID(2233); - NL_TEST_ASSERT(inSuite, header.Encode(buffer, &encodeLen) == CHIP_NO_ERROR); + EXPECT_EQ(header.Encode(buffer, &encodeLen), CHIP_NO_ERROR); header.SetMessageType(Protocols::Id(VendorId::NotSpecified, 0), 111).SetExchangeID(222); - NL_TEST_ASSERT(inSuite, header.Decode(buffer, &decodeLen) == CHIP_NO_ERROR); - NL_TEST_ASSERT(inSuite, encodeLen == decodeLen); - NL_TEST_ASSERT(inSuite, header.GetExchangeID() == 2233); - NL_TEST_ASSERT(inSuite, header.GetProtocolID() == Protocols::Id(VendorId::Common, 1221)); + EXPECT_EQ(header.Decode(buffer, &decodeLen), CHIP_NO_ERROR); + EXPECT_EQ(encodeLen, decodeLen); + EXPECT_EQ(header.GetExchangeID(), 2233); + EXPECT_EQ(header.GetProtocolID(), Protocols::Id(VendorId::Common, 1221)); header.SetMessageType(Protocols::Id(VendorId::NotSpecified, 4567), 221).SetExchangeID(3322); - NL_TEST_ASSERT(inSuite, header.Decode(buffer, &decodeLen) == CHIP_NO_ERROR); - NL_TEST_ASSERT(inSuite, encodeLen == decodeLen); - NL_TEST_ASSERT(inSuite, header.GetExchangeID() == 2233); - NL_TEST_ASSERT(inSuite, header.GetProtocolID() == Protocols::Id(VendorId::Common, 1221)); + EXPECT_EQ(header.Decode(buffer, &decodeLen), CHIP_NO_ERROR); + EXPECT_EQ(encodeLen, decodeLen); + EXPECT_EQ(header.GetExchangeID(), 2233); + EXPECT_EQ(header.GetProtocolID(), Protocols::Id(VendorId::Common, 1221)); } -void TestPacketHeaderEncodeDecodeBounds(nlTestSuite * inSuite, void * inContext) +TEST(TestMessageHeader, TestPacketHeaderEncodeDecodeBounds) { PacketHeader header; uint8_t buffer[64] = {}; @@ -226,54 +225,54 @@ void TestPacketHeaderEncodeDecodeBounds(nlTestSuite * inSuite, void * inContext) for (uint16_t shortLen = 0; shortLen < 8; shortLen++) { - NL_TEST_ASSERT(inSuite, header.Encode(buffer, shortLen, &unusedLen) != CHIP_NO_ERROR); - NL_TEST_ASSERT(inSuite, header.Decode(buffer, shortLen, &unusedLen) != CHIP_NO_ERROR); + EXPECT_NE(header.Encode(buffer, shortLen, &unusedLen), CHIP_NO_ERROR); + EXPECT_NE(header.Decode(buffer, shortLen, &unusedLen), CHIP_NO_ERROR); } // Now check that with 8 bytes we can successfully encode a // default-constructed PacketHeader. static const size_t minLen = 8; uint16_t encoded_len; - NL_TEST_ASSERT(inSuite, header.Encode(buffer, minLen, &encoded_len) == CHIP_NO_ERROR); - NL_TEST_ASSERT(inSuite, encoded_len == minLen); + EXPECT_EQ(header.Encode(buffer, minLen, &encoded_len), CHIP_NO_ERROR); + EXPECT_EQ(encoded_len, minLen); // Verify that decoding at any smaller length fails. for (uint16_t shortLen = 0; shortLen < encoded_len; shortLen++) { - NL_TEST_ASSERT(inSuite, header.Decode(buffer, shortLen, &unusedLen) != CHIP_NO_ERROR); + EXPECT_NE(header.Decode(buffer, shortLen, &unusedLen), CHIP_NO_ERROR); } uint16_t decoded_len; - NL_TEST_ASSERT(inSuite, header.Decode(buffer, encoded_len, &decoded_len) == CHIP_NO_ERROR); - NL_TEST_ASSERT(inSuite, decoded_len == encoded_len); + EXPECT_EQ(header.Decode(buffer, encoded_len, &decoded_len), CHIP_NO_ERROR); + EXPECT_EQ(decoded_len, encoded_len); // Now test encoding/decoding with a source node id present. header.SetSourceNodeId(1); for (uint16_t shortLen = minLen; shortLen < minLen + 8; shortLen++) { - NL_TEST_ASSERT(inSuite, header.Encode(buffer, shortLen, &unusedLen) != CHIP_NO_ERROR); + EXPECT_NE(header.Encode(buffer, shortLen, &unusedLen), CHIP_NO_ERROR); } - NL_TEST_ASSERT(inSuite, header.Encode(buffer, minLen + 8, &encoded_len) == CHIP_NO_ERROR); - NL_TEST_ASSERT(inSuite, encoded_len == minLen + 8); + EXPECT_EQ(header.Encode(buffer, minLen + 8, &encoded_len), CHIP_NO_ERROR); + EXPECT_EQ(encoded_len, minLen + 8); for (uint16_t shortLen = 0; shortLen < encoded_len; shortLen++) { - NL_TEST_ASSERT(inSuite, header.Decode(buffer, shortLen, &unusedLen) != CHIP_NO_ERROR); + EXPECT_NE(header.Decode(buffer, shortLen, &unusedLen), CHIP_NO_ERROR); } - NL_TEST_ASSERT(inSuite, header.Decode(buffer, encoded_len, &decoded_len) == CHIP_NO_ERROR); - NL_TEST_ASSERT(inSuite, decoded_len == encoded_len); + EXPECT_EQ(header.Decode(buffer, encoded_len, &decoded_len), CHIP_NO_ERROR); + EXPECT_EQ(decoded_len, encoded_len); // Now test encoding/decoding with a source and destination node id present. header.SetDestinationNodeId(1); for (uint16_t shortLen = minLen; shortLen < minLen + 16; shortLen++) { - NL_TEST_ASSERT(inSuite, header.Encode(buffer, shortLen, &unusedLen) != CHIP_NO_ERROR); + EXPECT_NE(header.Encode(buffer, shortLen, &unusedLen), CHIP_NO_ERROR); } - NL_TEST_ASSERT(inSuite, header.Encode(buffer, minLen + 16, &encoded_len) == CHIP_NO_ERROR); - NL_TEST_ASSERT(inSuite, encoded_len == minLen + 16); + EXPECT_EQ(header.Encode(buffer, minLen + 16, &encoded_len), CHIP_NO_ERROR); + EXPECT_EQ(encoded_len, minLen + 16); for (uint16_t shortLen = 0; shortLen < encoded_len; shortLen++) { - NL_TEST_ASSERT(inSuite, header.Decode(buffer, shortLen, &unusedLen) != CHIP_NO_ERROR); + EXPECT_NE(header.Decode(buffer, shortLen, &unusedLen), CHIP_NO_ERROR); } - NL_TEST_ASSERT(inSuite, header.Decode(buffer, encoded_len, &decoded_len) == CHIP_NO_ERROR); - NL_TEST_ASSERT(inSuite, decoded_len == encoded_len); + EXPECT_EQ(header.Decode(buffer, encoded_len, &decoded_len), CHIP_NO_ERROR); + EXPECT_EQ(decoded_len, encoded_len); // Now test encoding/decoding with a source node id and destination group id present. header.ClearDestinationNodeId(); @@ -281,19 +280,19 @@ void TestPacketHeaderEncodeDecodeBounds(nlTestSuite * inSuite, void * inContext) header.SetSessionType(Header::SessionType::kGroupSession); for (uint16_t shortLen = minLen; shortLen < minLen + 10; shortLen++) { - NL_TEST_ASSERT(inSuite, header.Encode(buffer, shortLen, &unusedLen) != CHIP_NO_ERROR); + EXPECT_NE(header.Encode(buffer, shortLen, &unusedLen), CHIP_NO_ERROR); } - NL_TEST_ASSERT(inSuite, header.Encode(buffer, minLen + 10, &encoded_len) == CHIP_NO_ERROR); - NL_TEST_ASSERT(inSuite, encoded_len == minLen + 10); + EXPECT_EQ(header.Encode(buffer, minLen + 10, &encoded_len), CHIP_NO_ERROR); + EXPECT_EQ(encoded_len, minLen + 10); for (uint16_t shortLen = 0; shortLen < encoded_len; shortLen++) { - NL_TEST_ASSERT(inSuite, header.Decode(buffer, shortLen, &unusedLen) != CHIP_NO_ERROR); + EXPECT_NE(header.Decode(buffer, shortLen, &unusedLen), CHIP_NO_ERROR); } - NL_TEST_ASSERT(inSuite, header.Decode(buffer, encoded_len, &decoded_len) == CHIP_NO_ERROR); - NL_TEST_ASSERT(inSuite, decoded_len == encoded_len); + EXPECT_EQ(header.Decode(buffer, encoded_len, &decoded_len), CHIP_NO_ERROR); + EXPECT_EQ(decoded_len, encoded_len); } -void TestPayloadHeaderEncodeDecodeBounds(nlTestSuite * inSuite, void * inContext) +TEST(TestMessageHeader, TestPayloadHeaderEncodeDecodeBounds) { PayloadHeader header; uint8_t buffer[64] = {}; @@ -301,8 +300,8 @@ void TestPayloadHeaderEncodeDecodeBounds(nlTestSuite * inSuite, void * inContext for (uint16_t shortLen = 0; shortLen < 6; shortLen++) { - NL_TEST_ASSERT(inSuite, header.Encode(buffer, shortLen, &unusedLen) != CHIP_NO_ERROR); - NL_TEST_ASSERT(inSuite, header.Decode(buffer, shortLen, &unusedLen) != CHIP_NO_ERROR); + EXPECT_NE(header.Encode(buffer, shortLen, &unusedLen), CHIP_NO_ERROR); + EXPECT_NE(header.Decode(buffer, shortLen, &unusedLen), CHIP_NO_ERROR); } } @@ -375,7 +374,7 @@ struct SpecComplianceTestVector theSpecComplianceTestVector[] = { }, }; -void TestSpecComplianceEncode(nlTestSuite * inSuite, void * inContext) +TEST(TestMessageHeader, TestSpecComplianceEncode) { uint8_t buffer[MAX_FIXED_HEADER_SIZE]; uint16_t encodeSize; @@ -394,26 +393,26 @@ void TestSpecComplianceEncode(nlTestSuite * inSuite, void * inContext) packetHeader.SetDestinationGroupId(static_cast(testEntry.groupId)); } - NL_TEST_ASSERT(inSuite, packetHeader.Encode(buffer, sizeof(buffer), &encodeSize) == CHIP_NO_ERROR); - NL_TEST_ASSERT(inSuite, encodeSize == testEntry.size); - NL_TEST_ASSERT(inSuite, memcmp(buffer, testEntry.encoded, encodeSize) == 0); + EXPECT_EQ(packetHeader.Encode(buffer, sizeof(buffer), &encodeSize), CHIP_NO_ERROR); + EXPECT_EQ(encodeSize, testEntry.size); + EXPECT_EQ(memcmp(buffer, testEntry.encoded, encodeSize), 0); } } -void TestSpecComplianceDecode(nlTestSuite * inSuite, void * inContext) +TEST(TestMessageHeader, TestSpecComplianceDecode) { PacketHeader packetHeader; uint16_t decodeSize; for (const auto & testEntry : theSpecComplianceTestVector) { - NL_TEST_ASSERT(inSuite, packetHeader.Decode(testEntry.encoded, testEntry.size, &decodeSize) == CHIP_NO_ERROR); - NL_TEST_ASSERT(inSuite, decodeSize == testEntry.size); - NL_TEST_ASSERT(inSuite, packetHeader.GetMessageFlags() == testEntry.messageFlags); - NL_TEST_ASSERT(inSuite, packetHeader.GetSecurityFlags() == testEntry.securityFlags); - NL_TEST_ASSERT(inSuite, packetHeader.GetSessionId() == testEntry.sessionId); - NL_TEST_ASSERT(inSuite, packetHeader.GetMessageCounter() == testEntry.messageCounter); - NL_TEST_ASSERT(inSuite, packetHeader.IsEncrypted() == testEntry.isSecure); + EXPECT_EQ(packetHeader.Decode(testEntry.encoded, testEntry.size, &decodeSize), CHIP_NO_ERROR); + EXPECT_EQ(decodeSize, testEntry.size); + EXPECT_EQ(packetHeader.GetMessageFlags(), testEntry.messageFlags); + EXPECT_EQ(packetHeader.GetSecurityFlags(), testEntry.securityFlags); + EXPECT_EQ(packetHeader.GetSessionId(), testEntry.sessionId); + EXPECT_EQ(packetHeader.GetMessageCounter(), testEntry.messageCounter); + EXPECT_EQ(packetHeader.IsEncrypted(), testEntry.isSecure); } } @@ -512,49 +511,26 @@ struct TestVectorMsgExtensions theTestVectorMsgExtensions[] = { }, }; -void TestMsgExtensionsDecode(nlTestSuite * inSuite, void * inContext) +TEST(TestMessageHeader, TestMsgExtensionsDecode) { PacketHeader packetHeader; PayloadHeader payloadHeader; uint16_t decodeSize; - NL_TEST_ASSERT(inSuite, chip::Platform::MemoryInit() == CHIP_NO_ERROR); + ASSERT_EQ(chip::Platform::MemoryInit(), CHIP_NO_ERROR); for (const auto & testEntry : theTestVectorMsgExtensions) { System::PacketBufferHandle msg = System::PacketBufferHandle::NewWithData(testEntry.msg, testEntry.msgLength); - NL_TEST_ASSERT(inSuite, packetHeader.Decode(msg->Start(), msg->DataLength(), &decodeSize) == CHIP_NO_ERROR); - NL_TEST_ASSERT(inSuite, decodeSize == testEntry.payloadOffset); + EXPECT_EQ(packetHeader.Decode(msg->Start(), msg->DataLength(), &decodeSize), CHIP_NO_ERROR); + EXPECT_EQ(decodeSize, testEntry.payloadOffset); - NL_TEST_ASSERT(inSuite, payloadHeader.Decode(msg->Start() + decodeSize, msg->DataLength(), &decodeSize) == CHIP_NO_ERROR); - NL_TEST_ASSERT(inSuite, decodeSize == testEntry.appPayloadOffset); + EXPECT_EQ(payloadHeader.Decode(msg->Start() + decodeSize, msg->DataLength(), &decodeSize), CHIP_NO_ERROR); + EXPECT_EQ(decodeSize, testEntry.appPayloadOffset); } -} - -} // namespace - -// clang-format off -static const nlTest sTests[] = -{ - NL_TEST_DEF("PacketInitialState", TestPacketHeaderInitialState), - NL_TEST_DEF("PayloadInitialState", TestPayloadHeaderInitialState), - NL_TEST_DEF("PacketEncodeDecode", TestPacketHeaderEncodeDecode), - NL_TEST_DEF("PayloadEncodeDecode", TestPayloadHeaderEncodeDecode), - NL_TEST_DEF("PacketEncodeDecodeBounds", TestPacketHeaderEncodeDecodeBounds), - NL_TEST_DEF("PayloadEncodeDecodeBounds", TestPayloadHeaderEncodeDecodeBounds), - NL_TEST_DEF("SpecComplianceEncode", TestSpecComplianceEncode), - NL_TEST_DEF("SpecComplianceDecode", TestSpecComplianceDecode), - NL_TEST_DEF("TestMsgExtensionsDecode", TestMsgExtensionsDecode), - NL_TEST_SENTINEL() -}; -// clang-format on -int TestMessageHeader() -{ - nlTestSuite theSuite = { "Transport-MessageHeader", &sTests[0], nullptr, nullptr }; - nlTestRunner(&theSuite, nullptr); - return nlTestRunnerStats(&theSuite); + chip::Platform::MemoryShutdown(); } -CHIP_REGISTER_TEST_SUITE(TestMessageHeader) +} // namespace diff --git a/src/transport/raw/tests/TestPeerAddress.cpp b/src/transport/raw/tests/TestPeerAddress.cpp index 6b7f9f886df085..8d82e28ad58eb5 100644 --- a/src/transport/raw/tests/TestPeerAddress.cpp +++ b/src/transport/raw/tests/TestPeerAddress.cpp @@ -24,10 +24,9 @@ #include #include #include -#include #include -#include +#include namespace { @@ -39,27 +38,27 @@ using chip::Transport::PeerAddress; /** * Test correct identification of IPv6 multicast addresses. */ -void TestPeerAddressMulticast(nlTestSuite * inSuite, void * inContext) +TEST(TestPeerAddress, TestPeerAddressMulticast) { constexpr chip::FabricId fabric = 0xa1a2a4a8b1b2b4b8; constexpr chip::GroupId group = 0xe10f; PeerAddress addr = PeerAddress::Multicast(fabric, group); - NL_TEST_ASSERT(inSuite, chip::Transport::Type::kUdp == addr.GetTransportType()); - NL_TEST_ASSERT(inSuite, addr.IsMulticast()); + EXPECT_EQ(chip::Transport::Type::kUdp, addr.GetTransportType()); + EXPECT_TRUE(addr.IsMulticast()); const Inet::IPAddress & ip = addr.GetIPAddress(); - NL_TEST_ASSERT(inSuite, ip.IsIPv6Multicast()); - NL_TEST_ASSERT(inSuite, chip::Inet::IPAddressType::kIPv6 == ip.Type()); + EXPECT_TRUE(ip.IsIPv6Multicast()); + EXPECT_EQ(chip::Inet::IPAddressType::kIPv6, ip.Type()); constexpr uint8_t expected[NL_INET_IPV6_ADDR_LEN_IN_BYTES] = { 0xff, 0x35, 0x00, 0x40, 0xfd, 0xa1, 0xa2, 0xa4, 0xa8, 0xb1, 0xb2, 0xb4, 0xb8, 0x00, 0xe1, 0x0f }; uint8_t result[NL_INET_IPV6_ADDR_LEN_IN_BYTES]; uint8_t * p = result; ip.WriteAddress(p); - NL_TEST_ASSERT(inSuite, !memcmp(expected, result, NL_INET_IPV6_ADDR_LEN_IN_BYTES)); + EXPECT_EQ(0, memcmp(expected, result, NL_INET_IPV6_ADDR_LEN_IN_BYTES)); } -void TestToString(nlTestSuite * inSuite, void * inContext) +TEST(TestPeerAddress, TestToString) { char buff[PeerAddress::kMaxToStringSize]; IPAddress ip; @@ -67,19 +66,19 @@ void TestToString(nlTestSuite * inSuite, void * inContext) IPAddress::FromString("::1", ip); PeerAddress::UDP(ip, 1122).ToString(buff); - NL_TEST_ASSERT(inSuite, !strcmp(buff, "UDP:[::1]:1122")); + EXPECT_STREQ(buff, "UDP:[::1]:1122"); } { IPAddress::FromString("::1", ip); PeerAddress::TCP(ip, 1122).ToString(buff); - NL_TEST_ASSERT(inSuite, !strcmp(buff, "TCP:[::1]:1122")); + EXPECT_STREQ(buff, "TCP:[::1]:1122"); } { PeerAddress::BLE().ToString(buff); - NL_TEST_ASSERT(inSuite, !strcmp(buff, "BLE")); + EXPECT_STREQ(buff, "BLE"); } { @@ -89,7 +88,7 @@ void TestToString(nlTestSuite * inSuite, void * inContext) int res1 = strcmp(buff, "UDP:[1223::3456:789a]:8080"); int res2 = strcmp(buff, "UDP:[1223::3456:789A]:8080"); - NL_TEST_ASSERT(inSuite, (!res1 || !res2)); + EXPECT_TRUE(!res1 || !res2); } { @@ -97,41 +96,8 @@ void TestToString(nlTestSuite * inSuite, void * inContext) PeerAddress udp = PeerAddress(Transport::Type::kUdp); udp.SetPort(5840); udp.ToString(buff); - NL_TEST_ASSERT(inSuite, !strcmp(buff, "UDP:[::]:5840")); + EXPECT_STREQ(buff, "UDP:[::]:5840"); } } -/** - * Test Suite. It lists all the test functions. - */ - -// clang-format off -const nlTest sTests[] = -{ - NL_TEST_DEF("PeerAddress Multicast", TestPeerAddressMulticast), - NL_TEST_DEF("ToString", TestToString), - NL_TEST_SENTINEL() -}; -// clang-format on - } // namespace - -int TestPeerAddress() -{ - // clang-format off - nlTestSuite theSuite = - { - "PeerAddress", - &sTests[0], - nullptr, - nullptr - }; - // clang-format on - - // Run test suite against one context. - nlTestRunner(&theSuite, nullptr); - - return (nlTestRunnerStats(&theSuite)); -} - -CHIP_REGISTER_TEST_SUITE(TestPeerAddress) diff --git a/src/transport/raw/tests/TestTCP.cpp b/src/transport/raw/tests/TestTCP.cpp index 620e97ca4325b3..93414e01e3d653 100644 --- a/src/transport/raw/tests/TestTCP.cpp +++ b/src/transport/raw/tests/TestTCP.cpp @@ -27,14 +27,12 @@ #include #include #include -#include -#include #include #include #include #include -#include +#include #include #include @@ -44,19 +42,6 @@ using namespace chip; using namespace chip::Inet; -static int Initialize(void * aContext); -static int Finalize(void * aContext); - -namespace chip { -namespace Transport { -class TCPTest -{ -public: - static void CheckProcessReceivedBuffer(nlTestSuite * inSuite, void * inContext); -}; -} // namespace Transport -} // namespace chip - namespace { constexpr size_t kMaxTcpActiveConnectionCount = 4; @@ -78,9 +63,7 @@ class MockTransportMgrDelegate : public chip::TransportMgrDelegate public: typedef int (*MessageReceivedCallback)(const uint8_t * message, size_t length, int count, void * data); - MockTransportMgrDelegate(nlTestSuite * inSuite, TestContext & inContext) : - mSuite(inSuite), mContext(inContext), mCallback(nullptr), mCallbackData(nullptr) - {} + MockTransportMgrDelegate(TestContext * inContext) : mContext(inContext), mCallback(nullptr), mCallbackData(nullptr) {} ~MockTransportMgrDelegate() override {} void SetCallback(MessageReceivedCallback callback = nullptr, void * callback_data = nullptr) @@ -92,13 +75,11 @@ class MockTransportMgrDelegate : public chip::TransportMgrDelegate { PacketHeader packetHeader; - CHIP_ERROR error = packetHeader.DecodeAndConsume(msgBuf); - NL_TEST_ASSERT(mSuite, error == CHIP_NO_ERROR); + EXPECT_EQ(packetHeader.DecodeAndConsume(msgBuf), CHIP_NO_ERROR); if (mCallback) { - int err = mCallback(msgBuf->Start(), msgBuf->DataLength(), mReceiveHandlerCallCount, mCallbackData); - NL_TEST_ASSERT(mSuite, err == 0); + EXPECT_EQ(mCallback(msgBuf->Start(), msgBuf->DataLength(), mReceiveHandlerCallCount, mCallbackData), 0); } mReceiveHandlerCallCount++; @@ -106,7 +87,7 @@ class MockTransportMgrDelegate : public chip::TransportMgrDelegate void InitializeMessageTest(TCPImpl & tcp, const IPAddress & addr) { - CHIP_ERROR err = tcp.Init(Transport::TcpListenParameters(mContext.GetTCPEndPointManager()).SetAddressType(addr.Type())); + CHIP_ERROR err = tcp.Init(Transport::TcpListenParameters(mContext->GetTCPEndPointManager()).SetAddressType(addr.Type())); // retry a few times in case the port is somehow in use. // this is a WORKAROUND for flaky testing if we run tests very fast after each other. @@ -125,10 +106,10 @@ class MockTransportMgrDelegate : public chip::TransportMgrDelegate { ChipLogProgress(NotSpecified, "RETRYING tcp initialization"); chip::test_utils::SleepMillis(100); - err = tcp.Init(Transport::TcpListenParameters(mContext.GetTCPEndPointManager()).SetAddressType(addr.Type())); + err = tcp.Init(Transport::TcpListenParameters(mContext->GetTCPEndPointManager()).SetAddressType(addr.Type())); } - NL_TEST_ASSERT(mSuite, err == CHIP_NO_ERROR); + EXPECT_EQ(err, CHIP_NO_ERROR); mTransportMgrBase.SetSessionManager(this); mTransportMgrBase.Init(&tcp); @@ -139,7 +120,7 @@ class MockTransportMgrDelegate : public chip::TransportMgrDelegate void SingleMessageTest(TCPImpl & tcp, const IPAddress & addr) { chip::System::PacketBufferHandle buffer = chip::System::PacketBufferHandle::NewWithData(PAYLOAD, sizeof(PAYLOAD)); - NL_TEST_ASSERT(mSuite, !buffer.IsNull()); + ASSERT_FALSE(buffer.IsNull()); PacketHeader header; header.SetSourceNodeId(kSourceNodeId).SetDestinationNodeId(kDestinationNodeId).SetMessageCounter(kMessageCounter); @@ -148,14 +129,14 @@ class MockTransportMgrDelegate : public chip::TransportMgrDelegate const_cast(static_cast(PAYLOAD))); CHIP_ERROR err = header.EncodeBeforeData(buffer); - NL_TEST_ASSERT(mSuite, err == CHIP_NO_ERROR); + EXPECT_EQ(err, CHIP_NO_ERROR); // Should be able to send a message to itself by just calling send. err = tcp.SendMessage(Transport::PeerAddress::TCP(addr), std::move(buffer)); - NL_TEST_ASSERT(mSuite, err == CHIP_NO_ERROR); + EXPECT_EQ(err, CHIP_NO_ERROR); - mContext.DriveIOUntil(chip::System::Clock::Seconds16(5), [this]() { return mReceiveHandlerCallCount != 0; }); - NL_TEST_ASSERT(mSuite, mReceiveHandlerCallCount == 1); + mContext->DriveIOUntil(chip::System::Clock::Seconds16(5), [this]() { return mReceiveHandlerCallCount != 0; }); + EXPECT_EQ(mReceiveHandlerCallCount, 1); SetCallback(nullptr); } @@ -164,14 +145,13 @@ class MockTransportMgrDelegate : public chip::TransportMgrDelegate { // Disconnect and wait for seeing peer close tcp.Disconnect(Transport::PeerAddress::TCP(addr)); - mContext.DriveIOUntil(chip::System::Clock::Seconds16(5), [&tcp]() { return !tcp.HasActiveConnections(); }); + mContext->DriveIOUntil(chip::System::Clock::Seconds16(5), [&tcp]() { return !tcp.HasActiveConnections(); }); } int mReceiveHandlerCallCount = 0; private: - nlTestSuite * mSuite; - TestContext & mContext; + TestContext * mContext; MessageReceivedCallback mCallback; void * mCallbackData; TransportMgrBase mTransportMgrBase; @@ -179,56 +159,56 @@ class MockTransportMgrDelegate : public chip::TransportMgrDelegate /////////////////////////// Init test -void CheckSimpleInitTest(nlTestSuite * inSuite, void * inContext, Inet::IPAddressType type) +class TestTCP : public ::testing::Test, public chip::Test::IOContext { - TestContext & ctx = *reinterpret_cast(inContext); - - TCPImpl tcp; +protected: + void SetUp() { ASSERT_EQ(Init(), CHIP_NO_ERROR); } + void TearDown() { Shutdown(); } - CHIP_ERROR err = tcp.Init(Transport::TcpListenParameters(ctx.GetTCPEndPointManager()).SetAddressType(type)); + void CheckSimpleInitTest(Inet::IPAddressType type) + { + TCPImpl tcp; - NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR); -} + CHIP_ERROR err = tcp.Init(Transport::TcpListenParameters(GetTCPEndPointManager()).SetAddressType(type)); -#if INET_CONFIG_ENABLE_IPV4 -void CheckSimpleInitTest4(nlTestSuite * inSuite, void * inContext) -{ - CheckSimpleInitTest(inSuite, inContext, IPAddressType::kIPv4); -} -#endif + EXPECT_EQ(err, CHIP_NO_ERROR); + } -void CheckSimpleInitTest6(nlTestSuite * inSuite, void * inContext) -{ - CheckSimpleInitTest(inSuite, inContext, IPAddressType::kIPv6); -} + void CheckMessageTest(const IPAddress & addr) + { + TCPImpl tcp; -/////////////////////////// Messaging test + MockTransportMgrDelegate gMockTransportMgrDelegate(this); + gMockTransportMgrDelegate.InitializeMessageTest(tcp, addr); + gMockTransportMgrDelegate.SingleMessageTest(tcp, addr); + gMockTransportMgrDelegate.FinalizeMessageTest(tcp, addr); + } +}; -void CheckMessageTest(nlTestSuite * inSuite, void * inContext, const IPAddress & addr) +#if INET_CONFIG_ENABLE_IPV4 +TEST_F(TestTCP, CheckSimpleInitTest4) { - TestContext & ctx = *reinterpret_cast(inContext); - TCPImpl tcp; - - MockTransportMgrDelegate gMockTransportMgrDelegate(inSuite, ctx); - gMockTransportMgrDelegate.InitializeMessageTest(tcp, addr); - gMockTransportMgrDelegate.SingleMessageTest(tcp, addr); - gMockTransportMgrDelegate.FinalizeMessageTest(tcp, addr); + CheckSimpleInitTest(IPAddressType::kIPv4); } -#if INET_CONFIG_ENABLE_IPV4 -void CheckMessageTest4(nlTestSuite * inSuite, void * inContext) +TEST_F(TestTCP, CheckMessageTest4) { IPAddress addr; IPAddress::FromString("127.0.0.1", addr); - CheckMessageTest(inSuite, inContext, addr); + CheckMessageTest(addr); +} +#endif + +TEST_F(TestTCP, CheckSimpleInitTest6) +{ + CheckSimpleInitTest(IPAddressType::kIPv6); } -#endif // INET_CONFIG_ENABLE_IPV4 -void CheckMessageTest6(nlTestSuite * inSuite, void * inContext) +TEST_F(TestTCP, CheckMessageTest6) { IPAddress addr; IPAddress::FromString("::1", addr); - CheckMessageTest(inSuite, inContext, addr); + CheckMessageTest(addr); } // Generates a packet buffer or a chain of packet buffers for a single message. @@ -382,127 +362,84 @@ int TestDataCallbackCheck(const uint8_t * message, size_t length, int count, voi } // namespace -void chip::Transport::TCPTest::CheckProcessReceivedBuffer(nlTestSuite * inSuite, void * inContext) -{ - TestContext & ctx = *reinterpret_cast(inContext); - TCPImpl tcp; - - IPAddress addr; - IPAddress::FromString("::1", addr); - - MockTransportMgrDelegate gMockTransportMgrDelegate(inSuite, ctx); - gMockTransportMgrDelegate.InitializeMessageTest(tcp, addr); - - // Send a packet to get TCP going, so that we can find a TCPEndPoint to pass to ProcessReceivedBuffer. - // (The current TCPEndPoint implementation is not effectively mockable.) - gMockTransportMgrDelegate.SingleMessageTest(tcp, addr); - - Transport::PeerAddress lPeerAddress = Transport::PeerAddress::TCP(addr); - TCPBase::ActiveConnectionState * state = tcp.FindActiveConnection(lPeerAddress); - NL_TEST_ASSERT(inSuite, state != nullptr); - Inet::TCPEndPoint * lEndPoint = state->mEndPoint; - NL_TEST_ASSERT(inSuite, lEndPoint != nullptr); - - CHIP_ERROR err = CHIP_NO_ERROR; - TestData testData[2]; - gMockTransportMgrDelegate.SetCallback(TestDataCallbackCheck, testData); - - // Test a single packet buffer. - gMockTransportMgrDelegate.mReceiveHandlerCallCount = 0; - NL_TEST_ASSERT(inSuite, testData[0].Init((const uint16_t[]){ 111, 0 })); - err = tcp.ProcessReceivedBuffer(lEndPoint, lPeerAddress, std::move(testData[0].mHandle)); - NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR); - NL_TEST_ASSERT(inSuite, gMockTransportMgrDelegate.mReceiveHandlerCallCount == 1); - - // Test a message in a chain of three packet buffers. The message length is split across buffers. - gMockTransportMgrDelegate.mReceiveHandlerCallCount = 0; - NL_TEST_ASSERT(inSuite, testData[0].Init((const uint16_t[]){ 1, 122, 123, 0 })); - err = tcp.ProcessReceivedBuffer(lEndPoint, lPeerAddress, std::move(testData[0].mHandle)); - NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR); - NL_TEST_ASSERT(inSuite, gMockTransportMgrDelegate.mReceiveHandlerCallCount == 1); - - // Test two messages in a chain. - gMockTransportMgrDelegate.mReceiveHandlerCallCount = 0; - NL_TEST_ASSERT(inSuite, testData[0].Init((const uint16_t[]){ 131, 0 })); - NL_TEST_ASSERT(inSuite, testData[1].Init((const uint16_t[]){ 132, 0 })); - testData[0].mHandle->AddToEnd(std::move(testData[1].mHandle)); - err = tcp.ProcessReceivedBuffer(lEndPoint, lPeerAddress, std::move(testData[0].mHandle)); - NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR); - NL_TEST_ASSERT(inSuite, gMockTransportMgrDelegate.mReceiveHandlerCallCount == 2); - - // Test a chain of two messages, each a chain. - gMockTransportMgrDelegate.mReceiveHandlerCallCount = 0; - NL_TEST_ASSERT(inSuite, testData[0].Init((const uint16_t[]){ 141, 142, 0 })); - NL_TEST_ASSERT(inSuite, testData[1].Init((const uint16_t[]){ 143, 144, 0 })); - testData[0].mHandle->AddToEnd(std::move(testData[1].mHandle)); - err = tcp.ProcessReceivedBuffer(lEndPoint, lPeerAddress, std::move(testData[0].mHandle)); - NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR); - NL_TEST_ASSERT(inSuite, gMockTransportMgrDelegate.mReceiveHandlerCallCount == 2); - - // Test a message that is too large to coalesce into a single packet buffer. - gMockTransportMgrDelegate.mReceiveHandlerCallCount = 0; - gMockTransportMgrDelegate.SetCallback(TestDataCallbackCheck, &testData[1]); - NL_TEST_ASSERT(inSuite, testData[0].Init((const uint16_t[]){ 51, System::PacketBuffer::kMaxSizeWithoutReserve, 0 })); - // Sending only the first buffer of the long chain. This should be enough to trigger the error. - System::PacketBufferHandle head = testData[0].mHandle.PopHead(); - err = tcp.ProcessReceivedBuffer(lEndPoint, lPeerAddress, std::move(head)); - NL_TEST_ASSERT(inSuite, err == CHIP_ERROR_MESSAGE_TOO_LONG); - NL_TEST_ASSERT(inSuite, gMockTransportMgrDelegate.mReceiveHandlerCallCount == 0); - - gMockTransportMgrDelegate.FinalizeMessageTest(tcp, addr); -} - -// Test Suite -/** - * Test Suite that lists all the test functions. - */ -// clang-format off -static const nlTest sTests[] = -{ -#if INET_CONFIG_ENABLE_IPV4 - NL_TEST_DEF("Simple Init Test IPV4", CheckSimpleInitTest4), - NL_TEST_DEF("Message Self Test IPV4", CheckMessageTest4), -#endif - - NL_TEST_DEF("Simple Init Test IPV6", CheckSimpleInitTest6), - NL_TEST_DEF("Message Self Test IPV6", CheckMessageTest6), - NL_TEST_DEF("ProcessReceivedBuffer Test", chip::Transport::TCPTest::CheckProcessReceivedBuffer), - - NL_TEST_SENTINEL() -}; -// clang-format on - -// clang-format off -static nlTestSuite sSuite = +namespace chip { +namespace Transport { +class TCPTest { - "Test-CHIP-Tcp", - &sTests[0], - Initialize, - Finalize +public: + static void CheckProcessReceivedBuffer(TestContext * ctx) + { + TCPImpl tcp; + + IPAddress addr; + IPAddress::FromString("::1", addr); + + MockTransportMgrDelegate gMockTransportMgrDelegate(ctx); + gMockTransportMgrDelegate.InitializeMessageTest(tcp, addr); + + // Send a packet to get TCP going, so that we can find a TCPEndPoint to pass to ProcessReceivedBuffer. + // (The current TCPEndPoint implementation is not effectively mockable.) + gMockTransportMgrDelegate.SingleMessageTest(tcp, addr); + + Transport::PeerAddress lPeerAddress = Transport::PeerAddress::TCP(addr); + TCPBase::ActiveConnectionState * state = tcp.FindActiveConnection(lPeerAddress); + ASSERT_NE(state, nullptr); + Inet::TCPEndPoint * lEndPoint = state->mEndPoint; + ASSERT_NE(lEndPoint, nullptr); + + CHIP_ERROR err = CHIP_NO_ERROR; + TestData testData[2]; + gMockTransportMgrDelegate.SetCallback(TestDataCallbackCheck, testData); + + // Test a single packet buffer. + gMockTransportMgrDelegate.mReceiveHandlerCallCount = 0; + EXPECT_TRUE(testData[0].Init((const uint16_t[]){ 111, 0 })); + err = tcp.ProcessReceivedBuffer(lEndPoint, lPeerAddress, std::move(testData[0].mHandle)); + EXPECT_EQ(err, CHIP_NO_ERROR); + EXPECT_EQ(gMockTransportMgrDelegate.mReceiveHandlerCallCount, 1); + + // Test a message in a chain of three packet buffers. The message length is split across buffers. + gMockTransportMgrDelegate.mReceiveHandlerCallCount = 0; + EXPECT_TRUE(testData[0].Init((const uint16_t[]){ 1, 122, 123, 0 })); + err = tcp.ProcessReceivedBuffer(lEndPoint, lPeerAddress, std::move(testData[0].mHandle)); + EXPECT_EQ(err, CHIP_NO_ERROR); + EXPECT_EQ(gMockTransportMgrDelegate.mReceiveHandlerCallCount, 1); + + // Test two messages in a chain. + gMockTransportMgrDelegate.mReceiveHandlerCallCount = 0; + EXPECT_TRUE(testData[0].Init((const uint16_t[]){ 131, 0 })); + EXPECT_TRUE(testData[1].Init((const uint16_t[]){ 132, 0 })); + testData[0].mHandle->AddToEnd(std::move(testData[1].mHandle)); + err = tcp.ProcessReceivedBuffer(lEndPoint, lPeerAddress, std::move(testData[0].mHandle)); + EXPECT_EQ(err, CHIP_NO_ERROR); + EXPECT_EQ(gMockTransportMgrDelegate.mReceiveHandlerCallCount, 2); + + // Test a chain of two messages, each a chain. + gMockTransportMgrDelegate.mReceiveHandlerCallCount = 0; + EXPECT_TRUE(testData[0].Init((const uint16_t[]){ 141, 142, 0 })); + EXPECT_TRUE(testData[1].Init((const uint16_t[]){ 143, 144, 0 })); + testData[0].mHandle->AddToEnd(std::move(testData[1].mHandle)); + err = tcp.ProcessReceivedBuffer(lEndPoint, lPeerAddress, std::move(testData[0].mHandle)); + EXPECT_EQ(err, CHIP_NO_ERROR); + EXPECT_EQ(gMockTransportMgrDelegate.mReceiveHandlerCallCount, 2); + + // Test a message that is too large to coalesce into a single packet buffer. + gMockTransportMgrDelegate.mReceiveHandlerCallCount = 0; + gMockTransportMgrDelegate.SetCallback(TestDataCallbackCheck, &testData[1]); + EXPECT_TRUE(testData[0].Init((const uint16_t[]){ 51, System::PacketBuffer::kMaxSizeWithoutReserve, 0 })); + // Sending only the first buffer of the long chain. This should be enough to trigger the error. + System::PacketBufferHandle head = testData[0].mHandle.PopHead(); + err = tcp.ProcessReceivedBuffer(lEndPoint, lPeerAddress, std::move(head)); + EXPECT_EQ(err, CHIP_ERROR_MESSAGE_TOO_LONG); + EXPECT_EQ(gMockTransportMgrDelegate.mReceiveHandlerCallCount, 0); + + gMockTransportMgrDelegate.FinalizeMessageTest(tcp, addr); + } }; -// clang-format on - -/** - * Initialize the test suite. - */ -static int Initialize(void * aContext) -{ - CHIP_ERROR err = reinterpret_cast(aContext)->Init(); - return (err == CHIP_NO_ERROR) ? SUCCESS : FAILURE; -} - -/** - * Finalize the test suite. - */ -static int Finalize(void * aContext) -{ - reinterpret_cast(aContext)->Shutdown(); - return SUCCESS; -} +} // namespace Transport +} // namespace chip -int TestTCP() +TEST_F(TestTCP, CheckProcessReceivedBuffer) { - return chip::ExecuteTestsWithContext(&sSuite); + chip::Transport::TCPTest::CheckProcessReceivedBuffer(this); } - -CHIP_REGISTER_TEST_SUITE(TestTCP); diff --git a/src/transport/raw/tests/TestUDP.cpp b/src/transport/raw/tests/TestUDP.cpp index b26d23277d5844..70077a6fa297e9 100644 --- a/src/transport/raw/tests/TestUDP.cpp +++ b/src/transport/raw/tests/TestUDP.cpp @@ -25,21 +25,16 @@ #include #include -#include -#include #include #include -#include +#include #include using namespace chip; using namespace chip::Inet; -static int Initialize(void * aContext); -static int Finalize(void * aContext); - namespace { constexpr NodeId kSourceNodeId = 123654; @@ -54,7 +49,7 @@ int ReceiveHandlerCallCount = 0; class MockTransportMgrDelegate : public TransportMgrDelegate { public: - MockTransportMgrDelegate(nlTestSuite * inSuite) : mSuite(inSuite) {} + MockTransportMgrDelegate() {} ~MockTransportMgrDelegate() override {} void OnMessageReceived(const Transport::PeerAddress & source, System::PacketBufferHandle && msgBuf) override @@ -62,69 +57,57 @@ class MockTransportMgrDelegate : public TransportMgrDelegate PacketHeader packetHeader; CHIP_ERROR err = packetHeader.DecodeAndConsume(msgBuf); - NL_TEST_ASSERT(mSuite, err == CHIP_NO_ERROR); + EXPECT_EQ(err, CHIP_NO_ERROR); - NL_TEST_ASSERT(mSuite, packetHeader.GetSourceNodeId() == Optional::Value(kSourceNodeId)); - NL_TEST_ASSERT(mSuite, packetHeader.GetDestinationNodeId() == Optional::Value(kDestinationNodeId)); - NL_TEST_ASSERT(mSuite, packetHeader.GetMessageCounter() == kMessageCounter); + EXPECT_EQ(packetHeader.GetSourceNodeId(), Optional::Value(kSourceNodeId)); + EXPECT_EQ(packetHeader.GetDestinationNodeId(), Optional::Value(kDestinationNodeId)); + EXPECT_EQ(packetHeader.GetMessageCounter(), kMessageCounter); size_t data_len = msgBuf->DataLength(); - int compare = memcmp(msgBuf->Start(), PAYLOAD, data_len); - NL_TEST_ASSERT(mSuite, compare == 0); + EXPECT_EQ(0, memcmp(msgBuf->Start(), PAYLOAD, data_len)); ReceiveHandlerCallCount++; } - -private: - nlTestSuite * mSuite; }; } // namespace /////////////////////////// Init test -void CheckSimpleInitTest(nlTestSuite * inSuite, void * inContext, Inet::IPAddressType type) +class TestUDP : public ::testing::Test { - TestContext & ctx = *reinterpret_cast(inContext); +protected: + TestUDP() { inContext = new TestContext(); } + ~TestUDP() { delete inContext; } + void SetUp() { ASSERT_EQ(inContext->Init(), CHIP_NO_ERROR); } + void TearDown() { inContext->Shutdown(); } + TestContext * inContext; +}; +void CheckSimpleInitTest(TestContext * ctx, Inet::IPAddressType type) +{ Transport::UDP udp; - CHIP_ERROR err = udp.Init(Transport::UdpListenParameters(ctx.GetUDPEndPointManager()).SetAddressType(type).SetListenPort(0)); + CHIP_ERROR err = udp.Init(Transport::UdpListenParameters(ctx->GetUDPEndPointManager()).SetAddressType(type).SetListenPort(0)); - NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR); + EXPECT_EQ(err, CHIP_NO_ERROR); } -#if INET_CONFIG_ENABLE_IPV4 -void CheckSimpleInitTest4(nlTestSuite * inSuite, void * inContext) +void CheckMessageTest(TestContext * ctx, const IPAddress & addr) { - CheckSimpleInitTest(inSuite, inContext, IPAddressType::kIPv4); -} -#endif - -void CheckSimpleInitTest6(nlTestSuite * inSuite, void * inContext) -{ - CheckSimpleInitTest(inSuite, inContext, IPAddressType::kIPv6); -} - -/////////////////////////// Messaging test - -void CheckMessageTest(nlTestSuite * inSuite, void * inContext, const IPAddress & addr) -{ - TestContext & ctx = *reinterpret_cast(inContext); - uint16_t payload_len = sizeof(PAYLOAD); chip::System::PacketBufferHandle buffer = chip::System::PacketBufferHandle::NewWithData(PAYLOAD, payload_len); - NL_TEST_ASSERT(inSuite, !buffer.IsNull()); + EXPECT_FALSE(buffer.IsNull()); CHIP_ERROR err = CHIP_NO_ERROR; Transport::UDP udp; - err = udp.Init(Transport::UdpListenParameters(ctx.GetUDPEndPointManager()).SetAddressType(addr.Type()).SetListenPort(0)); - NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR); + err = udp.Init(Transport::UdpListenParameters(ctx->GetUDPEndPointManager()).SetAddressType(addr.Type()).SetListenPort(0)); + EXPECT_EQ(err, CHIP_NO_ERROR); - MockTransportMgrDelegate gMockTransportMgrDelegate(inSuite); + MockTransportMgrDelegate gMockTransportMgrDelegate; TransportMgrBase gTransportMgrBase; gTransportMgrBase.SetSessionManager(&gMockTransportMgrDelegate); gTransportMgrBase.Init(&udp); @@ -135,82 +118,39 @@ void CheckMessageTest(nlTestSuite * inSuite, void * inContext, const IPAddress & header.SetSourceNodeId(kSourceNodeId).SetDestinationNodeId(kDestinationNodeId).SetMessageCounter(kMessageCounter); err = header.EncodeBeforeData(buffer); - NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR); + EXPECT_EQ(err, CHIP_NO_ERROR); // Should be able to send a message to itself by just calling send. err = udp.SendMessage(Transport::PeerAddress::UDP(addr, udp.GetBoundPort()), std::move(buffer)); - NL_TEST_ASSERT(inSuite, err == CHIP_NO_ERROR); + EXPECT_EQ(err, CHIP_NO_ERROR); - ctx.DriveIOUntil(chip::System::Clock::Seconds16(1), []() { return ReceiveHandlerCallCount != 0; }); + ctx->DriveIOUntil(chip::System::Clock::Seconds16(1), []() { return ReceiveHandlerCallCount != 0; }); - NL_TEST_ASSERT(inSuite, ReceiveHandlerCallCount == 1); + EXPECT_EQ(ReceiveHandlerCallCount, 1); } -void CheckMessageTest4(nlTestSuite * inSuite, void * inContext) +#if INET_CONFIG_ENABLE_IPV4 +TEST_F(TestUDP, CheckSimpleInitTest4) { - IPAddress addr; - IPAddress::FromString("127.0.0.1", addr); - CheckMessageTest(inSuite, inContext, addr); + CheckSimpleInitTest(inContext, IPAddressType::kIPv4); } -void CheckMessageTest6(nlTestSuite * inSuite, void * inContext) +TEST_F(TestUDP, CheckMessageTest4) { IPAddress addr; - IPAddress::FromString("::1", addr); - CheckMessageTest(inSuite, inContext, addr); + IPAddress::FromString("127.0.0.1", addr); + CheckMessageTest(inContext, addr); } - -// Test Suite - -/** - * Test Suite that lists all the test functions. - */ -// clang-format off -static const nlTest sTests[] = -{ -#if INET_CONFIG_ENABLE_IPV4 - NL_TEST_DEF("Simple Init Test IPV4", CheckSimpleInitTest4), - NL_TEST_DEF("Message Self Test IPV4", CheckMessageTest4), #endif - NL_TEST_DEF("Simple Init Test IPV6", CheckSimpleInitTest6), - NL_TEST_DEF("Message Self Test IPV6", CheckMessageTest6), - - NL_TEST_SENTINEL() -}; -// clang-format on - -// clang-format off -static nlTestSuite sSuite = -{ - "Test-CHIP-Udp", - &sTests[0], - Initialize, - Finalize -}; -// clang-format on - -/** - * Initialize the test suite. - */ -static int Initialize(void * aContext) -{ - CHIP_ERROR err = reinterpret_cast(aContext)->Init(); - return (err == CHIP_NO_ERROR) ? SUCCESS : FAILURE; -} - -/** - * Finalize the test suite. - */ -static int Finalize(void * aContext) +TEST_F(TestUDP, CheckSimpleInitTest6) { - reinterpret_cast(aContext)->Shutdown(); - return SUCCESS; + CheckSimpleInitTest(inContext, IPAddressType::kIPv6); } -int TestUDP() +TEST_F(TestUDP, CheckMessageTest6) { - return chip::ExecuteTestsWithContext(&sSuite); + IPAddress addr; + IPAddress::FromString("::1", addr); + CheckMessageTest(inContext, addr); } - -CHIP_REGISTER_TEST_SUITE(TestUDP); From cb7fd5a975ebb26ec508abaf9bcc8706c80228da Mon Sep 17 00:00:00 2001 From: chirag-silabs <100861685+chirag-silabs@users.noreply.github.com> Date: Tue, 30 Apr 2024 21:55:00 +0530 Subject: [PATCH 10/33] [Silabs][SiWx917] Adding the LED define for the 917 soc (#33228) * adding the led define for the 917 soc * Restyled by gn --------- Co-authored-by: Restyled.io --- third_party/silabs/SiWx917_sdk.gni | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/third_party/silabs/SiWx917_sdk.gni b/third_party/silabs/SiWx917_sdk.gni index 48abc728a4bf50..0819d7287bc9bc 100644 --- a/third_party/silabs/SiWx917_sdk.gni +++ b/third_party/silabs/SiWx917_sdk.gni @@ -282,7 +282,12 @@ template("siwx917_sdk") { # Enabling led interface if (use_wstk_leds) { - defines += [ "ENABLE_WSTK_LEDS" ] + defines += [ + "ENABLE_WSTK_LEDS", + + # TODO: remove this when it is added to the board config from wifi sdk + "SL_CATALOG_SIMPLE_LED_LED1_PRESENT", + ] } if (chip_enable_icd_server) { From f6bbfee37421b2fea075e1db56ab82f9a0c6a78d Mon Sep 17 00:00:00 2001 From: C Freeman Date: Tue, 30 Apr 2024 12:48:33 -0400 Subject: [PATCH 11/33] TC-DA-1.7: Use steps_function, add missing checks (#33117) * TC-DA-1.7: Use steps_function, add missing checks Also adding in a new flag that will let us use this test in post-cert (just introducing flag now, checks will be updated in an upcoming PR). * Restyled by autopep8 * Restyled by isort * Make error message more specific * whoops, missed some * Use the flag from setup --------- Co-authored-by: Restyled.io --- src/python_testing/TC_DA_1_7.py | 103 +++++++++++++++++++++++++------- 1 file changed, 81 insertions(+), 22 deletions(-) diff --git a/src/python_testing/TC_DA_1_7.py b/src/python_testing/TC_DA_1_7.py index 634dbb8885da2c..1d23883237eeeb 100644 --- a/src/python_testing/TC_DA_1_7.py +++ b/src/python_testing/TC_DA_1_7.py @@ -18,7 +18,7 @@ import logging from glob import glob from pathlib import Path -from typing import Optional +from typing import List, Optional import chip.clusters as Clusters from cryptography.exceptions import InvalidSignature @@ -26,7 +26,8 @@ from cryptography.hazmat.primitives.asymmetric import ec from cryptography.hazmat.primitives.serialization import Encoding, PublicFormat from cryptography.x509 import AuthorityKeyIdentifier, Certificate, SubjectKeyIdentifier, load_der_x509_certificate -from matter_testing_support import MatterBaseTest, async_test_body, bytes_from_hex, default_matter_test_main, hex_from_bytes +from matter_testing_support import (MatterBaseTest, TestStep, async_test_body, bytes_from_hex, default_matter_test_main, + hex_from_bytes) from mobly import asserts # Those are SDK samples that are known to be non-production. @@ -107,35 +108,84 @@ class TC_DA_1_7(MatterBaseTest): --script-args "--storage-path admin_storage.json --commissioning-method on-network \ --discriminator 12 34 --passcode 20202021 20202021 --bool-arg allow_sdk_dac:true" ''' + + def setup_class(self): + self.allow_sdk_dac = self.user_params.get("allow_sdk_dac", False) + self.post_cert_test = self.user_params.get("post_cert_test", False) + + def expected_number_of_DUTs(self) -> int: + return 1 if (self.allow_sdk_dac or self.post_cert_test) else 2 + + def steps_one_dut(self, DUT: int) -> List[TestStep]: + return [TestStep(f'{DUT}', f'Test DUT{DUT} DAC chain as follows:'), + TestStep(f'{DUT}.1', f'TH sends CertificateChainRequest Command to DUT{DUT} with the CertificateType set to PAICertificate', + 'Verify that the DUT returns a CertificateChainResponse. Save the returned Certificate as `pai_cert`.'), + TestStep(f'{DUT}.2', 'TH sends CertificateChainRequest Command to DUT1 with the CertificateType set to DACCertificate', + 'Verify that the DUT returns a CertificateChainResponse. Save the returned Certificate as `dac_cert`.'), + TestStep(f'{DUT}.3', 'TH extracts the Authority Key Identifier from the PAI certificate', + ('* Verify that the Authority Key Identifier is signed by a PAA in the DCL. (Ensure that it is not SDK’s test PAAs)\n' + '* Verify that PAI authority key ID must not be one of:\n' + ' - 78: 5C: E7: 05: B8: 6B: 8F: 4E: 6F: C7: 93: AA: 60: CB: 43: EA: 69: 68:82: D5\n' + ' - 6A: FD: 22: 77: 1F: 51: 1F: EC: BF: 16: 41: 97: 67: 10: DC: DC: 31: A1: 71: 7E\n' + '* Save the selected PAA certificate as `paa_cert`\n')), + TestStep(f'{DUT}.4', 'TH extracts ASN.1 DER bytes for the entire issuer field of `dac_cert` and subject field of `pai_cert`.', + 'Verify that the `dac_cert` `issuer field is byte-forbyte equivalent to the `pai_cert`subject field.'), + TestStep(f'{DUT}.5', 'TH extracts ASN.1 DER bytes for the entire issuer field of `pai_cert` and subject field of `paa_cert`.', + 'Verify that the `pai_cert` issuer field is byte-forbyte equivalent to the `paa_cert` subject field.'), + TestStep(f'{DUT}.6', f'TH extracts the public key from the DAC and saves as `pk_{DUT}`.') + ] + + def steps_TC_DA_1_7(self): + steps = [TestStep(0, "Commission DUT if not already done", is_commissioning=True)] + steps += self.steps_one_dut(1) + if self.expected_number_of_DUTs() == 2: + steps += self.steps_one_dut(2) + steps += [TestStep(3, "Verify that `pk_1` is not equal to `pk_2", + "Public keys do not match")] + return steps + @async_test_body async def test_TC_DA_1_7(self): - # For real tests, we require more than one DUT - # On the CI, this doesn't make sense to do since all the examples use the same DAC - # To specify more than 1 DUT, use a list of discriminators and passcodes - allow_sdk_dac = self.user_params.get("allow_sdk_dac", False) - if allow_sdk_dac: - asserts.assert_equal(len(self.matter_test_config.discriminators), 1, "Only one device can be tested with SDK DAC") - if not allow_sdk_dac: - asserts.assert_equal(len(self.matter_test_config.discriminators), 2, "This test requires 2 DUTs") + # post_cert_tests (or sdk) can use the qr or manual code + # We don't currently support this in cert because the base doesn't support multiple QR/manual + num = 0 + if self.matter_test_config.discriminators: + num += len(self.matter_test_config.discriminators) + if self.matter_test_config.qr_code_content: + num += 1 + if self.matter_test_config.manual_code: + num += 1 + + if num != self.expected_number_of_DUTs(): + if self.allow_sdk_dac: + msg = "The allow_sdk_dac flag is only for use in CI. When using this test in CI, please specify a single discriminator, manual-code or qr-code-content" + elif self.post_cert_test: + msg = "The post_cert_test flag is only for use post-certification. When using this flag, please specify a single discriminator, manual-code or qr-code-content" + else: + msg = "This test requires two devices for use at certification. Please specify two device discriminators ex. --discriminator 1234 5678" + asserts.fail(msg) + pk = [] + # Commissioning - already done. + self.step(0) + for i in range(len(self.matter_test_config.dut_node_ids)): - pk.append(await self.single_DUT(i, self.matter_test_config.dut_node_ids[i])) + pk.append(await self.single_DUT(i+1, self.matter_test_config.dut_node_ids[i])) + self.step(3) asserts.assert_equal(len(pk), len(set(pk)), "Found matching public keys in different DUTs") async def single_DUT(self, dut_index: int, dut_node_id: int) -> bytes: - # Option to allow SDK roots (skip step 4 check 2) - allow_sdk_dac = self.user_params.get("allow_sdk_dac", False) - logging.info("Pre-condition: load all PAAs SKIDs") conf = self.matter_test_config paa_by_skid = load_all_paa(conf.paa_trust_store_path) logging.info("Found %d PAAs" % len(paa_by_skid)) - logging.info("DUT {} Step 1: Commissioning, already done".format(dut_index)) + # Test plan step introducing test for each DUT + self.step(f'{dut_index}') dev_ctrl = self.default_controller - logging.info("DUT {} Step 2: Get PAI of DUT1 with certificate chain request".format(dut_index)) + self.step(f'{dut_index}.1') result = await dev_ctrl.SendCommand(dut_node_id, 0, Clusters.OperationalCredentials.Commands.CertificateChainRequest(2)) pai = result.certificate @@ -143,7 +193,7 @@ async def single_DUT(self, dut_index: int, dut_node_id: int) -> bytes: key = 'pai_{}'.format(dut_index) self.record_data({key: hex_from_bytes(pai)}) - logging.info("DUT {} Step 3: Get DAC of DUT1 with certificate chain request".format(dut_index)) + self.step(f'{dut_index}.2') result = await dev_ctrl.SendCommand(dut_node_id, 0, Clusters.OperationalCredentials.Commands.CertificateChainRequest(1)) dac = result.certificate @@ -151,7 +201,8 @@ async def single_DUT(self, dut_index: int, dut_node_id: int) -> bytes: key = 'dac_{}'.format(dut_index) self.record_data({key: hex_from_bytes(dac)}) - logging.info("DUT {} Step 4 check 1: Ensure PAI's AKID matches a PAA and signature is valid".format(dut_index)) + self.step(f'{dut_index}.3') + logging.info("DUT {} Step 3 check 1: Ensure PAI's AKID matches a PAA and signature is valid".format(dut_index)) pai_cert = load_der_x509_certificate(pai) pai_akid = extract_akid(pai_cert) if pai_akid not in paa_by_skid: @@ -168,15 +219,23 @@ async def single_DUT(self, dut_index: int, dut_node_id: int) -> bytes: asserts.fail("DUT %d: Failed to verify PAI signature against PAA public key: %s" % (dut_index, str(e))) logging.info("Validated PAI signature against PAA") - logging.info("DUT {} Step 4 check 2: Verify PAI AKID not in denylist of SDK PAIs".format(dut_index)) - if allow_sdk_dac: - logging.warn("===> TEST STEP SKIPPED: Allowing SDK DACs!") + logging.info("DUT {} Step 3 check 2: Verify PAI AKID not in denylist of SDK PAIs".format(dut_index)) + if self.allow_sdk_dac: + logging.warning("===> TEST STEP SKIPPED: Allowing SDK DACs!") else: for candidate in FORBIDDEN_AKID: asserts.assert_not_equal(hex_from_bytes(pai_akid), hex_from_bytes(candidate), "PAI AKID must not be in denylist") - logging.info("DUT {} Step 5: Extract subject public key of DAC and save".format(dut_index)) + self.step(f'{dut_index}.4') + # dac issuer == pai subject dac_cert = load_der_x509_certificate(dac) + asserts.assert_equal(dac_cert.issuer, pai_cert.subject, "DAC issuer does not match PAI subject") + + self.step(f'{dut_index}.5') + # pai issues == paa subject + asserts.assert_equal(pai_cert.issuer, paa_cert.subject, "PAI issuer does not match PAA subject") + + self.step(f'{dut_index}.6') pk = dac_cert.public_key().public_bytes(encoding=Encoding.X962, format=PublicFormat.UncompressedPoint) logging.info("Subject public key pk: %s" % hex_from_bytes(pk)) key = 'pk_{}'.format(dut_index) From 9ed9c724daef1ebd99548a2ea6e0da02a8ed177f Mon Sep 17 00:00:00 2001 From: Andrei Litvin Date: Tue, 30 Apr 2024 12:53:56 -0400 Subject: [PATCH 12/33] [chore] Replace all usages of chip::Optional with std::optional in src/lib/dnssd (#33200) * std optional in recordwriter * Fix a call * Change some advertiser.h to std::optional * Fix usage in advertiser.cpp * Make more things compile * Restyle * make clang-tidy happy * Replace chip optional from active resolveattempts * Fix platform dns * More test fixes * Fix one more compile to not have optional at all in dnssd * Restyle * Add back removed header * Some compile fixes for IP address * more compile fixes - tested that qpg thermostat compiles for me now * Fix tizen build * Commissioner passcode fix * make clang-tidy happy * Use references for MRPConfig optionals, as the mrpconfig may be larger * Reduce scope of optional usage * Use references everywhere for Advertiser * One more use of a reference * One more const reference passing to try to reduce code size * Restyle * Attempt to make clang-tidy happy in unit tst * Disable the check via a nolint * Code review: use C++17 if initializers to scope out temporary optional values * Use a few more references * Apply code review comment * Undo return as reference changes in getters for optional --------- Co-authored-by: Andrei Litvin --- examples/minimal-mdns/advertiser.cpp | 29 +-- src/app/server/Dnssd.cpp | 28 +-- src/lib/dnssd/ActiveResolveAttempts.cpp | 18 +- src/lib/dnssd/ActiveResolveAttempts.h | 6 +- src/lib/dnssd/Advertiser.h | 74 ++++---- src/lib/dnssd/Advertiser_ImplMinimalMdns.cpp | 65 +++---- src/lib/dnssd/Discovery_ImplPlatform.cpp | 44 ++--- src/lib/dnssd/Resolver.h | 10 +- src/lib/dnssd/Resolver_ImplMinimalMdns.cpp | 14 +- .../dnssd/minimal_mdns/core/RecordWriter.cpp | 12 +- .../dnssd/minimal_mdns/core/RecordWriter.h | 9 +- .../minimal_mdns/tests/TestAdvertiser.cpp | 46 ++--- src/lib/dnssd/platform/Dnssd.h | 4 +- src/lib/dnssd/platform/tests/TestPlatform.cpp | 46 ++--- .../dnssd/tests/TestActiveResolveAttempts.cpp | 175 +++++++++--------- ...nericThreadStackManagerImpl_OpenThread.hpp | 8 +- src/platform/Tizen/DnssdImpl.cpp | 4 +- src/platform/nxp/common/DnssdImpl.cpp | 4 +- 18 files changed, 304 insertions(+), 292 deletions(-) diff --git a/examples/minimal-mdns/advertiser.cpp b/examples/minimal-mdns/advertiser.cpp index 9d2f90c7858e00..6e260257301324 100644 --- a/examples/minimal-mdns/advertiser.cpp +++ b/examples/minimal-mdns/advertiser.cpp @@ -16,6 +16,7 @@ */ #include #include +#include #include #include @@ -45,18 +46,18 @@ struct Options AdvertisingMode advertisingMode = AdvertisingMode::kCommissionableNode; // commissionable node / commissioner params - Optional vendorId; - Optional productId; - Optional deviceType; - Optional deviceName; + std::optional vendorId; + std::optional productId; + std::optional deviceType; + std::optional deviceName; // commissionable node params uint8_t shortDiscriminator = 52; uint16_t longDiscriminator = 840; Dnssd::CommissioningMode commissioningMode = Dnssd::CommissioningMode::kDisabled; - Optional rotatingId; - Optional pairingInstr; - Optional pairingHint; + std::optional rotatingId; + std::optional pairingInstr; + std::optional pairingHint; // operational params uint64_t fabricId = 12345; @@ -130,10 +131,10 @@ bool HandleOptions(const char * aProgram, OptionSet * aOptions, int aIdentifier, gOptions.longDiscriminator = static_cast(atoi(aValue)); return true; case kOptionCommissioningVendorId: - gOptions.vendorId = Optional::Value(static_cast(atoi(aValue))); + gOptions.vendorId = std::make_optional(static_cast(atoi(aValue))); return true; case kOptionCommissioningProductId: - gOptions.productId = Optional::Value(static_cast(atoi(aValue))); + gOptions.productId = std::make_optional(static_cast(atoi(aValue))); return true; case kOptionCommissioningMode: cm = static_cast(atoi(aValue)); @@ -147,19 +148,19 @@ bool HandleOptions(const char * aProgram, OptionSet * aOptions, int aIdentifier, } return true; case kOptionCommissioningDeviceType: - gOptions.deviceType = Optional::Value(static_cast(atoi(aValue))); + gOptions.deviceType = std::make_optional(static_cast(atoi(aValue))); return true; case kOptionCommissioningDeviceName: - gOptions.deviceName = Optional::Value(static_cast(aValue)); + gOptions.deviceName = std::make_optional(static_cast(aValue)); return true; case kOptionCommissioningRotatingId: - gOptions.rotatingId = Optional::Value(static_cast(aValue)); + gOptions.rotatingId = std::make_optional(static_cast(aValue)); return true; case kOptionCommissioningPairingInstr: - gOptions.pairingInstr = Optional::Value(static_cast(aValue)); + gOptions.pairingInstr = std::make_optional(static_cast(aValue)); return true; case kOptionCommissioningPairingHint: - gOptions.pairingHint = Optional::Value(static_cast(atoi(aValue))); + gOptions.pairingHint = std::make_optional(static_cast(atoi(aValue))); return true; case kOptionOperationalFabricId: if (sscanf(aValue, "%" SCNx64, &gOptions.fabricId) != 1) diff --git a/src/app/server/Dnssd.cpp b/src/app/server/Dnssd.cpp index 3df796434e2671..3cdcd35f9a7e98 100644 --- a/src/app/server/Dnssd.cpp +++ b/src/app/server/Dnssd.cpp @@ -206,7 +206,7 @@ CHIP_ERROR DnssdServer::AdvertiseOperational() .SetMac(mac) .SetPort(GetSecuredPort()) .SetInterfaceId(GetInterfaceId()) - .SetLocalMRPConfig(GetLocalMRPConfig()) + .SetLocalMRPConfig(GetLocalMRPConfig().std_optional()) .EnableIpV4(true); #if CHIP_CONFIG_ENABLE_ICD_SERVER @@ -251,7 +251,7 @@ CHIP_ERROR DnssdServer::Advertise(bool commissionableNode, chip::Dnssd::Commissi } else { - advertiseParameters.SetVendorId(chip::Optional::Value(value)); + advertiseParameters.SetVendorId(std::make_optional(value)); } if (DeviceLayer::GetDeviceInstanceInfoProvider()->GetProductId(value) != CHIP_NO_ERROR) @@ -260,23 +260,23 @@ CHIP_ERROR DnssdServer::Advertise(bool commissionableNode, chip::Dnssd::Commissi } else { - advertiseParameters.SetProductId(chip::Optional::Value(value)); + advertiseParameters.SetProductId(std::make_optional(value)); } if (DeviceLayer::ConfigurationMgr().IsCommissionableDeviceTypeEnabled() && DeviceLayer::ConfigurationMgr().GetDeviceTypeId(val32) == CHIP_NO_ERROR) { - advertiseParameters.SetDeviceType(chip::Optional::Value(val32)); + advertiseParameters.SetDeviceType(std::make_optional(val32)); } char deviceName[chip::Dnssd::kKeyDeviceNameMaxLength + 1]; if (DeviceLayer::ConfigurationMgr().IsCommissionableDeviceNameEnabled() && DeviceLayer::ConfigurationMgr().GetCommissionableDeviceName(deviceName, sizeof(deviceName)) == CHIP_NO_ERROR) { - advertiseParameters.SetDeviceName(chip::Optional::Value(deviceName)); + advertiseParameters.SetDeviceName(std::make_optional(deviceName)); } - advertiseParameters.SetLocalMRPConfig(GetLocalMRPConfig()); + advertiseParameters.SetLocalMRPConfig(GetLocalMRPConfig().std_optional()); #if CHIP_CONFIG_ENABLE_ICD_SERVER AddICDKeyToAdvertisement(advertiseParameters); @@ -303,7 +303,7 @@ CHIP_ERROR DnssdServer::Advertise(bool commissionableNode, chip::Dnssd::Commissi #if CHIP_ENABLE_ROTATING_DEVICE_ID && defined(CHIP_DEVICE_CONFIG_ROTATING_DEVICE_ID_UNIQUE_ID) char rotatingDeviceIdHexBuffer[RotatingDeviceId::kHexMaxLength]; ReturnErrorOnFailure(GenerateRotatingDeviceId(rotatingDeviceIdHexBuffer, ArraySize(rotatingDeviceIdHexBuffer))); - advertiseParameters.SetRotatingDeviceId(chip::Optional::Value(rotatingDeviceIdHexBuffer)); + advertiseParameters.SetRotatingDeviceId(std::make_optional(rotatingDeviceIdHexBuffer)); #endif if (!HaveOperationalCredentials()) @@ -314,7 +314,7 @@ CHIP_ERROR DnssdServer::Advertise(bool commissionableNode, chip::Dnssd::Commissi } else { - advertiseParameters.SetPairingHint(chip::Optional::Value(value)); + advertiseParameters.SetPairingHint(std::make_optional(value)); } if (DeviceLayer::ConfigurationMgr().GetInitialPairingInstruction(pairingInst, sizeof(pairingInst)) != CHIP_NO_ERROR) @@ -323,7 +323,7 @@ CHIP_ERROR DnssdServer::Advertise(bool commissionableNode, chip::Dnssd::Commissi } else { - advertiseParameters.SetPairingInstruction(chip::Optional::Value(pairingInst)); + advertiseParameters.SetPairingInstruction(std::make_optional(pairingInst)); } } else @@ -334,7 +334,7 @@ CHIP_ERROR DnssdServer::Advertise(bool commissionableNode, chip::Dnssd::Commissi } else { - advertiseParameters.SetPairingHint(chip::Optional::Value(value)); + advertiseParameters.SetPairingHint(std::make_optional(value)); } if (DeviceLayer::ConfigurationMgr().GetSecondaryPairingInstruction(pairingInst, sizeof(pairingInst)) != CHIP_NO_ERROR) @@ -343,24 +343,24 @@ CHIP_ERROR DnssdServer::Advertise(bool commissionableNode, chip::Dnssd::Commissi } else { - advertiseParameters.SetPairingInstruction(chip::Optional::Value(pairingInst)); + advertiseParameters.SetPairingInstruction(std::make_optional(pairingInst)); } } } #if CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONER_PASSCODE else { - advertiseParameters.SetCommissionerPasscodeSupported(Optional(true)); + advertiseParameters.SetCommissionerPasscodeSupported(std::make_optional(true)); } #endif auto & mdnsAdvertiser = chip::Dnssd::ServiceAdvertiser::Instance(); ChipLogProgress(Discovery, "Advertise commission parameter vendorID=%u productID=%u discriminator=%04u/%02u cm=%u cp=%u", - advertiseParameters.GetVendorId().ValueOr(0), advertiseParameters.GetProductId().ValueOr(0), + advertiseParameters.GetVendorId().value_or(0), advertiseParameters.GetProductId().value_or(0), advertiseParameters.GetLongDiscriminator(), advertiseParameters.GetShortDiscriminator(), to_underlying(advertiseParameters.GetCommissioningMode()), - advertiseParameters.GetCommissionerPasscodeSupported().ValueOr(false) ? 1 : 0); + advertiseParameters.GetCommissionerPasscodeSupported().value_or(false) ? 1 : 0); return mdnsAdvertiser.Advertise(advertiseParameters); } diff --git a/src/lib/dnssd/ActiveResolveAttempts.cpp b/src/lib/dnssd/ActiveResolveAttempts.cpp index f49056896e0b2e..f8f351d85cf05e 100644 --- a/src/lib/dnssd/ActiveResolveAttempts.cpp +++ b/src/lib/dnssd/ActiveResolveAttempts.cpp @@ -218,9 +218,9 @@ void ActiveResolveAttempts::MarkPending(ScheduledAttempt && attempt) entryToUse->nextRetryDelay = System::Clock::Seconds16(1); } -Optional ActiveResolveAttempts::GetTimeUntilNextExpectedResponse() const +std::optional ActiveResolveAttempts::GetTimeUntilNextExpectedResponse() const { - Optional minDelay = Optional::Missing(); + std::optional minDelay = std::nullopt; chip::System::Clock::Timestamp now = mClock->GetMonotonicTimestamp(); @@ -234,20 +234,20 @@ Optional ActiveResolveAttempts::GetTimeUntilNextExpected if (now >= entry.queryDueTime) { // found an entry that needs processing right now - return Optional::Value(0); + return std::make_optional(0); } System::Clock::Timeout entryDelay = entry.queryDueTime - now; - if (!minDelay.HasValue() || (minDelay.Value() > entryDelay)) + if (!minDelay.has_value() || (*minDelay > entryDelay)) { - minDelay.SetValue(entryDelay); + minDelay.emplace(entryDelay); } } return minDelay; } -Optional ActiveResolveAttempts::NextScheduled() +std::optional ActiveResolveAttempts::NextScheduled() { chip::System::Clock::Timestamp now = mClock->GetMonotonicTimestamp(); @@ -273,13 +273,13 @@ Optional ActiveResolveAttempts::NextSch entry.queryDueTime = now + entry.nextRetryDelay; entry.nextRetryDelay *= 2; - Optional attempt = MakeOptional(entry.attempt); - entry.attempt.firstSend = false; + std::optional attempt = std::make_optional(entry.attempt); + entry.attempt.firstSend = false; return attempt; } - return Optional::Missing(); + return std::nullopt; } bool ActiveResolveAttempts::ShouldResolveIpAddress(PeerId peerId) const diff --git a/src/lib/dnssd/ActiveResolveAttempts.h b/src/lib/dnssd/ActiveResolveAttempts.h index 55790bd1e3821e..157790b531c3e7 100644 --- a/src/lib/dnssd/ActiveResolveAttempts.h +++ b/src/lib/dnssd/ActiveResolveAttempts.h @@ -19,8 +19,8 @@ #include #include +#include -#include #include #include #include @@ -273,7 +273,7 @@ class ActiveResolveAttempts // Get minimum time until the next pending reply is required. // // Returns missing if no actively tracked elements exist. - chip::Optional GetTimeUntilNextExpectedResponse() const; + std::optional GetTimeUntilNextExpectedResponse() const; // Get the peer Id that needs scheduling for a query // @@ -283,7 +283,7 @@ class ActiveResolveAttempts // now' // - there is NO sorting implied by this call. Returned value will be // any peer that needs a new request sent - chip::Optional NextScheduled(); + std::optional NextScheduled(); /// Check if any of the pending queries are for the given host name for /// IP resolution. diff --git a/src/lib/dnssd/Advertiser.h b/src/lib/dnssd/Advertiser.h index 64fa9ec3fd5d33..02888181f98181 100644 --- a/src/lib/dnssd/Advertiser.h +++ b/src/lib/dnssd/Advertiser.h @@ -19,9 +19,9 @@ #include #include +#include #include -#include #include #include #include @@ -95,20 +95,20 @@ class BaseAdvertisingParams const chip::ByteSpan GetMac() const { return chip::ByteSpan(mMacStorage, mMacLength); } // Common Flags - Derived & SetLocalMRPConfig(const Optional & config) + Derived & SetLocalMRPConfig(const std::optional & config) { mLocalMRPConfig = config; return *reinterpret_cast(this); } - const Optional & GetLocalMRPConfig() const { return mLocalMRPConfig; } + const std::optional & GetLocalMRPConfig() const { return mLocalMRPConfig; } // NOTE: The SetTcpSupported API is deprecated and not compliant with 1.3. T flag should not be set. - Derived & SetTcpSupported(Optional tcpSupported) + Derived & SetTcpSupported(std::optional tcpSupported) { mTcpSupported = tcpSupported; return *reinterpret_cast(this); } - Optional GetTcpSupported() const { return mTcpSupported; } + std::optional GetTcpSupported() const { return mTcpSupported; } Derived & SetICDModeToAdvertise(ICDModeAdvertise operatingMode) { @@ -123,8 +123,8 @@ class BaseAdvertisingParams bool mEnableIPv4 = true; uint8_t mMacStorage[kMaxMacSize] = {}; size_t mMacLength = 0; - Optional mLocalMRPConfig; - Optional mTcpSupported; + std::optional mLocalMRPConfig; + std::optional mTcpSupported; ICDModeAdvertise mICDModeAdvertise = ICDModeAdvertise::kNone; }; @@ -176,19 +176,19 @@ class CommissionAdvertisingParameters : public BaseAdvertisingParams vendorId) + CommissionAdvertisingParameters & SetVendorId(std::optional vendorId) { mVendorId = vendorId; return *this; } - Optional GetVendorId() const { return mVendorId; } + std::optional GetVendorId() const { return mVendorId; } - CommissionAdvertisingParameters & SetProductId(Optional productId) + CommissionAdvertisingParameters & SetProductId(std::optional productId) { mProductId = productId; return *this; } - Optional GetProductId() const { return mProductId; } + std::optional GetProductId() const { return mProductId; } CommissionAdvertisingParameters & SetCommissioningMode(CommissioningMode mode) { @@ -197,18 +197,18 @@ class CommissionAdvertisingParameters : public BaseAdvertisingParams deviceType) + CommissionAdvertisingParameters & SetDeviceType(std::optional deviceType) { mDeviceType = deviceType; return *this; } - Optional GetDeviceType() const { return mDeviceType; } + std::optional GetDeviceType() const { return mDeviceType; } - CommissionAdvertisingParameters & SetDeviceName(Optional deviceName) + CommissionAdvertisingParameters & SetDeviceName(std::optional deviceName) { - if (deviceName.HasValue()) + if (deviceName.has_value()) { - Platform::CopyString(mDeviceName, sizeof(mDeviceName), deviceName.Value()); + Platform::CopyString(mDeviceName, sizeof(mDeviceName), *deviceName); mDeviceNameHasValue = true; } else @@ -217,16 +217,16 @@ class CommissionAdvertisingParameters : public BaseAdvertisingParams GetDeviceName() const + std::optional GetDeviceName() const { - return mDeviceNameHasValue ? Optional::Value(mDeviceName) : Optional::Missing(); + return mDeviceNameHasValue ? std::make_optional(mDeviceName) : std::nullopt; } - CommissionAdvertisingParameters & SetRotatingDeviceId(Optional rotatingId) + CommissionAdvertisingParameters & SetRotatingDeviceId(std::optional rotatingId) { - if (rotatingId.HasValue()) + if (rotatingId.has_value()) { - Platform::CopyString(mRotatingId, sizeof(mRotatingId), rotatingId.Value()); + Platform::CopyString(mRotatingId, sizeof(mRotatingId), *rotatingId); mRotatingIdHasValue = true; } else @@ -235,16 +235,16 @@ class CommissionAdvertisingParameters : public BaseAdvertisingParams GetRotatingDeviceId() const + std::optional GetRotatingDeviceId() const { - return mRotatingIdHasValue ? Optional::Value(mRotatingId) : Optional::Missing(); + return mRotatingIdHasValue ? std::make_optional(mRotatingId) : std::nullopt; } - CommissionAdvertisingParameters & SetPairingInstruction(Optional pairingInstr) + CommissionAdvertisingParameters & SetPairingInstruction(std::optional pairingInstr) { - if (pairingInstr.HasValue()) + if (pairingInstr.has_value()) { - Platform::CopyString(mPairingInstr, sizeof(mPairingInstr), pairingInstr.Value()); + Platform::CopyString(mPairingInstr, sizeof(mPairingInstr), *pairingInstr); mPairingInstrHasValue = true; } else @@ -253,17 +253,17 @@ class CommissionAdvertisingParameters : public BaseAdvertisingParams GetPairingInstruction() const + std::optional GetPairingInstruction() const { - return mPairingInstrHasValue ? Optional::Value(mPairingInstr) : Optional::Missing(); + return mPairingInstrHasValue ? std::make_optional(mPairingInstr) : std::nullopt; } - CommissionAdvertisingParameters & SetPairingHint(Optional pairingHint) + CommissionAdvertisingParameters & SetPairingHint(std::optional pairingHint) { mPairingHint = pairingHint; return *this; } - Optional GetPairingHint() const { return mPairingHint; } + std::optional GetPairingHint() const { return mPairingHint; } CommissionAdvertisingParameters & SetCommissionAdvertiseMode(CommssionAdvertiseMode mode) { @@ -272,22 +272,22 @@ class CommissionAdvertisingParameters : public BaseAdvertisingParams commissionerPasscodeSupported) + CommissionAdvertisingParameters & SetCommissionerPasscodeSupported(std::optional commissionerPasscodeSupported) { mCommissionerPasscodeSupported = commissionerPasscodeSupported; return *this; } - Optional GetCommissionerPasscodeSupported() const { return mCommissionerPasscodeSupported; } + std::optional GetCommissionerPasscodeSupported() const { return mCommissionerPasscodeSupported; } private: uint8_t mShortDiscriminator = 0; uint16_t mLongDiscriminator = 0; // 12-bit according to spec CommssionAdvertiseMode mMode = CommssionAdvertiseMode::kCommissionableNode; CommissioningMode mCommissioningMode = CommissioningMode::kEnabledBasic; - chip::Optional mVendorId; - chip::Optional mProductId; - chip::Optional mDeviceType; - chip::Optional mPairingHint; + std::optional mVendorId; + std::optional mProductId; + std::optional mDeviceType; + std::optional mPairingHint; char mDeviceName[kKeyDeviceNameMaxLength + 1]; bool mDeviceNameHasValue = false; @@ -298,7 +298,7 @@ class CommissionAdvertisingParameters : public BaseAdvertisingParams mCommissionerPasscodeSupported; + std::optional mCommissionerPasscodeSupported; }; /** diff --git a/src/lib/dnssd/Advertiser_ImplMinimalMdns.cpp b/src/lib/dnssd/Advertiser_ImplMinimalMdns.cpp index e25487f781860f..5ca002673cd4c9 100644 --- a/src/lib/dnssd/Advertiser_ImplMinimalMdns.cpp +++ b/src/lib/dnssd/Advertiser_ImplMinimalMdns.cpp @@ -226,11 +226,10 @@ class AdvertiserMinMdns : public ServiceAdvertiser, CHIP_ERROR AddCommonTxtEntries(const BaseAdvertisingParams & params, CommonTxtEntryStorage & storage, char ** txtFields, size_t & numTxtFields) { - auto optionalMrp = params.GetLocalMRPConfig(); - if (optionalMrp.HasValue()) + if (const auto & optionalMrp = params.GetLocalMRPConfig(); optionalMrp.has_value()) { - auto mrp = optionalMrp.Value(); + auto mrp = *optionalMrp; // An ICD operating as a LIT shall not advertise its slow polling interval. // Don't include the SII key in the advertisement when operating as so. @@ -278,14 +277,16 @@ class AdvertiserMinMdns : public ServiceAdvertiser, txtFields[numTxtFields++] = storage.sessionActiveThresholdBuf; } } - if (params.GetTcpSupported().HasValue()) + + if (const auto & tcpSupported = params.GetTcpSupported(); tcpSupported.has_value()) { - size_t writtenCharactersNumber = static_cast( - snprintf(storage.tcpSupportedBuf, sizeof(storage.tcpSupportedBuf), "T=%d", params.GetTcpSupported().Value())); + size_t writtenCharactersNumber = + static_cast(snprintf(storage.tcpSupportedBuf, sizeof(storage.tcpSupportedBuf), "T=%d", *tcpSupported)); VerifyOrReturnError((writtenCharactersNumber > 0) && (writtenCharactersNumber < sizeof(storage.tcpSupportedBuf)), CHIP_ERROR_INVALID_STRING_LENGTH); txtFields[numTxtFields++] = storage.tcpSupportedBuf; } + if (params.GetICDModeToAdvertise() != ICDModeAdvertise::kNone) { size_t writtenCharactersNumber = @@ -670,10 +671,9 @@ CHIP_ERROR AdvertiserMinMdns::Advertise(const CommissionAdvertisingParameters & } } - if (params.GetVendorId().HasValue()) + if (const auto & vendorId = params.GetVendorId(); vendorId.has_value()) { - MakeServiceSubtype(nameBuffer, sizeof(nameBuffer), - DiscoveryFilter(DiscoveryFilterType::kVendorId, params.GetVendorId().Value())); + MakeServiceSubtype(nameBuffer, sizeof(nameBuffer), DiscoveryFilter(DiscoveryFilterType::kVendorId, *vendorId)); FullQName vendorServiceName = allocator->AllocateQName(nameBuffer, kSubtypeServiceNamePart, serviceType, kCommissionProtocol, kLocalDomain); ReturnErrorCodeIf(vendorServiceName.nameCount == 0, CHIP_ERROR_NO_MEMORY); @@ -688,10 +688,9 @@ CHIP_ERROR AdvertiserMinMdns::Advertise(const CommissionAdvertisingParameters & } } - if (params.GetDeviceType().HasValue()) + if (const auto & deviceType = params.GetDeviceType(); deviceType.has_value()) { - MakeServiceSubtype(nameBuffer, sizeof(nameBuffer), - DiscoveryFilter(DiscoveryFilterType::kDeviceType, params.GetDeviceType().Value())); + MakeServiceSubtype(nameBuffer, sizeof(nameBuffer), DiscoveryFilter(DiscoveryFilterType::kDeviceType, *deviceType)); FullQName vendorServiceName = allocator->AllocateQName(nameBuffer, kSubtypeServiceNamePart, serviceType, kCommissionProtocol, kLocalDomain); ReturnErrorCodeIf(vendorServiceName.nameCount == 0, CHIP_ERROR_NO_MEMORY); @@ -812,28 +811,32 @@ FullQName AdvertiserMinMdns::GetCommissioningTxtEntries(const CommissionAdvertis : &mQueryResponderAllocatorCommissioner; char txtVidPid[chip::Dnssd::kKeyVendorProductMaxLength + 4]; - if (params.GetProductId().HasValue() && params.GetVendorId().HasValue()) - { - snprintf(txtVidPid, sizeof(txtVidPid), "VP=%d+%d", params.GetVendorId().Value(), params.GetProductId().Value()); - txtFields[numTxtFields++] = txtVidPid; - } - else if (params.GetVendorId().HasValue()) { - snprintf(txtVidPid, sizeof(txtVidPid), "VP=%d", params.GetVendorId().Value()); - txtFields[numTxtFields++] = txtVidPid; + const auto & productId = params.GetProductId(); + const auto & vendorId = params.GetVendorId(); + if (productId.has_value() && vendorId.has_value()) + { + snprintf(txtVidPid, sizeof(txtVidPid), "VP=%d+%d", *vendorId, *productId); + txtFields[numTxtFields++] = txtVidPid; + } + else if (vendorId.has_value()) + { + snprintf(txtVidPid, sizeof(txtVidPid), "VP=%d", *vendorId); + txtFields[numTxtFields++] = txtVidPid; + } } char txtDeviceType[chip::Dnssd::kKeyDeviceTypeMaxLength + 4]; - if (params.GetDeviceType().HasValue()) + if (const auto & deviceType = params.GetDeviceType(); deviceType.has_value()) { - snprintf(txtDeviceType, sizeof(txtDeviceType), "DT=%" PRIu32, params.GetDeviceType().Value()); + snprintf(txtDeviceType, sizeof(txtDeviceType), "DT=%" PRIu32, *deviceType); txtFields[numTxtFields++] = txtDeviceType; } char txtDeviceName[chip::Dnssd::kKeyDeviceNameMaxLength + 4]; - if (params.GetDeviceName().HasValue()) + if (const auto & deviceName = params.GetDeviceName(); deviceName.has_value()) { - snprintf(txtDeviceName, sizeof(txtDeviceName), "DN=%s", params.GetDeviceName().Value()); + snprintf(txtDeviceName, sizeof(txtDeviceName), "DN=%s", *deviceName); txtFields[numTxtFields++] = txtDeviceName; } CommonTxtEntryStorage commonStorage; @@ -858,27 +861,27 @@ FullQName AdvertiserMinMdns::GetCommissioningTxtEntries(const CommissionAdvertis snprintf(txtCommissioningMode, sizeof(txtCommissioningMode), "CM=%d", static_cast(params.GetCommissioningMode())); txtFields[numTxtFields++] = txtCommissioningMode; - if (params.GetRotatingDeviceId().HasValue()) + if (const auto & rotatingDeviceId = params.GetRotatingDeviceId(); rotatingDeviceId.has_value()) { - snprintf(txtRotatingDeviceId, sizeof(txtRotatingDeviceId), "RI=%s", params.GetRotatingDeviceId().Value()); + snprintf(txtRotatingDeviceId, sizeof(txtRotatingDeviceId), "RI=%s", *rotatingDeviceId); txtFields[numTxtFields++] = txtRotatingDeviceId; } - if (params.GetPairingHint().HasValue()) + if (const auto & pairingHint = params.GetPairingHint(); pairingHint.has_value()) { - snprintf(txtPairingHint, sizeof(txtPairingHint), "PH=%d", params.GetPairingHint().Value()); + snprintf(txtPairingHint, sizeof(txtPairingHint), "PH=%d", *pairingHint); txtFields[numTxtFields++] = txtPairingHint; } - if (params.GetPairingInstruction().HasValue()) + if (const auto & pairingInstruction = params.GetPairingInstruction(); pairingInstruction.has_value()) { - snprintf(txtPairingInstr, sizeof(txtPairingInstr), "PI=%s", params.GetPairingInstruction().Value()); + snprintf(txtPairingInstr, sizeof(txtPairingInstr), "PI=%s", *pairingInstruction); txtFields[numTxtFields++] = txtPairingInstr; } } else { - if (params.GetCommissionerPasscodeSupported().ValueOr(false)) + if (params.GetCommissionerPasscodeSupported().value_or(false)) { snprintf(txtCommissionerPasscode, sizeof(txtCommissionerPasscode), "CP=%d", static_cast(1)); txtFields[numTxtFields++] = txtCommissionerPasscode; diff --git a/src/lib/dnssd/Discovery_ImplPlatform.cpp b/src/lib/dnssd/Discovery_ImplPlatform.cpp index 2b6b6cd470c618..f4a524f2c81f31 100644 --- a/src/lib/dnssd/Discovery_ImplPlatform.cpp +++ b/src/lib/dnssd/Discovery_ImplPlatform.cpp @@ -15,6 +15,7 @@ * limitations under the License. */ +#include #include #include @@ -72,14 +73,16 @@ static void HandleNodeBrowse(void * context, DnssdService * services, size_t ser discoveryContext->Retain(); // For some platforms browsed services are already resolved, so verify if resolve is really needed or call resolve callback + auto & ipAddress = services[i].mAddress; + // Check if SRV, TXT and AAAA records were received in DNS responses - if (strlen(services[i].mHostName) == 0 || services[i].mTextEntrySize == 0 || !services[i].mAddress.HasValue()) + if (strlen(services[i].mHostName) == 0 || services[i].mTextEntrySize == 0 || !ipAddress.has_value()) { ChipDnssdResolve(&services[i], services[i].mInterface, HandleNodeResolve, context); } else { - Inet::IPAddress * address = &(services[i].mAddress.Value()); + Inet::IPAddress * address = &(*ipAddress); HandleNodeResolve(context, &services[i], Span(address, 1), error); } } @@ -113,10 +116,10 @@ CHIP_ERROR AddPtrRecord(DiscoveryFilterType type, const char ** entries, size_t template CHIP_ERROR AddPtrRecord(DiscoveryFilterType type, const char ** entries, size_t & entriesCount, char * buffer, size_t bufferLen, - chip::Optional value) + const std::optional & value) { - VerifyOrReturnError(value.HasValue(), CHIP_NO_ERROR); - return AddPtrRecord(type, entries, entriesCount, buffer, bufferLen, value.Value()); + VerifyOrReturnError(value.has_value(), CHIP_NO_ERROR); + return AddPtrRecord(type, entries, entriesCount, buffer, bufferLen, *value); } CHIP_ERROR ENFORCE_FORMAT(4, 5) @@ -161,36 +164,36 @@ CHIP_ERROR CopyTextRecordValue(char * buffer, size_t bufferLen, CommissioningMod } template -CHIP_ERROR CopyTextRecordValue(char * buffer, size_t bufferLen, chip::Optional value) +CHIP_ERROR CopyTextRecordValue(char * buffer, size_t bufferLen, std::optional value) { - VerifyOrReturnError(value.HasValue(), CHIP_ERROR_UNINITIALIZED); - return CopyTextRecordValue(buffer, bufferLen, value.Value()); + VerifyOrReturnError(value.has_value(), CHIP_ERROR_UNINITIALIZED); + return CopyTextRecordValue(buffer, bufferLen, *value); } -CHIP_ERROR CopyTextRecordValue(char * buffer, size_t bufferLen, chip::Optional value1, chip::Optional value2) +CHIP_ERROR CopyTextRecordValue(char * buffer, size_t bufferLen, std::optional value1, std::optional value2) { - VerifyOrReturnError(value1.HasValue(), CHIP_ERROR_UNINITIALIZED); - return value2.HasValue() ? CopyTextRecordValue(buffer, bufferLen, value1.Value(), value2.Value()) - : CopyTextRecordValue(buffer, bufferLen, value1.Value()); + VerifyOrReturnError(value1.has_value(), CHIP_ERROR_UNINITIALIZED); + return value2.has_value() ? CopyTextRecordValue(buffer, bufferLen, *value1, *value2) + : CopyTextRecordValue(buffer, bufferLen, *value1); } -CHIP_ERROR CopyTextRecordValue(char * buffer, size_t bufferLen, const chip::Optional optional, +CHIP_ERROR CopyTextRecordValue(char * buffer, size_t bufferLen, const std::optional & optional, TxtFieldKey key) { VerifyOrReturnError((key == TxtFieldKey::kSessionIdleInterval || key == TxtFieldKey::kSessionActiveInterval || key == TxtFieldKey::kSessionActiveThreshold), CHIP_ERROR_INVALID_ARGUMENT); - VerifyOrReturnError(optional.HasValue(), CHIP_ERROR_UNINITIALIZED); + VerifyOrReturnError(optional.has_value(), CHIP_ERROR_UNINITIALIZED); CHIP_ERROR err; if (key == TxtFieldKey::kSessionActiveThreshold) { - err = CopyTextRecordValue(buffer, bufferLen, optional.Value().mActiveThresholdTime.count()); + err = CopyTextRecordValue(buffer, bufferLen, optional->mActiveThresholdTime.count()); } else { bool isIdle = (key == TxtFieldKey::kSessionIdleInterval); - auto retryInterval = isIdle ? optional.Value().mIdleRetransTimeout : optional.Value().mActiveRetransTimeout; + auto retryInterval = isIdle ? optional->mIdleRetransTimeout : optional->mActiveRetransTimeout; if (retryInterval > kMaxRetryInterval) { ChipLogProgress(Discovery, "MRP retry interval %s value exceeds allowed range of 1 hour, using maximum available", @@ -254,7 +257,7 @@ CHIP_ERROR CopyTxtRecord(TxtFieldKey key, char * buffer, size_t bufferLen, const return CopyTextRecordValue(buffer, bufferLen, params.GetCommissioningMode()); case TxtFieldKey::kCommissionerPasscode: return CopyTextRecordValue(buffer, bufferLen, - static_cast(params.GetCommissionerPasscodeSupported().ValueOr(false) ? 1 : 0)); + static_cast(params.GetCommissionerPasscodeSupported().value_or(false) ? 1 : 0)); default: return CopyTxtRecord(key, buffer, bufferLen, static_cast>(params)); } @@ -760,16 +763,15 @@ CHIP_ERROR DiscoveryImplPlatform::StartDiscovery(DiscoveryType type, DiscoveryFi CHIP_ERROR DiscoveryImplPlatform::StopDiscovery(DiscoveryContext & context) { - if (!context.GetBrowseIdentifier().HasValue()) + const std::optional browseIdentifier = context.GetBrowseIdentifier(); + if (!browseIdentifier.has_value()) { // No discovery going on. return CHIP_NO_ERROR; } - const auto browseIdentifier = context.GetBrowseIdentifier().Value(); context.ClearBrowseIdentifier(); - - return ChipDnssdStopBrowse(browseIdentifier); + return ChipDnssdStopBrowse(*browseIdentifier); } CHIP_ERROR DiscoveryImplPlatform::ReconfirmRecord(const char * hostname, Inet::IPAddress address, Inet::InterfaceId interfaceId) diff --git a/src/lib/dnssd/Resolver.h b/src/lib/dnssd/Resolver.h index bf684cef6a12a5..28406e1dc724f1 100644 --- a/src/lib/dnssd/Resolver.h +++ b/src/lib/dnssd/Resolver.h @@ -19,13 +19,13 @@ #include #include +#include #include #include #include #include #include -#include #include #include #include @@ -74,9 +74,9 @@ class OperationalResolveDelegate class DiscoveryContext : public ReferenceCounted { public: - void SetBrowseIdentifier(intptr_t identifier) { mBrowseIdentifier.Emplace(identifier); } - void ClearBrowseIdentifier() { mBrowseIdentifier.ClearValue(); } - const Optional & GetBrowseIdentifier() const { return mBrowseIdentifier; } + void SetBrowseIdentifier(intptr_t identifier) { mBrowseIdentifier.emplace(identifier); } + void ClearBrowseIdentifier() { mBrowseIdentifier.reset(); } + const std::optional & GetBrowseIdentifier() const { return mBrowseIdentifier; } void SetDiscoveryDelegate(DiscoverNodeDelegate * delegate) { mDelegate = delegate; } void OnNodeDiscovered(const DiscoveredNodeData & nodeData) @@ -93,7 +93,7 @@ class DiscoveryContext : public ReferenceCounted private: DiscoverNodeDelegate * mDelegate = nullptr; - Optional mBrowseIdentifier; + std::optional mBrowseIdentifier; }; /** diff --git a/src/lib/dnssd/Resolver_ImplMinimalMdns.cpp b/src/lib/dnssd/Resolver_ImplMinimalMdns.cpp index 403da6effcd36c..64b194339b8bd1 100644 --- a/src/lib/dnssd/Resolver_ImplMinimalMdns.cpp +++ b/src/lib/dnssd/Resolver_ImplMinimalMdns.cpp @@ -644,9 +644,9 @@ CHIP_ERROR MinMdnsResolver::SendAllPendingQueries() { while (true) { - Optional resolve = mActiveResolves.NextScheduled(); + std::optional resolve = mActiveResolves.NextScheduled(); - if (!resolve.HasValue()) + if (!resolve.has_value()) { break; } @@ -657,9 +657,9 @@ CHIP_ERROR MinMdnsResolver::SendAllPendingQueries() QueryBuilder builder(std::move(buffer)); builder.Header().SetMessageId(0); - ReturnErrorOnFailure(BuildQuery(builder, resolve.Value())); + ReturnErrorOnFailure(BuildQuery(builder, *resolve)); - if (resolve.Value().firstSend) + if (resolve->firstSend) { ReturnErrorOnFailure(GlobalMinimalMdnsServer::Server().BroadcastUnicastQuery(builder.ReleasePacket(), kMdnsPort)); } @@ -744,14 +744,14 @@ CHIP_ERROR MinMdnsResolver::ScheduleRetries() ReturnErrorCodeIf(mSystemLayer == nullptr, CHIP_ERROR_INCORRECT_STATE); mSystemLayer->CancelTimer(&RetryCallback, this); - Optional delay = mActiveResolves.GetTimeUntilNextExpectedResponse(); + std::optional delay = mActiveResolves.GetTimeUntilNextExpectedResponse(); - if (!delay.HasValue()) + if (!delay.has_value()) { return CHIP_NO_ERROR; } - return mSystemLayer->StartTimer(delay.Value(), &RetryCallback, this); + return mSystemLayer->StartTimer(*delay, &RetryCallback, this); } void MinMdnsResolver::RetryCallback(System::Layer *, void * self) diff --git a/src/lib/dnssd/minimal_mdns/core/RecordWriter.cpp b/src/lib/dnssd/minimal_mdns/core/RecordWriter.cpp index 41e9985687ad81..693fc9418e91a7 100644 --- a/src/lib/dnssd/minimal_mdns/core/RecordWriter.cpp +++ b/src/lib/dnssd/minimal_mdns/core/RecordWriter.cpp @@ -50,12 +50,12 @@ RecordWriter & RecordWriter::WriteQName(const FullQName & qname) remaining.nameCount = qname.nameCount - i; // Try to find a valid offset - chip::Optional offset = FindPreviousName(remaining); + std::optional offset = FindPreviousName(remaining); - if (offset.HasValue()) + if (offset.has_value()) { // Pointer to offset: set the highest 2 bits - mOutput->Put16(offset.Value() | 0xC000); + mOutput->Put16(*offset | 0xC000); if (mOutput->Fit() && !isFullyCompressed) { @@ -85,13 +85,13 @@ RecordWriter & RecordWriter::WriteQName(const SerializedQNameIterator & qname) SerializedQNameIterator copy = qname; while (true) { - chip::Optional offset = FindPreviousName(copy); + std::optional offset = FindPreviousName(copy); - if (offset.HasValue()) + if (offset.has_value()) { // Pointer to offset: set the highest 2 bits // We guarantee that offsets saved are <= kMaxReuseOffset - mOutput->Put16(offset.Value() | 0xC000); + mOutput->Put16(*offset | 0xC000); if (mOutput->Fit() && !isFullyCompressed) { diff --git a/src/lib/dnssd/minimal_mdns/core/RecordWriter.h b/src/lib/dnssd/minimal_mdns/core/RecordWriter.h index 35e563fe870ec2..0bb80fce7cffd7 100644 --- a/src/lib/dnssd/minimal_mdns/core/RecordWriter.h +++ b/src/lib/dnssd/minimal_mdns/core/RecordWriter.h @@ -17,10 +17,11 @@ #pragma once #include -#include #include #include +#include + namespace mdns { namespace Minimal { @@ -99,7 +100,7 @@ class RecordWriter /// Find the offset at which this qname was previously seen (if any) /// works with QName and SerializedQNameIterator template - chip::Optional FindPreviousName(const T & name) const + std::optional FindPreviousName(const T & name) const { for (size_t i = 0; i < kMaxCachedReferences; i++) { @@ -110,7 +111,7 @@ class RecordWriter { if (previous == name) { - return chip::MakeOptional(static_cast(previous.OffsetInCurrentValidData())); + return std::make_optional(static_cast(previous.OffsetInCurrentValidData())); } if (!previous.Next()) @@ -120,7 +121,7 @@ class RecordWriter } } - return chip::Optional::Missing(); + return std::nullopt; } /// Gets the iterator corresponding to the previous name diff --git a/src/lib/dnssd/minimal_mdns/tests/TestAdvertiser.cpp b/src/lib/dnssd/minimal_mdns/tests/TestAdvertiser.cpp index b39fd5858858c1..c868939573f1c7 100644 --- a/src/lib/dnssd/minimal_mdns/tests/TestAdvertiser.cpp +++ b/src/lib/dnssd/minimal_mdns/tests/TestAdvertiser.cpp @@ -79,7 +79,7 @@ OperationalAdvertisingParameters operationalParams1 = .SetMac(ByteSpan(kMac)) .SetPort(CHIP_PORT) .EnableIpV4(true) - .SetLocalMRPConfig(chip::Optional::Value( + .SetLocalMRPConfig(std::make_optional( 32_ms32, 30_ms32)); // Match SII, SAI. SAT not provided so it uses default 4000ms OperationalAdvertisingParameters operationalParams2 = OperationalAdvertisingParameters().SetPeerId(kPeerId2).SetMac(ByteSpan(kMac)).SetPort(CHIP_PORT).EnableIpV4(true); @@ -151,14 +151,14 @@ CommissionAdvertisingParameters commissionableNodeParamsLargeBasic = .SetMac(ByteSpan(kMac, sizeof(kMac))) .SetLongDiscriminator(22) .SetShortDiscriminator(2) - .SetVendorId(chip::Optional(555)) - .SetDeviceType(chip::Optional(70000)) + .SetVendorId(std::make_optional(555)) + .SetDeviceType(std::make_optional(70000)) .SetCommissioningMode(CommissioningMode::kEnabledBasic) - .SetDeviceName(chip::Optional("testy-test")) - .SetPairingHint(chip::Optional(3)) - .SetPairingInstruction(chip::Optional("Pair me")) - .SetProductId(chip::Optional(897)) - .SetRotatingDeviceId(chip::Optional("id_that_spins")); + .SetDeviceName(std::make_optional("testy-test")) + .SetPairingHint(std::make_optional(3)) + .SetPairingInstruction(std::make_optional("Pair me")) + .SetProductId(std::make_optional(897)) + .SetRotatingDeviceId(std::make_optional("id_that_spins")); QNamePart txtCommissionableNodeParamsLargeBasicParts[] = { "D=22", "VP=555+897", "CM=1", "DT=70000", "DN=testy-test", "RI=id_that_spins", "PI=Pair me", "PH=3" }; FullQName txtCommissionableNodeParamsLargeBasicName = FullQName(txtCommissionableNodeParamsLargeBasicParts); @@ -171,17 +171,17 @@ CommissionAdvertisingParameters commissionableNodeParamsLargeEnhanced = .SetMac(ByteSpan(kMac, sizeof(kMac))) .SetLongDiscriminator(22) .SetShortDiscriminator(2) - .SetVendorId(chip::Optional(555)) - .SetDeviceType(chip::Optional(70000)) + .SetVendorId(std::make_optional(555)) + .SetDeviceType(std::make_optional(70000)) .SetCommissioningMode(CommissioningMode::kEnabledEnhanced) - .SetDeviceName(chip::Optional("testy-test")) - .SetPairingHint(chip::Optional(3)) - .SetPairingInstruction(chip::Optional("Pair me")) - .SetProductId(chip::Optional(897)) - .SetRotatingDeviceId(chip::Optional("id_that_spins")) + .SetDeviceName(std::make_optional("testy-test")) + .SetPairingHint(std::make_optional(3)) + .SetPairingInstruction(std::make_optional("Pair me")) + .SetProductId(std::make_optional(897)) + .SetRotatingDeviceId(std::make_optional("id_that_spins")) .SetICDModeToAdvertise(ICDModeAdvertise::kSIT) // 3600005 is more than the max so should be adjusted down - .SetLocalMRPConfig(Optional::Value(3600000_ms32, 3600005_ms32, 65535_ms16)); + .SetLocalMRPConfig(std::make_optional(3600000_ms32, 3600005_ms32, 65535_ms16)); QNamePart txtCommissionableNodeParamsLargeEnhancedParts[] = { "D=22", "VP=555+897", "CM=2", "DT=70000", "DN=testy-test", "RI=id_that_spins", "PI=Pair me", "PH=3", "SAI=3600000", "SII=3600000", "SAT=65535", "ICD=0" }; @@ -196,15 +196,15 @@ CommissionAdvertisingParameters commissionableNodeParamsEnhancedAsICDLIT = .SetMac(ByteSpan(kMac, sizeof(kMac))) .SetLongDiscriminator(22) .SetShortDiscriminator(2) - .SetVendorId(chip::Optional(555)) - .SetDeviceType(chip::Optional(70000)) + .SetVendorId(std::make_optional(555)) + .SetDeviceType(std::make_optional(70000)) .SetCommissioningMode(CommissioningMode::kEnabledEnhanced) - .SetDeviceName(chip::Optional("testy-test")) - .SetPairingHint(chip::Optional(3)) - .SetPairingInstruction(chip::Optional("Pair me")) - .SetProductId(chip::Optional(897)) + .SetDeviceName(std::make_optional("testy-test")) + .SetPairingHint(std::make_optional(3)) + .SetPairingInstruction(std::make_optional("Pair me")) + .SetProductId(std::make_optional(897)) .SetICDModeToAdvertise(ICDModeAdvertise::kLIT) - .SetLocalMRPConfig(Optional::Value(3600000_ms32, 3600000_ms32, 65535_ms16)); + .SetLocalMRPConfig(std::make_optional(3600000_ms32, 3600000_ms32, 65535_ms16)); // With ICD Operation as LIT, SII key will not be added to the advertisement QNamePart txtCommissionableNodeParamsEnhancedAsICDLITParts[] = { "D=22", "VP=555+897", "CM=2", "DT=70000", "DN=testy-test", "PI=Pair me", "PH=3", "SAI=3600000", diff --git a/src/lib/dnssd/platform/Dnssd.h b/src/lib/dnssd/platform/Dnssd.h index fcbeabe1ce8d51..02fb851a12d861 100644 --- a/src/lib/dnssd/platform/Dnssd.h +++ b/src/lib/dnssd/platform/Dnssd.h @@ -26,12 +26,12 @@ #pragma once #include +#include #include #include #include #include -#include #include #include #include @@ -77,7 +77,7 @@ struct DnssdService size_t mTextEntrySize; const char ** mSubTypes; size_t mSubTypeSize; - Optional mAddress; + std::optional mAddress; // Time to live in seconds. Per rfc6762 section 10, because we have a hostname, our default TTL is 120 seconds uint32_t mTtlSeconds = 120; diff --git a/src/lib/dnssd/platform/tests/TestPlatform.cpp b/src/lib/dnssd/platform/tests/TestPlatform.cpp index ebdb46643847c6..324863a948902d 100644 --- a/src/lib/dnssd/platform/tests/TestPlatform.cpp +++ b/src/lib/dnssd/platform/tests/TestPlatform.cpp @@ -46,14 +46,14 @@ test::ExpectedCall operationalCall1 = test::ExpectedCall() .SetInstanceName("BEEFBEEFF00DF00D-1111222233334444") .SetHostName(host) .AddSubtype("_IBEEFBEEFF00DF00D"); -OperationalAdvertisingParameters operationalParams2 = - OperationalAdvertisingParameters() - .SetPeerId(kPeerId2) - .SetMac(ByteSpan(kMac)) - .SetPort(CHIP_PORT) - .EnableIpV4(true) - .SetLocalMRPConfig(Optional::Value(32_ms32, 30_ms32, 10_ms16)) // SII and SAI to match below - .SetICDModeToAdvertise(ICDModeAdvertise::kSIT); +OperationalAdvertisingParameters operationalParams2 = OperationalAdvertisingParameters() + .SetPeerId(kPeerId2) + .SetMac(ByteSpan(kMac)) + .SetPort(CHIP_PORT) + .EnableIpV4(true) + .SetLocalMRPConfig(std::make_optional( + 32_ms32, 30_ms32, 10_ms16)) // SII and SAI to match below + .SetICDModeToAdvertise(ICDModeAdvertise::kSIT); test::ExpectedCall operationalCall2 = test::ExpectedCall() .SetProtocol(DnssdServiceProtocol::kDnssdProtocolTcp) .SetServiceName("_matter") @@ -87,17 +87,17 @@ CommissionAdvertisingParameters commissionableNodeParamsLargeBasic = .SetMac(ByteSpan(kMac, sizeof(kMac))) .SetLongDiscriminator(22) .SetShortDiscriminator(2) - .SetVendorId(Optional(555)) - .SetDeviceType(Optional(70000)) + .SetVendorId(std::make_optional(555)) + .SetDeviceType(std::make_optional(70000)) .SetCommissioningMode(CommissioningMode::kEnabledBasic) - .SetDeviceName(Optional("testy-test")) - .SetPairingHint(Optional(3)) - .SetPairingInstruction(Optional("Pair me")) - .SetProductId(Optional(897)) - .SetRotatingDeviceId(Optional("id_that_spins")) + .SetDeviceName(std::make_optional("testy-test")) + .SetPairingHint(std::make_optional(3)) + .SetPairingInstruction(std::make_optional("Pair me")) + .SetProductId(std::make_optional(897)) + .SetRotatingDeviceId(std::make_optional("id_that_spins")) .SetICDModeToAdvertise(ICDModeAdvertise::kSIT) // 3600005 is over the max, so this should be adjusted by the platform - .SetLocalMRPConfig(Optional::Value(3600000_ms32, 3600005_ms32, 65535_ms16)); + .SetLocalMRPConfig(std::make_optional(3600000_ms32, 3600005_ms32, 65535_ms16)); test::ExpectedCall commissionableLargeBasic = test::ExpectedCall() .SetProtocol(DnssdServiceProtocol::kDnssdProtocolUdp) @@ -126,14 +126,14 @@ CommissionAdvertisingParameters commissionableNodeParamsLargeEnhanced = .SetMac(ByteSpan(kMac, sizeof(kMac))) .SetLongDiscriminator(22) .SetShortDiscriminator(2) - .SetVendorId(chip::Optional(555)) - .SetDeviceType(chip::Optional(70000)) + .SetVendorId(std::make_optional(555)) + .SetDeviceType(std::make_optional(70000)) .SetCommissioningMode(CommissioningMode::kEnabledEnhanced) - .SetDeviceName(chip::Optional("testy-test")) - .SetPairingHint(chip::Optional(3)) - .SetPairingInstruction(chip::Optional("Pair me")) - .SetProductId(chip::Optional(897)) - .SetRotatingDeviceId(chip::Optional("id_that_spins")); + .SetDeviceName(std::make_optional("testy-test")) + .SetPairingHint(std::make_optional(3)) + .SetPairingInstruction(std::make_optional("Pair me")) + .SetProductId(std::make_optional(897)) + .SetRotatingDeviceId(std::make_optional("id_that_spins")); test::ExpectedCall commissionableLargeEnhanced = test::ExpectedCall() .SetProtocol(DnssdServiceProtocol::kDnssdProtocolUdp) diff --git a/src/lib/dnssd/tests/TestActiveResolveAttempts.cpp b/src/lib/dnssd/tests/TestActiveResolveAttempts.cpp index 4c2665658f3493..0648c9880c597b 100644 --- a/src/lib/dnssd/tests/TestActiveResolveAttempts.cpp +++ b/src/lib/dnssd/tests/TestActiveResolveAttempts.cpp @@ -31,14 +31,17 @@ PeerId MakePeerId(NodeId nodeId) return peerId.SetNodeId(nodeId).SetCompressedFabricId(123); } -Optional ScheduledPeer(NodeId id, bool first) +std::optional ScheduledPeer(NodeId id, bool first) { - return Optional::Value(ActiveResolveAttempts::ScheduledAttempt(MakePeerId(id), first)); + return std::make_optional( + ActiveResolveAttempts::ScheduledAttempt(MakePeerId(id), first)); } -Optional ScheduledBrowse(const Dnssd::DiscoveryFilter & filter, - const Dnssd::DiscoveryType type, bool first) + +std::optional ScheduledBrowse(const Dnssd::DiscoveryFilter & filter, + const Dnssd::DiscoveryType type, bool first) { - return Optional::Value(ActiveResolveAttempts::ScheduledAttempt(filter, type, first)); + return std::make_optional( + ActiveResolveAttempts::ScheduledAttempt(filter, type, first)); } TEST(TestActiveResolveAttempts, TestSinglePeerAddRemove) @@ -49,39 +52,39 @@ TEST(TestActiveResolveAttempts, TestSinglePeerAddRemove) mockClock.AdvanceMonotonic(1234_ms32); // Starting up, no scheduled peers are expected - EXPECT_FALSE(attempts.GetTimeUntilNextExpectedResponse().HasValue()); - EXPECT_FALSE(attempts.NextScheduled().HasValue()); + EXPECT_FALSE(attempts.GetTimeUntilNextExpectedResponse().has_value()); + EXPECT_FALSE(attempts.NextScheduled().has_value()); // Adding a single peer should result in it being scheduled attempts.MarkPending(MakePeerId(1)); - EXPECT_EQ(attempts.GetTimeUntilNextExpectedResponse(), Optional(0_ms32)); + EXPECT_EQ(attempts.GetTimeUntilNextExpectedResponse(), std::make_optional(0_ms32)); EXPECT_EQ(attempts.NextScheduled(), ScheduledPeer(1, true)); - EXPECT_FALSE(attempts.NextScheduled().HasValue()); + EXPECT_FALSE(attempts.NextScheduled().has_value()); // one Next schedule is called, expect to have a delay of 1000 ms - EXPECT_EQ(attempts.GetTimeUntilNextExpectedResponse(), Optional(1000_ms32)); + EXPECT_EQ(attempts.GetTimeUntilNextExpectedResponse(), std::make_optional(1000_ms32)); mockClock.AdvanceMonotonic(500_ms32); - EXPECT_EQ(attempts.GetTimeUntilNextExpectedResponse(), Optional(500_ms32)); - EXPECT_FALSE(attempts.NextScheduled().HasValue()); + EXPECT_EQ(attempts.GetTimeUntilNextExpectedResponse(), std::make_optional(500_ms32)); + EXPECT_FALSE(attempts.NextScheduled().has_value()); // past due date: timeout should be 0 mockClock.AdvanceMonotonic(800_ms32); - EXPECT_EQ(attempts.GetTimeUntilNextExpectedResponse(), Optional(0_ms32)); + EXPECT_EQ(attempts.GetTimeUntilNextExpectedResponse(), std::make_optional(0_ms32)); EXPECT_EQ(attempts.NextScheduled(), ScheduledPeer(1, false)); - EXPECT_FALSE(attempts.NextScheduled().HasValue()); + EXPECT_FALSE(attempts.NextScheduled().has_value()); // one Next schedule is called, expect to have a delay of 2000 ms // sincve the timeout doubles every time - EXPECT_EQ(attempts.GetTimeUntilNextExpectedResponse(), Optional(2000_ms32)); + EXPECT_EQ(attempts.GetTimeUntilNextExpectedResponse(), std::make_optional(2000_ms32)); mockClock.AdvanceMonotonic(100_ms32); - EXPECT_EQ(attempts.GetTimeUntilNextExpectedResponse(), Optional(1900_ms32)); + EXPECT_EQ(attempts.GetTimeUntilNextExpectedResponse(), std::make_optional(1900_ms32)); // once complete, nothing to schedule attempts.Complete(MakePeerId(1)); - EXPECT_FALSE(attempts.GetTimeUntilNextExpectedResponse().HasValue()); - EXPECT_FALSE(attempts.NextScheduled().HasValue()); + EXPECT_FALSE(attempts.GetTimeUntilNextExpectedResponse().has_value()); + EXPECT_FALSE(attempts.NextScheduled().has_value()); } TEST(TestActiveResolveAttempts, TestSingleBrowseAddRemove) @@ -94,41 +97,41 @@ TEST(TestActiveResolveAttempts, TestSingleBrowseAddRemove) mockClock.AdvanceMonotonic(1234_ms32); // Starting up, no scheduled peers are expected - EXPECT_FALSE(attempts.GetTimeUntilNextExpectedResponse().HasValue()); - EXPECT_FALSE(attempts.NextScheduled().HasValue()); + EXPECT_FALSE(attempts.GetTimeUntilNextExpectedResponse().has_value()); + EXPECT_FALSE(attempts.NextScheduled().has_value()); // Adding a single attempt should result in it being scheduled attempts.MarkPending(filter, type); - EXPECT_EQ(attempts.GetTimeUntilNextExpectedResponse(), Optional(0_ms32)); + EXPECT_EQ(attempts.GetTimeUntilNextExpectedResponse(), std::make_optional(0_ms32)); EXPECT_EQ(attempts.NextScheduled(), ScheduledBrowse(filter, type, true)); - EXPECT_FALSE(attempts.NextScheduled().HasValue()); + EXPECT_FALSE(attempts.NextScheduled().has_value()); // one Next schedule is called, expect to have a delay of 1000 ms - EXPECT_EQ(attempts.GetTimeUntilNextExpectedResponse(), Optional(1000_ms32)); + EXPECT_EQ(attempts.GetTimeUntilNextExpectedResponse(), std::make_optional(1000_ms32)); mockClock.AdvanceMonotonic(500_ms32); - EXPECT_EQ(attempts.GetTimeUntilNextExpectedResponse(), Optional(500_ms32)); - EXPECT_FALSE(attempts.NextScheduled().HasValue()); + EXPECT_EQ(attempts.GetTimeUntilNextExpectedResponse(), std::make_optional(500_ms32)); + EXPECT_FALSE(attempts.NextScheduled().has_value()); // past due date: timeout should be 0 mockClock.AdvanceMonotonic(800_ms32); - EXPECT_EQ(attempts.GetTimeUntilNextExpectedResponse(), Optional(0_ms32)); + EXPECT_EQ(attempts.GetTimeUntilNextExpectedResponse(), std::make_optional(0_ms32)); EXPECT_EQ(attempts.NextScheduled(), ScheduledBrowse(filter, type, false)); - EXPECT_FALSE(attempts.NextScheduled().HasValue()); + EXPECT_FALSE(attempts.NextScheduled().has_value()); // one Next schedule is called, expect to have a delay of 2000 ms // sincve the timeout doubles every time - EXPECT_EQ(attempts.GetTimeUntilNextExpectedResponse(), Optional(2000_ms32)); + EXPECT_EQ(attempts.GetTimeUntilNextExpectedResponse(), std::make_optional(2000_ms32)); mockClock.AdvanceMonotonic(100_ms32); - EXPECT_EQ(attempts.GetTimeUntilNextExpectedResponse(), Optional(1900_ms32)); + EXPECT_EQ(attempts.GetTimeUntilNextExpectedResponse(), std::make_optional(1900_ms32)); // once complete, nothing to schedule Dnssd::DiscoveredNodeData data; data.Set(); data.Get().longDiscriminator = 1234; attempts.CompleteCommissionable(data); - EXPECT_FALSE(attempts.GetTimeUntilNextExpectedResponse().HasValue()); - EXPECT_FALSE(attempts.NextScheduled().HasValue()); + EXPECT_FALSE(attempts.GetTimeUntilNextExpectedResponse().has_value()); + EXPECT_FALSE(attempts.NextScheduled().has_value()); } TEST(TestActiveResolveAttempts, TestRescheduleSamePeerId) @@ -140,27 +143,27 @@ TEST(TestActiveResolveAttempts, TestRescheduleSamePeerId) attempts.MarkPending(MakePeerId(1)); - EXPECT_EQ(attempts.GetTimeUntilNextExpectedResponse(), Optional(0_ms32)); + EXPECT_EQ(attempts.GetTimeUntilNextExpectedResponse(), std::make_optional(0_ms32)); EXPECT_EQ(attempts.NextScheduled(), ScheduledPeer(1, true)); - EXPECT_FALSE(attempts.NextScheduled().HasValue()); + EXPECT_FALSE(attempts.NextScheduled().has_value()); // one Next schedule is called, expect to have a delay of 1000 ms - EXPECT_EQ(attempts.GetTimeUntilNextExpectedResponse(), Optional(1000_ms32)); + EXPECT_EQ(attempts.GetTimeUntilNextExpectedResponse(), std::make_optional(1000_ms32)); // 2nd try goes to 2 seconds (once at least 1 second passes) mockClock.AdvanceMonotonic(1234_ms32); - EXPECT_EQ(attempts.GetTimeUntilNextExpectedResponse(), Optional(0_ms32)); + EXPECT_EQ(attempts.GetTimeUntilNextExpectedResponse(), std::make_optional(0_ms32)); EXPECT_EQ(attempts.NextScheduled(), ScheduledPeer(1, false)); - EXPECT_FALSE(attempts.NextScheduled().HasValue()); - EXPECT_EQ(attempts.GetTimeUntilNextExpectedResponse(), Optional(2000_ms32)); + EXPECT_FALSE(attempts.NextScheduled().has_value()); + EXPECT_EQ(attempts.GetTimeUntilNextExpectedResponse(), std::make_optional(2000_ms32)); // reschedule starts fresh attempts.MarkPending(MakePeerId(1)); - EXPECT_EQ(attempts.GetTimeUntilNextExpectedResponse(), Optional(0_ms32)); + EXPECT_EQ(attempts.GetTimeUntilNextExpectedResponse(), std::make_optional(0_ms32)); EXPECT_EQ(attempts.NextScheduled(), ScheduledPeer(1, true)); - EXPECT_FALSE(attempts.NextScheduled().HasValue()); - EXPECT_EQ(attempts.GetTimeUntilNextExpectedResponse(), Optional(1000_ms32)); + EXPECT_FALSE(attempts.NextScheduled().has_value()); + EXPECT_EQ(attempts.GetTimeUntilNextExpectedResponse(), std::make_optional(1000_ms32)); } TEST(TestActiveResolveAttempts, TestRescheduleSameFilter) @@ -174,27 +177,27 @@ TEST(TestActiveResolveAttempts, TestRescheduleSameFilter) attempts.MarkPending(filter, type); - EXPECT_EQ(attempts.GetTimeUntilNextExpectedResponse(), Optional(0_ms32)); + EXPECT_EQ(attempts.GetTimeUntilNextExpectedResponse(), std::make_optional(0_ms32)); EXPECT_EQ(attempts.NextScheduled(), ScheduledBrowse(filter, type, true)); - EXPECT_FALSE(attempts.NextScheduled().HasValue()); + EXPECT_FALSE(attempts.NextScheduled().has_value()); // one Next schedule is called, expect to have a delay of 1000 ms - EXPECT_EQ(attempts.GetTimeUntilNextExpectedResponse(), Optional(1000_ms32)); + EXPECT_EQ(attempts.GetTimeUntilNextExpectedResponse(), std::make_optional(1000_ms32)); // 2nd try goes to 2 seconds (once at least 1 second passes) mockClock.AdvanceMonotonic(1234_ms32); - EXPECT_EQ(attempts.GetTimeUntilNextExpectedResponse(), Optional(0_ms32)); + EXPECT_EQ(attempts.GetTimeUntilNextExpectedResponse(), std::make_optional(0_ms32)); EXPECT_EQ(attempts.NextScheduled(), ScheduledBrowse(filter, type, false)); - EXPECT_FALSE(attempts.NextScheduled().HasValue()); - EXPECT_EQ(attempts.GetTimeUntilNextExpectedResponse(), Optional(2000_ms32)); + EXPECT_FALSE(attempts.NextScheduled().has_value()); + EXPECT_EQ(attempts.GetTimeUntilNextExpectedResponse(), std::make_optional(2000_ms32)); // reschedule starts fresh attempts.MarkPending(filter, type); - EXPECT_EQ(attempts.GetTimeUntilNextExpectedResponse(), Optional(0_ms32)); + EXPECT_EQ(attempts.GetTimeUntilNextExpectedResponse(), std::make_optional(0_ms32)); EXPECT_EQ(attempts.NextScheduled(), ScheduledBrowse(filter, type, true)); - EXPECT_FALSE(attempts.NextScheduled().HasValue()); - EXPECT_EQ(attempts.GetTimeUntilNextExpectedResponse(), Optional(1000_ms32)); + EXPECT_FALSE(attempts.NextScheduled().has_value()); + EXPECT_EQ(attempts.GetTimeUntilNextExpectedResponse(), std::make_optional(1000_ms32)); } TEST(TestActiveResolveAttempts, TestLRU) @@ -208,15 +211,15 @@ TEST(TestActiveResolveAttempts, TestLRU) // add a single very old peer attempts.MarkPending(MakePeerId(9999)); EXPECT_EQ(attempts.NextScheduled(), ScheduledPeer(9999, true)); - EXPECT_FALSE(attempts.NextScheduled().HasValue()); + EXPECT_FALSE(attempts.NextScheduled().has_value()); mockClock.AdvanceMonotonic(1000_ms32); EXPECT_EQ(attempts.NextScheduled(), ScheduledPeer(9999, false)); - EXPECT_FALSE(attempts.NextScheduled().HasValue()); + EXPECT_FALSE(attempts.NextScheduled().has_value()); mockClock.AdvanceMonotonic(2000_ms32); EXPECT_EQ(attempts.NextScheduled(), ScheduledPeer(9999, false)); - EXPECT_FALSE(attempts.NextScheduled().HasValue()); + EXPECT_FALSE(attempts.NextScheduled().has_value()); // at this point, peer 9999 has a delay of 4 seconds. Fill up the rest of the table @@ -226,25 +229,26 @@ TEST(TestActiveResolveAttempts, TestLRU) mockClock.AdvanceMonotonic(1_ms32); EXPECT_EQ(attempts.NextScheduled(), ScheduledPeer(i, true)); - EXPECT_FALSE(attempts.NextScheduled().HasValue()); + EXPECT_FALSE(attempts.NextScheduled().has_value()); } // +2 because: 1 element skipped, one element is the "current" that has a delay of 1000ms EXPECT_EQ(attempts.GetTimeUntilNextExpectedResponse(), - Optional::Value( + std::make_optional( System::Clock::Milliseconds32(1000 - mdns::Minimal::ActiveResolveAttempts::kRetryQueueSize + 2))); // add another element - this should overwrite peer 9999 attempts.MarkPending(MakePeerId(mdns::Minimal::ActiveResolveAttempts::kRetryQueueSize)); mockClock.AdvanceMonotonic(32_s16); - for (Optional s = attempts.NextScheduled(); s.HasValue(); s = attempts.NextScheduled()) + for (std::optional s = attempts.NextScheduled(); s.has_value(); + s = attempts.NextScheduled()) { - EXPECT_NE(s.Value().ResolveData().peerId.GetNodeId(), 9999u); + EXPECT_NE(s->ResolveData().peerId.GetNodeId(), 9999u); } // Still have active pending items (queue is full) - EXPECT_TRUE(attempts.GetTimeUntilNextExpectedResponse().HasValue()); + EXPECT_TRUE(attempts.GetTimeUntilNextExpectedResponse().has_value()); // expire all of them. Since we double timeout every expiry, we expect a // few iteratios to be able to expire the entire queue @@ -253,18 +257,19 @@ TEST(TestActiveResolveAttempts, TestLRU) int i = 0; for (; i < kMaxIterations; i++) { - Optional ms = attempts.GetTimeUntilNextExpectedResponse(); - if (!ms.HasValue()) + std::optional ms = attempts.GetTimeUntilNextExpectedResponse(); + if (!ms.has_value()) { break; } - mockClock.AdvanceMonotonic(ms.Value()); + mockClock.AdvanceMonotonic(*ms); - Optional s = attempts.NextScheduled(); - while (s.HasValue()) + std::optional s = attempts.NextScheduled(); + while (s.has_value()) { - EXPECT_NE(s.Value().ResolveData().peerId.GetNodeId(), 9999u); + // NOLINTNEXTLINE(bugprone-unchecked-optional-access): this is checked in the while loop + EXPECT_NE(s->ResolveData().peerId.GetNodeId(), 9999u); s = attempts.NextScheduled(); } } @@ -282,48 +287,48 @@ TEST(TestActiveResolveAttempts, TestNextPeerOrdering) attempts.MarkPending(MakePeerId(1)); EXPECT_EQ(attempts.NextScheduled(), ScheduledPeer(1, true)); - EXPECT_FALSE(attempts.NextScheduled().HasValue()); - EXPECT_EQ(attempts.GetTimeUntilNextExpectedResponse(), Optional(1000_ms32)); + EXPECT_FALSE(attempts.NextScheduled().has_value()); + EXPECT_EQ(attempts.GetTimeUntilNextExpectedResponse(), std::make_optional(1000_ms32)); mockClock.AdvanceMonotonic(20_ms32); - EXPECT_EQ(attempts.GetTimeUntilNextExpectedResponse(), Optional(980_ms32)); + EXPECT_EQ(attempts.GetTimeUntilNextExpectedResponse(), std::make_optional(980_ms32)); // expect peerid to be resolve within 1 second from now attempts.MarkPending(MakePeerId(2)); // mock that we are querying 2 as well EXPECT_EQ(attempts.NextScheduled(), ScheduledPeer(2, true)); - EXPECT_FALSE(attempts.NextScheduled().HasValue()); + EXPECT_FALSE(attempts.NextScheduled().has_value()); mockClock.AdvanceMonotonic(80_ms32); - EXPECT_EQ(attempts.GetTimeUntilNextExpectedResponse(), Optional(900_ms32)); + EXPECT_EQ(attempts.GetTimeUntilNextExpectedResponse(), std::make_optional(900_ms32)); // Peer 1 is done, now peer2 should be pending (in 980ms) attempts.Complete(MakePeerId(1)); - EXPECT_EQ(attempts.GetTimeUntilNextExpectedResponse(), Optional(920_ms32)); + EXPECT_EQ(attempts.GetTimeUntilNextExpectedResponse(), std::make_optional(920_ms32)); mockClock.AdvanceMonotonic(20_ms32); - EXPECT_EQ(attempts.GetTimeUntilNextExpectedResponse(), Optional(900_ms32)); + EXPECT_EQ(attempts.GetTimeUntilNextExpectedResponse(), std::make_optional(900_ms32)); // Once peer 3 is added, queue should be // - 900 ms until peer id 2 is pending // - 1000 ms until peer id 3 is pending attempts.MarkPending(MakePeerId(3)); EXPECT_EQ(attempts.NextScheduled(), ScheduledPeer(3, true)); - EXPECT_FALSE(attempts.NextScheduled().HasValue()); - EXPECT_EQ(attempts.GetTimeUntilNextExpectedResponse(), Optional(900_ms32)); + EXPECT_FALSE(attempts.NextScheduled().has_value()); + EXPECT_EQ(attempts.GetTimeUntilNextExpectedResponse(), std::make_optional(900_ms32)); // After the clock advance // - 400 ms until peer id 2 is pending // - 500 ms until peer id 3 is pending mockClock.AdvanceMonotonic(500_ms32); - EXPECT_EQ(attempts.GetTimeUntilNextExpectedResponse(), Optional(400_ms32)); - EXPECT_FALSE(attempts.NextScheduled().HasValue()); + EXPECT_EQ(attempts.GetTimeUntilNextExpectedResponse(), std::make_optional(400_ms32)); + EXPECT_FALSE(attempts.NextScheduled().has_value()); // advancing the clock 'too long' will return both other entries, in reverse order due to how // the internal cache is built mockClock.AdvanceMonotonic(500_ms32); EXPECT_EQ(attempts.NextScheduled(), ScheduledPeer(3, false)); EXPECT_EQ(attempts.NextScheduled(), ScheduledPeer(2, false)); - EXPECT_FALSE(attempts.NextScheduled().HasValue()); + EXPECT_FALSE(attempts.NextScheduled().has_value()); } TEST(TestActiveResolveAttempts, TestCombination) @@ -342,32 +347,32 @@ TEST(TestActiveResolveAttempts, TestCombination) EXPECT_EQ(attempts.NextScheduled(), ScheduledPeer(1, true)); EXPECT_EQ(attempts.NextScheduled(), ScheduledBrowse(filter, type, true)); - EXPECT_FALSE(attempts.NextScheduled().HasValue()); + EXPECT_FALSE(attempts.NextScheduled().has_value()); // At this point, both should reset, so we're back to 1000ms - EXPECT_EQ(attempts.GetTimeUntilNextExpectedResponse(), Optional(1000_ms32)); + EXPECT_EQ(attempts.GetTimeUntilNextExpectedResponse(), std::make_optional(1000_ms32)); // We used 20 ms, so the next time for the peer and resolve should be 980 ms mockClock.AdvanceMonotonic(20_ms32); - EXPECT_EQ(attempts.GetTimeUntilNextExpectedResponse(), Optional(980_ms32)); + EXPECT_EQ(attempts.GetTimeUntilNextExpectedResponse(), std::make_optional(980_ms32)); - EXPECT_FALSE(attempts.NextScheduled().HasValue()); + EXPECT_FALSE(attempts.NextScheduled().has_value()); // Add a second Peer mockClock.AdvanceMonotonic(20_ms32); attempts.MarkPending(MakePeerId(2)); - EXPECT_EQ(attempts.GetTimeUntilNextExpectedResponse(), Optional(0_ms32)); + EXPECT_EQ(attempts.GetTimeUntilNextExpectedResponse(), std::make_optional(0_ms32)); EXPECT_EQ(attempts.NextScheduled(), ScheduledPeer(2, true)); - EXPECT_FALSE(attempts.NextScheduled().HasValue()); + EXPECT_FALSE(attempts.NextScheduled().has_value()); // Advance to the retry time of peer 1 and the resolve mockClock.AdvanceMonotonic(960_ms32); - EXPECT_EQ(attempts.GetTimeUntilNextExpectedResponse(), Optional(0_ms32)); + EXPECT_EQ(attempts.GetTimeUntilNextExpectedResponse(), std::make_optional(0_ms32)); EXPECT_EQ(attempts.NextScheduled(), ScheduledPeer(1, false)); EXPECT_EQ(attempts.NextScheduled(), ScheduledBrowse(filter, type, false)); - EXPECT_FALSE(attempts.NextScheduled().HasValue()); + EXPECT_FALSE(attempts.NextScheduled().has_value()); // Complete all, we should see no more scheduled. attempts.Complete(MakePeerId(2)); @@ -377,7 +382,7 @@ TEST(TestActiveResolveAttempts, TestCombination) data.Get().longDiscriminator = 1234; attempts.CompleteCommissionable(data); - EXPECT_FALSE(attempts.GetTimeUntilNextExpectedResponse().HasValue()); - EXPECT_FALSE(attempts.NextScheduled().HasValue()); + EXPECT_FALSE(attempts.GetTimeUntilNextExpectedResponse().has_value()); + EXPECT_FALSE(attempts.NextScheduled().has_value()); } } // namespace diff --git a/src/platform/OpenThread/GenericThreadStackManagerImpl_OpenThread.hpp b/src/platform/OpenThread/GenericThreadStackManagerImpl_OpenThread.hpp index 1c14aeb91dd21d..c28cb86edf0085 100644 --- a/src/platform/OpenThread/GenericThreadStackManagerImpl_OpenThread.hpp +++ b/src/platform/OpenThread/GenericThreadStackManagerImpl_OpenThread.hpp @@ -1738,7 +1738,7 @@ CHIP_ERROR GenericThreadStackManagerImpl_OpenThread::FromOtDnsRespons if (!otIp6IsAddressUnspecified(&serviceInfo.mHostAddress)) { mdnsService.mAddressType = Inet::IPAddressType::kIPv6; - mdnsService.mAddress = MakeOptional(ToIPAddress(serviceInfo.mHostAddress)); + mdnsService.mAddress = std::make_optional(ToIPAddress(serviceInfo.mHostAddress)); } // Check if TXT record was included in DNS response. @@ -1812,9 +1812,9 @@ void GenericThreadStackManagerImpl_OpenThread::DispatchResolve(intptr Dnssd::DnssdService & service = dnsResult->mMdnsService; Span ipAddrs; - if (service.mAddress.HasValue()) + if (service.mAddress.has_value()) { - ipAddrs = Span(&service.mAddress.Value(), 1); + ipAddrs = Span(&*service.mAddress, 1); } ThreadStackMgrImpl().mDnsResolveCallback(dnsResult->context, &service, ipAddrs, dnsResult->error); @@ -1964,7 +1964,7 @@ void GenericThreadStackManagerImpl_OpenThread::OnDnsAddressResolveRes error = MapOpenThreadError(otDnsAddressResponseGetAddress(aResponse, 0, &address, nullptr)); if (error == CHIP_NO_ERROR) { - dnsResult->mMdnsService.mAddress = MakeOptional(ToIPAddress(address)); + dnsResult->mMdnsService.mAddress = std::make_optional(ToIPAddress(address)); } dnsResult->error = error; diff --git a/src/platform/Tizen/DnssdImpl.cpp b/src/platform/Tizen/DnssdImpl.cpp index cc3e5a1e8f76a6..1b57e1811a1495 100644 --- a/src/platform/Tizen/DnssdImpl.cpp +++ b/src/platform/Tizen/DnssdImpl.cpp @@ -354,7 +354,7 @@ void OnResolve(dnssd_error_e result, dnssd_service_h service, void * userData) VerifyOrExit(ret == DNSSD_ERROR_NONE, ChipLogError(DeviceLayer, "dnssd_service_get_all_txt_record() failed: %s", get_error_message(ret))); - rCtx->mResult.mAddress.SetValue(ipAddr); + rCtx->mResult.mAddress.emplace(ipAddr); { // Before calling the Resolve() callback, we need to lock stack mutex. @@ -467,7 +467,7 @@ void ResolveContext::Finalize(CHIP_ERROR error) mResult.mTextEntries = textEntries.empty() ? nullptr : textEntries.data(); mResult.mTextEntrySize = textEntries.size(); - chip::Inet::IPAddress ipAddr = mResult.mAddress.Value(); + chip::Inet::IPAddress ipAddr = mResult.mAddress.value(); mCallback(mCbContext, &mResult, chip::Span(&ipAddr, 1), CHIP_NO_ERROR); } diff --git a/src/platform/nxp/common/DnssdImpl.cpp b/src/platform/nxp/common/DnssdImpl.cpp index 8050da137f26b8..17116f21fc277f 100644 --- a/src/platform/nxp/common/DnssdImpl.cpp +++ b/src/platform/nxp/common/DnssdImpl.cpp @@ -778,9 +778,9 @@ void DispatchResolve(intptr_t context) Dnssd::DnssdService & service = resolveContext->mMdnsService; Span ipAddrs; - if (service.mAddress.HasValue()) + if (service.mAddress.has_value()) { - ipAddrs = Span(&service.mAddress.Value(), 1); + ipAddrs = Span(&*service.mAddress, 1); } mDnsResolveCallback(resolveContext->matterCtx, &service, ipAddrs, resolveContext->error); From 745c17cd10b957aa82683837726c51de316fdf9d Mon Sep 17 00:00:00 2001 From: Mihai Ignat <50373067+mihai-ignat@users.noreply.github.com> Date: Tue, 30 Apr 2024 20:05:54 +0300 Subject: [PATCH 13/33] [nxp][platform][k32w] BLE force disconnect handler calls API to allow low power (#33167) --- src/platform/nxp/k32w/common/BLEManagerCommon.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/platform/nxp/k32w/common/BLEManagerCommon.cpp b/src/platform/nxp/k32w/common/BLEManagerCommon.cpp index 12b32b8e4b71b2..4c9048a3f68192 100644 --- a/src/platform/nxp/k32w/common/BLEManagerCommon.cpp +++ b/src/platform/nxp/k32w/common/BLEManagerCommon.cpp @@ -1075,6 +1075,10 @@ void BLEManagerCommon::HandleForceDisconnect() { ChipLogProgress(DeviceLayer, "Gap_Disconnect() failed."); } + +#if defined(chip_with_low_power) && (chip_with_low_power == 1) + PWR_AllowDeviceToSleep(); +#endif } /******************************************************************************* From a30b439061036455538a61969c5d170167721a6d Mon Sep 17 00:00:00 2001 From: Andrei Litvin Date: Tue, 30 Apr 2024 13:15:25 -0400 Subject: [PATCH 14/33] Some interface cleanup and make AttributeValueEncoder/Decoder more similar (#33028) * Uniform API: provide subject descriptor only for both value encode and decode * Split out AttributeEncodeState and decouple things to use less friend classes * Fix tests * Slight move around based on pahole results, to try to make size differences a bit smaller * Fix typo ... amazingly enough tests still pass, so test read is maybe broken * Two more replacements for state compare logic * Restyle * Fix logic error in Descripto creation for test * Update argument name * Remove useless comments * move AttributeEncodeState to a separate file * Make the copy from a pointer logic cleaner * Fix value passing * Fix const correctness * Fix one more compile * Put back AccessingFabricIndex * Updated back the comments and file layout --------- Co-authored-by: Andrei Litvin --- src/app/AttributeEncodeState.h | 103 ++++++++++++++++++ src/app/AttributeValueEncoder.cpp | 10 +- src/app/AttributeValueEncoder.h | 59 +++------- src/app/BUILD.gn | 1 + src/app/ConcreteAttributePath.h | 2 +- src/app/ReadHandler.cpp | 4 +- src/app/ReadHandler.h | 6 +- src/app/dynamic_server/DynamicDispatcher.cpp | 2 +- src/app/reporting/Engine.cpp | 8 +- src/app/reporting/Engine.h | 3 +- src/app/tests/TestAttributeValueEncoder.cpp | 32 +++++- src/app/tests/TestPowerSourceCluster.cpp | 3 +- src/app/tests/TestReadInteraction.cpp | 4 +- .../tests/integration/chip_im_initiator.cpp | 2 +- .../tests/integration/chip_im_responder.cpp | 5 +- .../util/ember-compatibility-functions.cpp | 15 ++- src/app/util/ember-compatibility-functions.h | 2 +- src/app/util/mock/Functions.h | 2 +- src/app/util/mock/attribute-storage.cpp | 11 +- src/controller/tests/data_model/TestRead.cpp | 35 +++--- 20 files changed, 201 insertions(+), 108 deletions(-) create mode 100644 src/app/AttributeEncodeState.h diff --git a/src/app/AttributeEncodeState.h b/src/app/AttributeEncodeState.h new file mode 100644 index 00000000000000..271e16235f0947 --- /dev/null +++ b/src/app/AttributeEncodeState.h @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2021-2024 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#pragma once + +#include + +namespace chip { +namespace app { + +/// Maintains the internal state of list encoding +/// +/// List encoding is generally assumed incremental and chunkable (i.e. +/// partial encoding is ok.). For this purpose the class maintains two +/// pieces of data: +/// - AllowPartialData tracks if partial encoding is acceptable in the +/// current encoding state (to be used for atomic/non-atomic list item writes) +/// - CurrentEncodingListIndex representing the list index that is next +/// to be encoded in the output. kInvalidListIndex means that a new list +/// encoding has been started. +class AttributeEncodeState +{ +public: + AttributeEncodeState() = default; + + /// Allows the encode state to be initialized from an OPTIONAL + /// other encoding state + /// + /// if other is nullptr, this is the same as the default initializer. + AttributeEncodeState(const AttributeEncodeState * other) + { + if (other != nullptr) + { + *this = *other; + } + else + { + mCurrentEncodingListIndex = kInvalidListIndex; + mAllowPartialData = false; + } + } + + bool AllowPartialData() const { return mAllowPartialData; } + ListIndex CurrentEncodingListIndex() const { return mCurrentEncodingListIndex; } + + AttributeEncodeState & SetAllowPartialData(bool allow) + { + mAllowPartialData = allow; + return *this; + } + + AttributeEncodeState & SetCurrentEncodingListIndex(ListIndex idx) + { + mCurrentEncodingListIndex = idx; + return *this; + } + + void Reset() + { + mCurrentEncodingListIndex = kInvalidListIndex; + mAllowPartialData = false; + } + +private: + /** + * If set to kInvalidListIndex, indicates that we have not encoded any data for the list yet and + * need to start by encoding an empty list before we start encoding any list items. + * + * When set to a valid ListIndex value, indicates the index of the next list item that needs to be + * encoded (i.e. the count of items encoded so far). + */ + ListIndex mCurrentEncodingListIndex = kInvalidListIndex; + + /** + * When an attempt to encode an attribute returns an error, the buffer may contain tailing dirty data + * (since the put was aborted). The report engine normally rolls back the buffer to right before encoding + * of the attribute started on errors. + * + * When chunking a list, EncodeListItem will atomically encode list items, ensuring that the + * state of the buffer is valid to send (i.e. contains no trailing garbage), and return an error + * if the list doesn't entirely fit. In this situation, mAllowPartialData is set to communicate to the + * report engine that it should not roll back the list items. + * + * TODO: There might be a better name for this variable. + */ + bool mAllowPartialData = false; +}; + +} // namespace app +} // namespace chip diff --git a/src/app/AttributeValueEncoder.cpp b/src/app/AttributeValueEncoder.cpp index da4edd1fc483e7..4b6bb10e66abdb 100644 --- a/src/app/AttributeValueEncoder.cpp +++ b/src/app/AttributeValueEncoder.cpp @@ -32,13 +32,13 @@ CHIP_ERROR AttributeValueEncoder::EnsureListStarted() { VerifyOrDie(mCurrentEncodingListIndex == kInvalidListIndex); - mEncodingInitialList = (mEncodeState.mCurrentEncodingListIndex == kInvalidListIndex); + mEncodingInitialList = (mEncodeState.CurrentEncodingListIndex() == kInvalidListIndex); if (mEncodingInitialList) { // Clear mAllowPartialData flag here since this encode procedure is not atomic. // The most common error in this function is CHIP_ERROR_NO_MEMORY / CHIP_ERROR_BUFFER_TOO_SMALL, just revert and try // next time is ok. - mEncodeState.mAllowPartialData = false; + mEncodeState.SetAllowPartialData(false); AttributeReportBuilder builder; @@ -59,7 +59,7 @@ CHIP_ERROR AttributeValueEncoder::EnsureListStarted() ReturnErrorOnFailure( mAttributeReportIBsBuilder.GetWriter()->ReserveBuffer(kEndOfAttributeReportIBByteCount + kEndOfListByteCount)); - mEncodeState.mCurrentEncodingListIndex = 0; + mEncodeState.SetCurrentEncodingListIndex(0); } else { @@ -72,7 +72,7 @@ CHIP_ERROR AttributeValueEncoder::EnsureListStarted() // After encoding the initial list start, the remaining items are atomically encoded into the buffer. Tell report engine to not // revert partial data. - mEncodeState.mAllowPartialData = true; + mEncodeState.SetAllowPartialData(true); return CHIP_NO_ERROR; } @@ -105,7 +105,7 @@ void AttributeValueEncoder::EnsureListEnded() // If we succeeded at encoding the whole list (i.e. the list is in fact // empty and we fit in the packet), mAllowPartialData will be ignored, // so it's safe to set it to false even if encoding succeeded. - mEncodeState.mAllowPartialData = false; + mEncodeState.SetAllowPartialData(false); } } diff --git a/src/app/AttributeValueEncoder.h b/src/app/AttributeValueEncoder.h index d5efe1768c9d06..5c196f91f2e426 100644 --- a/src/app/AttributeValueEncoder.h +++ b/src/app/AttributeValueEncoder.h @@ -16,6 +16,8 @@ */ #pragma once +#include +#include #include #include #include @@ -51,9 +53,9 @@ class AttributeValueEncoder // If we are encoding for a fabric filtered attribute read and the fabric index does not match that present in the // request, skip encoding this list item. VerifyOrReturnError(!mAttributeValueEncoder.mIsFabricFiltered || - aArg.GetFabricIndex() == mAttributeValueEncoder.mAccessingFabricIndex, + aArg.GetFabricIndex() == mAttributeValueEncoder.AccessingFabricIndex(), CHIP_NO_ERROR); - return mAttributeValueEncoder.EncodeListItem(mAttributeValueEncoder.mAccessingFabricIndex, std::forward(aArg)); + return mAttributeValueEncoder.EncodeListItem(mAttributeValueEncoder.AccessingFabricIndex(), std::forward(aArg)); } template ::value, bool> = true> @@ -66,42 +68,11 @@ class AttributeValueEncoder AttributeValueEncoder & mAttributeValueEncoder; }; - class AttributeEncodeState - { - public: - AttributeEncodeState() : mAllowPartialData(false), mCurrentEncodingListIndex(kInvalidListIndex) {} - bool AllowPartialData() const { return mAllowPartialData; } - - private: - friend class AttributeValueEncoder; - /** - * When an attempt to encode an attribute returns an error, the buffer may contain tailing dirty data - * (since the put was aborted). The report engine normally rolls back the buffer to right before encoding - * of the attribute started on errors. - * - * When chunking a list, EncodeListItem will atomically encode list items, ensuring that the - * state of the buffer is valid to send (i.e. contains no trailing garbage), and return an error - * if the list doesn't entirely fit. In this situation, mAllowPartialData is set to communicate to the - * report engine that it should not roll back the list items. - * - * TODO: There might be a better name for this variable. - */ - bool mAllowPartialData = false; - /** - * If set to kInvalidListIndex, indicates that we have not encoded any data for the list yet and - * need to start by encoding an empty list before we start encoding any list items. - * - * When set to a valid ListIndex value, indicates the index of the next list item that needs to be - * encoded (i.e. the count of items encoded so far). - */ - ListIndex mCurrentEncodingListIndex = kInvalidListIndex; - }; - - AttributeValueEncoder(AttributeReportIBs::Builder & aAttributeReportIBsBuilder, FabricIndex aAccessingFabricIndex, + AttributeValueEncoder(AttributeReportIBs::Builder & aAttributeReportIBsBuilder, Access::SubjectDescriptor subjectDescriptor, const ConcreteAttributePath & aPath, DataVersion aDataVersion, bool aIsFabricFiltered = false, const AttributeEncodeState & aState = AttributeEncodeState()) : mAttributeReportIBsBuilder(aAttributeReportIBsBuilder), - mAccessingFabricIndex(aAccessingFabricIndex), mPath(aPath.mEndpointId, aPath.mClusterId, aPath.mAttributeId), + mSubjectDescriptor(subjectDescriptor), mPath(aPath.mEndpointId, aPath.mClusterId, aPath.mAttributeId), mDataVersion(aDataVersion), mIsFabricFiltered(aIsFabricFiltered), mEncodeState(aState) {} @@ -169,17 +140,19 @@ class AttributeValueEncoder if (err == CHIP_NO_ERROR) { // The Encode procedure finished without any error, clear the state. - mEncodeState = AttributeEncodeState(); + mEncodeState.Reset(); } return err; } bool TriedEncode() const { return mTriedEncode; } + const Access::SubjectDescriptor & GetSubjectDescriptor() const { return mSubjectDescriptor; } + /** * The accessing fabric index for this read or subscribe interaction. */ - FabricIndex AccessingFabricIndex() const { return mAccessingFabricIndex; } + FabricIndex AccessingFabricIndex() const { return GetSubjectDescriptor().fabricIndex; } /** * AttributeValueEncoder is a short lived object, and the state is persisted by mEncodeState and restored by constructor. @@ -195,7 +168,7 @@ class AttributeValueEncoder { // EncodeListItem must be called after EnsureListStarted(), thus mCurrentEncodingListIndex and // mEncodeState.mCurrentEncodingListIndex are not invalid values. - if (mCurrentEncodingListIndex < mEncodeState.mCurrentEncodingListIndex) + if (mCurrentEncodingListIndex < mEncodeState.CurrentEncodingListIndex()) { // We have encoded this element in previous chunks, skip it. mCurrentEncodingListIndex++; @@ -226,7 +199,7 @@ class AttributeValueEncoder } mCurrentEncodingListIndex++; - mEncodeState.mCurrentEncodingListIndex++; + mEncodeState.SetCurrentEncodingListIndex(mCurrentEncodingListIndex); mEncodedAtLeastOneListItem = true; return CHIP_NO_ERROR; } @@ -266,20 +239,20 @@ class AttributeValueEncoder */ void EnsureListEnded(); - bool mTriedEncode = false; AttributeReportIBs::Builder & mAttributeReportIBsBuilder; - const FabricIndex mAccessingFabricIndex; + const Access::SubjectDescriptor mSubjectDescriptor; ConcreteDataAttributePath mPath; DataVersion mDataVersion; + bool mTriedEncode = false; bool mIsFabricFiltered = false; // mEncodingInitialList is true if we're encoding a list and we have not // started chunking it yet, so we're encoding a single attribute report IB // for the whole list, not one per item. bool mEncodingInitialList = false; // mEncodedAtLeastOneListItem becomes true once we successfully encode a list item. - bool mEncodedAtLeastOneListItem = false; - AttributeEncodeState mEncodeState; + bool mEncodedAtLeastOneListItem = false; ListIndex mCurrentEncodingListIndex = kInvalidListIndex; + AttributeEncodeState mEncodeState; }; } // namespace app diff --git a/src/app/BUILD.gn b/src/app/BUILD.gn index 042d3ba92281d4..e40847403cd01f 100644 --- a/src/app/BUILD.gn +++ b/src/app/BUILD.gn @@ -281,6 +281,7 @@ static_library("attribute-access") { "AttributeAccessInterfaceCache.h", "AttributeAccessInterfaceRegistry.cpp", "AttributeAccessInterfaceRegistry.h", + "AttributeEncodeState.h", "AttributeReportBuilder.cpp", "AttributeReportBuilder.h", "AttributeValueDecoder.h", diff --git a/src/app/ConcreteAttributePath.h b/src/app/ConcreteAttributePath.h index 03e801bd9b3395..99afb4614e574f 100644 --- a/src/app/ConcreteAttributePath.h +++ b/src/app/ConcreteAttributePath.h @@ -101,7 +101,7 @@ struct ConcreteReadAttributePath : public ConcreteAttributePath */ struct ConcreteDataAttributePath : public ConcreteAttributePath { - enum class ListOperation + enum class ListOperation : uint8_t { NotList, // Path points to an attribute that isn't a list. ReplaceAll, // Path points to an attribute that is a list, indicating that the contents of the list should be replaced in diff --git a/src/app/ReadHandler.cpp b/src/app/ReadHandler.cpp index 142df8015601ca..461add0f2dc150 100644 --- a/src/app/ReadHandler.cpp +++ b/src/app/ReadHandler.cpp @@ -841,7 +841,7 @@ void ReadHandler::PersistSubscription() void ReadHandler::ResetPathIterator() { mAttributePathExpandIterator = AttributePathExpandIterator(mpAttributePathList); - mAttributeEncoderState = AttributeValueEncoder::AttributeEncodeState(); + mAttributeEncoderState.Reset(); } void ReadHandler::AttributePathIsDirty(const AttributePathParams & aAttributeChanged) @@ -870,7 +870,7 @@ void ReadHandler::AttributePathIsDirty(const AttributePathParams & aAttributeCha // our iterator to point back to the beginning of that cluster. This ensures that the receiver will get a coherent view of // the state of the cluster as present on the server mAttributePathExpandIterator.ResetCurrentCluster(); - mAttributeEncoderState = AttributeValueEncoder::AttributeEncodeState(); + mAttributeEncoderState.Reset(); } // ReportScheduler will take care of verifying the reportability of the handler and schedule the run diff --git a/src/app/ReadHandler.h b/src/app/ReadHandler.h index f5355372ac5301..a30f1f8974ad25 100644 --- a/src/app/ReadHandler.h +++ b/src/app/ReadHandler.h @@ -412,8 +412,8 @@ class ReadHandler : public Messaging::ExchangeDelegate /// or after the min interval is reached if it has not yet been reached. void ForceDirtyState(); - const AttributeValueEncoder::AttributeEncodeState & GetAttributeEncodeState() const { return mAttributeEncoderState; } - void SetAttributeEncodeState(const AttributeValueEncoder::AttributeEncodeState & aState) { mAttributeEncoderState = aState; } + const AttributeEncodeState & GetAttributeEncodeState() const { return mAttributeEncoderState; } + void SetAttributeEncodeState(const AttributeEncodeState & aState) { mAttributeEncoderState = aState; } uint32_t GetLastWrittenEventsBytes() const { return mLastWrittenEventsBytes; } // Returns the number of interested paths, including wildcard and concrete paths. @@ -562,7 +562,7 @@ class ReadHandler : public Messaging::ExchangeDelegate // The detailed encoding state for a single attribute, used by list chunking feature. // The size of AttributeEncoderState is 2 bytes for now. - AttributeValueEncoder::AttributeEncodeState mAttributeEncoderState; + AttributeEncodeState mAttributeEncoderState; // Current Handler state HandlerState mState = HandlerState::Idle; diff --git a/src/app/dynamic_server/DynamicDispatcher.cpp b/src/app/dynamic_server/DynamicDispatcher.cpp index 5f9476aa6fd40a..e1f458f0bc3df1 100644 --- a/src/app/dynamic_server/DynamicDispatcher.cpp +++ b/src/app/dynamic_server/DynamicDispatcher.cpp @@ -123,7 +123,7 @@ Status DetermineAttributeStatus(const ConcreteAttributePath & aPath, bool aIsWri CHIP_ERROR ReadSingleClusterData(const SubjectDescriptor & aSubjectDescriptor, bool aIsFabricFiltered, const ConcreteReadAttributePath & aPath, AttributeReportIBs::Builder & aAttributeReports, - AttributeValueEncoder::AttributeEncodeState * aEncoderState) + AttributeEncodeState * aEncoderState) { Status status = DetermineAttributeStatus(aPath, /* aIsWrite = */ false); return aAttributeReports.EncodeAttributeStatus(aPath, StatusIB(status)); diff --git a/src/app/reporting/Engine.cpp b/src/app/reporting/Engine.cpp index 37c7e31dd645fb..39c582f3e45f0b 100644 --- a/src/app/reporting/Engine.cpp +++ b/src/app/reporting/Engine.cpp @@ -82,7 +82,7 @@ bool Engine::IsClusterDataVersionMatch(const SingleLinkedListNode Cluster %" PRIx32 ", Attribute %" PRIx32 " is dirty", aPath.mClusterId, aPath.mAttributeId); @@ -199,7 +199,7 @@ CHIP_ERROR Engine::BuildSingleReportDataAttributeReportIBs(ReportDataMessage::Bu attributeReportIBs.Checkpoint(attributeBackup); ConcreteReadAttributePath pathForRetrieval(readPath); // Load the saved state from previous encoding session for chunking of one single attribute (list chunking). - AttributeValueEncoder::AttributeEncodeState encodeState = apReadHandler->GetAttributeEncodeState(); + AttributeEncodeState encodeState = apReadHandler->GetAttributeEncodeState(); err = RetrieveClusterData(apReadHandler->GetSubjectDescriptor(), apReadHandler->IsFabricFiltered(), attributeReportIBs, pathForRetrieval, &encodeState); if (err != CHIP_NO_ERROR) @@ -226,7 +226,7 @@ CHIP_ERROR Engine::BuildSingleReportDataAttributeReportIBs(ReportDataMessage::Bu // We met a error during writing reports, one common case is we are running out of buffer, rollback the // attributeReportIB to avoid any partial data. attributeReportIBs.Rollback(attributeBackup); - apReadHandler->SetAttributeEncodeState(AttributeValueEncoder::AttributeEncodeState()); + apReadHandler->SetAttributeEncodeState(AttributeEncodeState()); if (!IsOutOfWriterSpaceError(err)) { @@ -256,7 +256,7 @@ CHIP_ERROR Engine::BuildSingleReportDataAttributeReportIBs(ReportDataMessage::Bu } SuccessOrExit(err); // Successfully encoded the attribute, clear the internal state. - apReadHandler->SetAttributeEncodeState(AttributeValueEncoder::AttributeEncodeState()); + apReadHandler->SetAttributeEncodeState(AttributeEncodeState()); } // We just visited all paths interested by this read handler and did not abort in the middle of iteration, there are no more // chunks for this report. diff --git a/src/app/reporting/Engine.h b/src/app/reporting/Engine.h index fccf9e08ab020f..0bf7a9f83de1ae 100644 --- a/src/app/reporting/Engine.h +++ b/src/app/reporting/Engine.h @@ -170,8 +170,7 @@ class Engine bool aBufferIsUsed, bool * apHasMoreChunks, bool * apHasEncodedData); CHIP_ERROR RetrieveClusterData(const Access::SubjectDescriptor & aSubjectDescriptor, bool aIsFabricFiltered, AttributeReportIBs::Builder & aAttributeReportIBs, - const ConcreteReadAttributePath & aClusterInfo, - AttributeValueEncoder::AttributeEncodeState * apEncoderState); + const ConcreteReadAttributePath & aClusterInfo, AttributeEncodeState * apEncoderState); CHIP_ERROR CheckAccessDeniedEventPaths(TLV::TLVWriter & aWriter, bool & aHasEncodedData, ReadHandler * apReadHandler); // If version match, it means don't send, if version mismatch, it means send. diff --git a/src/app/tests/TestAttributeValueEncoder.cpp b/src/app/tests/TestAttributeValueEncoder.cpp index 25ea87736c84e8..085c4f870cdf64 100644 --- a/src/app/tests/TestAttributeValueEncoder.cpp +++ b/src/app/tests/TestAttributeValueEncoder.cpp @@ -49,15 +49,37 @@ constexpr ClusterId kRandomClusterId = 0xaa; constexpr AttributeId kRandomAttributeId = 0xcc; constexpr DataVersion kRandomDataVersion = 0x99; constexpr FabricIndex kTestFabricIndex = 1; +constexpr NodeId kFakeNodeId = 1; constexpr TLV::Tag kFabricIndexTag = TLV::ContextTag(254); +Access::SubjectDescriptor DescriptorWithFabric(FabricIndex fabricIndex) +{ + Access::SubjectDescriptor result; + + result.fabricIndex = fabricIndex; + result.subject = kFakeNodeId; + + if (fabricIndex == kUndefinedFabricIndex) + { + // Make it seem somewhat valid: a fabric index is not available in PASE + // before AddNOC + result.authMode = Access::AuthMode::kPase; + } + else + { + result.authMode = Access::AuthMode::kCase; + } + return result; +} + template struct LimitedTestSetup { LimitedTestSetup(nlTestSuite * aSuite, const FabricIndex aFabricIndex = kUndefinedFabricIndex, - const AttributeValueEncoder::AttributeEncodeState & aState = AttributeValueEncoder::AttributeEncodeState()) : - encoder(builder, aFabricIndex, ConcreteAttributePath(kRandomEndpointId, kRandomClusterId, kRandomAttributeId), - kRandomDataVersion, aFabricIndex != kUndefinedFabricIndex, aState) + const AttributeEncodeState & aState = AttributeEncodeState()) : + encoder(builder, DescriptorWithFabric(aFabricIndex), + ConcreteAttributePath(kRandomEndpointId, kRandomClusterId, kRandomAttributeId), kRandomDataVersion, + aFabricIndex != kUndefinedFabricIndex, aState) { writer.Init(buf); { @@ -275,7 +297,7 @@ void TestEncodeFabricScoped(nlTestSuite * aSuite, void * aContext) void TestEncodeListChunking(nlTestSuite * aSuite, void * aContext) { - AttributeValueEncoder::AttributeEncodeState state; + AttributeEncodeState state; bool list[] = { true, false, false, true, true, false }; auto listEncoder = [&list](const auto & encoder) -> CHIP_ERROR { @@ -400,7 +422,7 @@ void TestEncodeListChunking(nlTestSuite * aSuite, void * aContext) void TestEncodeListChunking2(nlTestSuite * aSuite, void * aContext) { - AttributeValueEncoder::AttributeEncodeState state; + AttributeEncodeState state; bool list[] = { true, false, false, true, true, false }; auto listEncoder = [&list](const auto & encoder) -> CHIP_ERROR { diff --git a/src/app/tests/TestPowerSourceCluster.cpp b/src/app/tests/TestPowerSourceCluster.cpp index 46371b332a1804..374b9619d38684 100644 --- a/src/app/tests/TestPowerSourceCluster.cpp +++ b/src/app/tests/TestPowerSourceCluster.cpp @@ -80,7 +80,8 @@ std::vector ReadEndpointsThroughAttributeReader(nlTestSuite * apSuit ConcreteAttributePath path(endpoint, Clusters::PowerSource::Id, Clusters::PowerSource::Attributes::EndpointList::Id); ConcreteReadAttributePath readPath(path); chip::DataVersion dataVersion(0); - AttributeValueEncoder aEncoder(builder, 0, path, dataVersion); + Access::SubjectDescriptor subjectDescriptor; + AttributeValueEncoder aEncoder(builder, subjectDescriptor, path, dataVersion); err = attrAccess.Read(readPath, aEncoder); diff --git a/src/app/tests/TestReadInteraction.cpp b/src/app/tests/TestReadInteraction.cpp index eacd9a1d6f7762..8173761b6ca83a 100644 --- a/src/app/tests/TestReadInteraction.cpp +++ b/src/app/tests/TestReadInteraction.cpp @@ -303,7 +303,7 @@ namespace app { CHIP_ERROR ReadSingleClusterData(const Access::SubjectDescriptor & aSubjectDescriptor, bool aIsFabricFiltered, const ConcreteReadAttributePath & aPath, AttributeReportIBs::Builder & aAttributeReports, - AttributeValueEncoder::AttributeEncodeState * apEncoderState) + AttributeEncodeState * apEncoderState) { if (aPath.mClusterId >= Test::kMockEndpointMin) { @@ -331,7 +331,7 @@ CHIP_ERROR ReadSingleClusterData(const Access::SubjectDescriptor & aSubjectDescr return attributeReport.EndOfAttributeReportIB(); } - return AttributeValueEncoder(aAttributeReports, 0, aPath, 0).Encode(kTestFieldValue1); + return AttributeValueEncoder(aAttributeReports, aSubjectDescriptor, aPath, 0 /* dataVersion */).Encode(kTestFieldValue1); } bool IsClusterDataVersionEqual(const ConcreteClusterPath & aConcreteClusterPath, DataVersion aRequiredVersion) diff --git a/src/app/tests/integration/chip_im_initiator.cpp b/src/app/tests/integration/chip_im_initiator.cpp index 56cd7f37005ce5..48a66cb7fc2bba 100644 --- a/src/app/tests/integration/chip_im_initiator.cpp +++ b/src/app/tests/integration/chip_im_initiator.cpp @@ -631,7 +631,7 @@ void DispatchSingleClusterCommand(const ConcreteCommandPath & aCommandPath, chip CHIP_ERROR ReadSingleClusterData(const Access::SubjectDescriptor & aSubjectDescriptor, bool aIsFabricFiltered, const ConcreteReadAttributePath & aPath, AttributeReportIBs::Builder & aAttributeReports, - AttributeValueEncoder::AttributeEncodeState * apEncoderState) + AttributeEncodeState * apEncoderState) { AttributeReportIB::Builder & attributeReport = aAttributeReports.CreateAttributeReport(); ReturnErrorOnFailure(aAttributeReports.GetError()); diff --git a/src/app/tests/integration/chip_im_responder.cpp b/src/app/tests/integration/chip_im_responder.cpp index 0250cd0fbc7e69..72f056ca6ab8b7 100644 --- a/src/app/tests/integration/chip_im_responder.cpp +++ b/src/app/tests/integration/chip_im_responder.cpp @@ -121,10 +121,9 @@ void DispatchSingleClusterCommand(const ConcreteCommandPath & aRequestCommandPat CHIP_ERROR ReadSingleClusterData(const Access::SubjectDescriptor & aSubjectDescriptor, bool aIsFabricFiltered, const ConcreteReadAttributePath & aPath, AttributeReportIBs::Builder & aAttributeReports, - AttributeValueEncoder::AttributeEncodeState * apEncoderState) + AttributeEncodeState * apEncoderState) { - ReturnErrorOnFailure(AttributeValueEncoder(aAttributeReports, 0, aPath, 0).Encode(kTestFieldValue1)); - return CHIP_NO_ERROR; + return AttributeValueEncoder(aAttributeReports, aSubjectDescriptor, aPath, 0).Encode(kTestFieldValue1); } bool ConcreteAttributePathExists(const ConcreteAttributePath & aPath) diff --git a/src/app/util/ember-compatibility-functions.cpp b/src/app/util/ember-compatibility-functions.cpp index 3c98863aa50fb1..e87e0f564a5ff7 100644 --- a/src/app/util/ember-compatibility-functions.cpp +++ b/src/app/util/ember-compatibility-functions.cpp @@ -425,16 +425,15 @@ CHIP_ERROR GlobalAttributeReader::EncodeCommandList(const ConcreteClusterPath & // Helper function for trying to read an attribute value via an // AttributeAccessInterface. On failure, the read has failed. On success, the // aTriedEncode outparam is set to whether the AttributeAccessInterface tried to encode a value. -CHIP_ERROR ReadViaAccessInterface(FabricIndex aAccessingFabricIndex, bool aIsFabricFiltered, +CHIP_ERROR ReadViaAccessInterface(const SubjectDescriptor & subjectDescriptor, bool aIsFabricFiltered, const ConcreteReadAttributePath & aPath, AttributeReportIBs::Builder & aAttributeReports, - AttributeValueEncoder::AttributeEncodeState * aEncoderState, - AttributeAccessInterface * aAccessInterface, bool * aTriedEncode) + AttributeEncodeState * aEncoderState, AttributeAccessInterface * aAccessInterface, + bool * aTriedEncode) { - AttributeValueEncoder::AttributeEncodeState state = - (aEncoderState == nullptr ? AttributeValueEncoder::AttributeEncodeState() : *aEncoderState); + AttributeEncodeState state(aEncoderState); DataVersion version = 0; ReturnErrorOnFailure(ReadClusterDataVersion(aPath, version)); - AttributeValueEncoder valueEncoder(aAttributeReports, aAccessingFabricIndex, aPath, version, aIsFabricFiltered, state); + AttributeValueEncoder valueEncoder(aAttributeReports, subjectDescriptor, aPath, version, aIsFabricFiltered, state); CHIP_ERROR err = aAccessInterface->Read(aPath, valueEncoder); if (err == CHIP_IM_GLOBAL_STATUS(UnsupportedRead) && aPath.mExpanded) @@ -523,7 +522,7 @@ bool ConcreteAttributePathExists(const ConcreteAttributePath & aPath) CHIP_ERROR ReadSingleClusterData(const SubjectDescriptor & aSubjectDescriptor, bool aIsFabricFiltered, const ConcreteReadAttributePath & aPath, AttributeReportIBs::Builder & aAttributeReports, - AttributeValueEncoder::AttributeEncodeState * apEncoderState) + AttributeEncodeState * apEncoderState) { ChipLogDetail(DataManagement, "Reading attribute: Cluster=" ChipLogFormatMEI " Endpoint=%x AttributeId=" ChipLogFormatMEI " (expanded=%d)", @@ -569,7 +568,7 @@ CHIP_ERROR ReadSingleClusterData(const SubjectDescriptor & aSubjectDescriptor, b if (attributeOverride) { bool triedEncode = false; - ReturnErrorOnFailure(ReadViaAccessInterface(aSubjectDescriptor.fabricIndex, aIsFabricFiltered, aPath, aAttributeReports, + ReturnErrorOnFailure(ReadViaAccessInterface(aSubjectDescriptor, aIsFabricFiltered, aPath, aAttributeReports, apEncoderState, attributeOverride, &triedEncode)); ReturnErrorCodeIf(triedEncode, CHIP_NO_ERROR); } diff --git a/src/app/util/ember-compatibility-functions.h b/src/app/util/ember-compatibility-functions.h index 72d4379bce69f0..ca7f16950bad39 100644 --- a/src/app/util/ember-compatibility-functions.h +++ b/src/app/util/ember-compatibility-functions.h @@ -60,7 +60,7 @@ bool ConcreteAttributePathExists(const ConcreteAttributePath & aPath); */ CHIP_ERROR ReadSingleClusterData(const Access::SubjectDescriptor & aSubjectDescriptor, bool aIsFabricFiltered, const ConcreteReadAttributePath & aPath, AttributeReportIBs::Builder & aAttributeReports, - AttributeValueEncoder::AttributeEncodeState * apEncoderState); + AttributeEncodeState * apEncoderState); /** * Returns the metadata of the attribute for the given path. diff --git a/src/app/util/mock/Functions.h b/src/app/util/mock/Functions.h index 2304d54c589787..6d58e6370cf39d 100644 --- a/src/app/util/mock/Functions.h +++ b/src/app/util/mock/Functions.h @@ -35,7 +35,7 @@ namespace Test { CHIP_ERROR ReadSingleMockClusterData(FabricIndex aAccessingFabricIndex, const app::ConcreteAttributePath & aPath, app::AttributeReportIBs::Builder & aAttributeReports, - app::AttributeValueEncoder::AttributeEncodeState * apEncoderState); + app::AttributeEncodeState * apEncoderState); /// Increase the current value for `GetVersion` void BumpVersion(); diff --git a/src/app/util/mock/attribute-storage.cpp b/src/app/util/mock/attribute-storage.cpp index 7326886851ff37..2293a48a8403e4 100644 --- a/src/app/util/mock/attribute-storage.cpp +++ b/src/app/util/mock/attribute-storage.cpp @@ -321,8 +321,7 @@ DataVersion GetVersion() } CHIP_ERROR ReadSingleMockClusterData(FabricIndex aAccessingFabricIndex, const ConcreteAttributePath & aPath, - AttributeReportIBs::Builder & aAttributeReports, - AttributeValueEncoder::AttributeEncodeState * apEncoderState) + AttributeReportIBs::Builder & aAttributeReports, AttributeEncodeState * apEncoderState) { bool dataExists = (emberAfGetServerAttributeIndexByAttributeId(aPath.mEndpointId, aPath.mClusterId, aPath.mAttributeId) != UINT16_MAX); @@ -351,9 +350,11 @@ CHIP_ERROR ReadSingleMockClusterData(FabricIndex aAccessingFabricIndex, const Co // Attribute 4 acts as a large attribute to trigger chunking. if (aPath.mAttributeId == MockAttributeId(4)) { - AttributeValueEncoder::AttributeEncodeState state = - (apEncoderState == nullptr ? AttributeValueEncoder::AttributeEncodeState() : *apEncoderState); - AttributeValueEncoder valueEncoder(aAttributeReports, aAccessingFabricIndex, aPath, dataVersion, false, state); + AttributeEncodeState state(apEncoderState); + Access::SubjectDescriptor subject; + subject.fabricIndex = aAccessingFabricIndex; + + AttributeValueEncoder valueEncoder(aAttributeReports, subject, aPath, dataVersion, /* aIsFabricFiltered = */ false, state); CHIP_ERROR err = valueEncoder.EncodeList([](const auto & encoder) -> CHIP_ERROR { for (int i = 0; i < 6; i++) diff --git a/src/controller/tests/data_model/TestRead.cpp b/src/controller/tests/data_model/TestRead.cpp index fc2cfaf516524b..bcf0233662d2bc 100644 --- a/src/controller/tests/data_model/TestRead.cpp +++ b/src/controller/tests/data_model/TestRead.cpp @@ -89,7 +89,7 @@ namespace chip { namespace app { CHIP_ERROR ReadSingleClusterData(const Access::SubjectDescriptor & aSubjectDescriptor, bool aIsFabricFiltered, const ConcreteReadAttributePath & aPath, AttributeReportIBs::Builder & aAttributeReports, - AttributeValueEncoder::AttributeEncodeState * apEncoderState) + AttributeEncodeState * apEncoderState) { if (aPath.mEndpointId >= chip::Test::kMockEndpointMin) { @@ -109,10 +109,8 @@ CHIP_ERROR ReadSingleClusterData(const Access::SubjectDescriptor & aSubjectDescr // Use an incorrect attribute id for some of the responses. path.mAttributeId = static_cast(path.mAttributeId + (i / 2) + (responseDirective == kSendManyDataResponsesWrongPath)); - AttributeValueEncoder::AttributeEncodeState state = - (apEncoderState == nullptr ? AttributeValueEncoder::AttributeEncodeState() : *apEncoderState); - AttributeValueEncoder valueEncoder(aAttributeReports, aSubjectDescriptor.fabricIndex, path, - kDataVersion /* data version */, aIsFabricFiltered, state); + AttributeEncodeState state(apEncoderState); + AttributeValueEncoder valueEncoder(aAttributeReports, aSubjectDescriptor, path, kDataVersion, aIsFabricFiltered, state); ReturnErrorOnFailure(valueEncoder.Encode(true)); } @@ -124,10 +122,9 @@ CHIP_ERROR ReadSingleClusterData(const Access::SubjectDescriptor & aSubjectDescr if (aPath.mClusterId == app::Clusters::UnitTesting::Id && aPath.mAttributeId == app::Clusters::UnitTesting::Attributes::ListFabricScoped::Id) { - AttributeValueEncoder::AttributeEncodeState state = - (apEncoderState == nullptr ? AttributeValueEncoder::AttributeEncodeState() : *apEncoderState); - AttributeValueEncoder valueEncoder(aAttributeReports, aSubjectDescriptor.fabricIndex, aPath, - kDataVersion /* data version */, aIsFabricFiltered, state); + AttributeEncodeState state(apEncoderState); + AttributeValueEncoder valueEncoder(aAttributeReports, aSubjectDescriptor, aPath, kDataVersion, aIsFabricFiltered, + state); return valueEncoder.EncodeList([aSubjectDescriptor](const auto & encoder) -> CHIP_ERROR { app::Clusters::UnitTesting::Structs::TestFabricScoped::Type val; @@ -141,19 +138,18 @@ CHIP_ERROR ReadSingleClusterData(const Access::SubjectDescriptor & aSubjectDescr if (aPath.mClusterId == app::Clusters::UnitTesting::Id && aPath.mAttributeId == app::Clusters::UnitTesting::Attributes::Int16u::Id) { - AttributeValueEncoder::AttributeEncodeState state = - (apEncoderState == nullptr ? AttributeValueEncoder::AttributeEncodeState() : *apEncoderState); - AttributeValueEncoder valueEncoder(aAttributeReports, aSubjectDescriptor.fabricIndex, aPath, - kDataVersion /* data version */, aIsFabricFiltered, state); + AttributeEncodeState state(apEncoderState); + AttributeValueEncoder valueEncoder(aAttributeReports, aSubjectDescriptor, aPath, kDataVersion, aIsFabricFiltered, + state); return valueEncoder.Encode(++totalReadCount); } if (aPath.mClusterId == kPerpetualClusterId || (aPath.mClusterId == app::Clusters::UnitTesting::Id && aPath.mAttributeId == kPerpetualAttributeid)) { - AttributeValueEncoder::AttributeEncodeState state = AttributeValueEncoder::AttributeEncodeState(); - AttributeValueEncoder valueEncoder(aAttributeReports, aSubjectDescriptor.fabricIndex, aPath, - kDataVersion /* data version */, aIsFabricFiltered, state); + AttributeEncodeState state; + AttributeValueEncoder valueEncoder(aAttributeReports, aSubjectDescriptor, aPath, kDataVersion, aIsFabricFiltered, + state); CHIP_ERROR err = valueEncoder.EncodeList([](const auto & encoder) -> CHIP_ERROR { encoder.Encode(static_cast(1)); @@ -174,10 +170,9 @@ CHIP_ERROR ReadSingleClusterData(const Access::SubjectDescriptor & aSubjectDescr if (aPath.mClusterId == app::Clusters::IcdManagement::Id && aPath.mAttributeId == app::Clusters::IcdManagement::Attributes::OperatingMode::Id) { - AttributeValueEncoder::AttributeEncodeState state = - (apEncoderState == nullptr ? AttributeValueEncoder::AttributeEncodeState() : *apEncoderState); - AttributeValueEncoder valueEncoder(aAttributeReports, aSubjectDescriptor.fabricIndex, aPath, - kDataVersion /* data version */, aIsFabricFiltered, state); + AttributeEncodeState state(apEncoderState); + AttributeValueEncoder valueEncoder(aAttributeReports, aSubjectDescriptor, aPath, kDataVersion, aIsFabricFiltered, + state); return valueEncoder.Encode(isLitIcd ? Clusters::IcdManagement::OperatingModeEnum::kLit : Clusters::IcdManagement::OperatingModeEnum::kSit); From 1b9d971c8d55a3adb84ca618e26ad45f9c1dac38 Mon Sep 17 00:00:00 2001 From: Wang Qixiang <43193572+wqx6@users.noreply.github.com> Date: Wed, 1 May 2024 01:17:13 +0800 Subject: [PATCH 15/33] chef: Use -u flag to force linking non-weak functions for esp32 example (#33209) --- examples/chef/common/stubs.cpp | 4 ++++ examples/chef/esp32/main/CMakeLists.txt | 3 +++ 2 files changed, 7 insertions(+) diff --git a/examples/chef/common/stubs.cpp b/examples/chef/common/stubs.cpp index 91a7b5a84d10e1..5756aaa35b7e26 100644 --- a/examples/chef/common/stubs.cpp +++ b/examples/chef/common/stubs.cpp @@ -235,3 +235,7 @@ void emberAfWakeOnLanClusterInitCallback(EndpointId endpoint) WakeOnLan::SetDefaultDelegate(endpoint, &wakeOnLanManager); } #endif + +// No-op function, used to force linking this file, +// instead of the weak functions from other files +extern "C" void chef_include_stubs_impl(void) {} diff --git a/examples/chef/esp32/main/CMakeLists.txt b/examples/chef/esp32/main/CMakeLists.txt index 75cf0b85222d95..549f98abcfac9c 100644 --- a/examples/chef/esp32/main/CMakeLists.txt +++ b/examples/chef/esp32/main/CMakeLists.txt @@ -121,6 +121,9 @@ idf_component_register(PRIV_INCLUDE_DIRS PRIV_REQUIRES chip nvs_flash bt console mbedtls QRCode tft screen-framework spidriver SRC_DIRS ${SRC_DIRS_LIST}) +# Forces the linker to include common/stubs.cpp +target_link_libraries(${COMPONENT_LIB} INTERFACE "-u chef_include_stubs_impl") + include("${CHIP_ROOT}/build/chip/esp32/esp32_codegen.cmake") chip_app_component_codegen("${CHEF}/devices/${SAMPLE_NAME}.matter") chip_app_component_zapgen("${CHEF}/devices/${SAMPLE_NAME}.zap") From 4b58ad287f56215c757a64b6e6736727f7969bf2 Mon Sep 17 00:00:00 2001 From: Wang Qixiang <43193572+wqx6@users.noreply.github.com> Date: Wed, 1 May 2024 02:40:08 +0800 Subject: [PATCH 16/33] examples: Remove requires in main components for esp32 examples (#33213) --- .../all-clusters-app/esp32/main/CMakeLists.txt | 17 +++-------------- .../esp32/main/CMakeLists.txt | 15 ++------------- examples/bridge-app/esp32/main/CMakeLists.txt | 3 +-- examples/chef/esp32/main/CMakeLists.txt | 1 - .../esp32/main/CMakeLists.txt | 9 +-------- .../light-switch-app/esp32/main/CMakeLists.txt | 4 ++-- examples/lighting-app/esp32/main/CMakeLists.txt | 10 +--------- examples/lock-app/esp32/main/CMakeLists.txt | 4 ++-- .../ota-provider-app/esp32/main/CMakeLists.txt | 3 +-- .../ota-requestor-app/esp32/main/CMakeLists.txt | 5 +---- .../esp32/main/CMakeLists.txt | 3 +-- examples/pigweed-app/esp32/main/CMakeLists.txt | 3 +-- examples/shell/esp32/main/CMakeLists.txt | 3 +-- .../esp32/main/CMakeLists.txt | 3 --- 14 files changed, 17 insertions(+), 66 deletions(-) diff --git a/examples/all-clusters-app/esp32/main/CMakeLists.txt b/examples/all-clusters-app/esp32/main/CMakeLists.txt index 63851b1deeb611..7fd1d548609257 100644 --- a/examples/all-clusters-app/esp32/main/CMakeLists.txt +++ b/examples/all-clusters-app/esp32/main/CMakeLists.txt @@ -96,8 +96,8 @@ set(SRC_DIRS_LIST "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/time-synchronization-server" "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/valve-configuration-and-control-server" "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/dishwasher-alarm-server" - "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/laundry-washer-controls-server" - "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/laundry-washer-controls-server" + "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/laundry-washer-controls-server" + "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/laundry-washer-controls-server" "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/laundry-dryer-controls-server" "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/examples/all-clusters-app/all-clusters-common/src" "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/energy-preference-server" @@ -136,20 +136,9 @@ if (CONFIG_ENABLE_ICD_SERVER) list(APPEND SRC_DIRS_LIST "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/examples/platform/esp32/icd") endif() -set(PRIV_REQUIRES_LIST chip QRCode bt app_update nvs_flash spi_flash openthread) - -if(${IDF_TARGET} STREQUAL "esp32") - list(APPEND PRIV_REQUIRES_LIST spidriver screen-framework) -endif() - -if(CONFIG_DEVICE_TYPE_ESP32_C3_DEVKITM) - list(APPEND PRIV_REQUIRES_LIST led_strip) -endif() - idf_component_register(PRIV_INCLUDE_DIRS ${PRIV_INCLUDE_DIRS_LIST} SRC_DIRS ${SRC_DIRS_LIST} - EXCLUDE_SRCS ${EXCLUDE_SRCS} - PRIV_REQUIRES ${PRIV_REQUIRES_LIST}) + EXCLUDE_SRCS ${EXCLUDE_SRCS}) get_filename_component(CHIP_ROOT ${CMAKE_SOURCE_DIR}/third_party/connectedhomeip REALPATH) diff --git a/examples/all-clusters-minimal-app/esp32/main/CMakeLists.txt b/examples/all-clusters-minimal-app/esp32/main/CMakeLists.txt index cae8b64315a232..7178945c7eb21c 100644 --- a/examples/all-clusters-minimal-app/esp32/main/CMakeLists.txt +++ b/examples/all-clusters-minimal-app/esp32/main/CMakeLists.txt @@ -82,7 +82,7 @@ set(SRC_DIRS_LIST "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/door-lock-server" "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/occupancy-sensor-server" "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/device-energy-management-server" - "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/energy-evse-server" + "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/energy-evse-server" "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/ethernet-network-diagnostics-server" "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/localization-configuration-server" "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/time-format-localization-server" @@ -118,19 +118,8 @@ set(SRC_DIRS_LIST "${SRC_DIRS_LIST}" ) endif (CONFIG_ENABLE_PW_RPC) -set(PRIV_REQUIRES_LIST chip QRCode bt driver app_update nvs_flash spi_flash openthread) - -if(${IDF_TARGET} STREQUAL "esp32") - list(APPEND PRIV_REQUIRES_LIST spidriver screen-framework) -endif() - -if(CONFIG_DEVICE_TYPE_ESP32_C3_DEVKITM) - list(APPEND PRIV_REQUIRES_LIST led_strip) -endif() - idf_component_register(PRIV_INCLUDE_DIRS ${PRIV_INCLUDE_DIRS_LIST} - SRC_DIRS ${SRC_DIRS_LIST} - PRIV_REQUIRES ${PRIV_REQUIRES_LIST}) + SRC_DIRS ${SRC_DIRS_LIST}) get_filename_component(CHIP_ROOT ${CMAKE_SOURCE_DIR}/third_party/connectedhomeip REALPATH) diff --git a/examples/bridge-app/esp32/main/CMakeLists.txt b/examples/bridge-app/esp32/main/CMakeLists.txt index e2250f001799b5..3330f6971b68cd 100644 --- a/examples/bridge-app/esp32/main/CMakeLists.txt +++ b/examples/bridge-app/esp32/main/CMakeLists.txt @@ -48,8 +48,7 @@ idf_component_register(PRIV_INCLUDE_DIRS "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/operational-credentials-server" "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/general-commissioning-server" "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/examples/platform/esp32/common" - "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/examples/providers" - PRIV_REQUIRES chip QRCode bt nvs_flash) + "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/examples/providers") get_filename_component(CHIP_ROOT ${CMAKE_SOURCE_DIR}/third_party/connectedhomeip REALPATH) diff --git a/examples/chef/esp32/main/CMakeLists.txt b/examples/chef/esp32/main/CMakeLists.txt index 549f98abcfac9c..ac436a7919637b 100644 --- a/examples/chef/esp32/main/CMakeLists.txt +++ b/examples/chef/esp32/main/CMakeLists.txt @@ -118,7 +118,6 @@ endif (CONFIG_ENABLE_PW_RPC) idf_component_register(PRIV_INCLUDE_DIRS "${CHIP_SHELL_DIR}/shell_common/include" "${PRIV_INCLUDE_DIRS_LIST}" - PRIV_REQUIRES chip nvs_flash bt console mbedtls QRCode tft screen-framework spidriver SRC_DIRS ${SRC_DIRS_LIST}) # Forces the linker to include common/stubs.cpp diff --git a/examples/energy-management-app/esp32/main/CMakeLists.txt b/examples/energy-management-app/esp32/main/CMakeLists.txt index a38ce499bc1ea5..a9a8c4100ae2de 100644 --- a/examples/energy-management-app/esp32/main/CMakeLists.txt +++ b/examples/energy-management-app/esp32/main/CMakeLists.txt @@ -72,12 +72,6 @@ set(SRC_DIRS_LIST "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/electrical-power-measurement-server" ) -set(PRIV_REQUIRES_LIST chip QRCode bt led_strip app_update openthread driver nvs_flash spi_flash) - -if(${IDF_TARGET} STREQUAL "esp32") - list(APPEND PRIV_REQUIRES_LIST spidriver screen-framework) -endif() - if (CONFIG_ENABLE_PW_RPC) # Append additional directories for RPC build @@ -103,8 +97,7 @@ set(SRC_DIRS_LIST "${SRC_DIRS_LIST}" endif (CONFIG_ENABLE_PW_RPC) idf_component_register(PRIV_INCLUDE_DIRS ${PRIV_INCLUDE_DIRS_LIST} - SRC_DIRS ${SRC_DIRS_LIST} - PRIV_REQUIRES ${PRIV_REQUIRES_LIST}) + SRC_DIRS ${SRC_DIRS_LIST}) get_filename_component(CHIP_ROOT ${CMAKE_SOURCE_DIR}/third_party/connectedhomeip REALPATH) include("${CHIP_ROOT}/build/chip/esp32/esp32_codegen.cmake") diff --git a/examples/light-switch-app/esp32/main/CMakeLists.txt b/examples/light-switch-app/esp32/main/CMakeLists.txt index 210cbcefee9a23..e2600438b55346 100644 --- a/examples/light-switch-app/esp32/main/CMakeLists.txt +++ b/examples/light-switch-app/esp32/main/CMakeLists.txt @@ -59,8 +59,8 @@ idf_component_register(PRIV_INCLUDE_DIRS "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/groups-server" "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/group-key-mgmt-server" "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/time-synchronization-server" - "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/icd-management-server" - PRIV_REQUIRES chip QRCode bt app_update driver nvs_flash spi_flash) + "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/icd-management-server") + get_filename_component(CHIP_ROOT ${CMAKE_SOURCE_DIR}/third_party/connectedhomeip REALPATH) include("${CHIP_ROOT}/build/chip/esp32/esp32_codegen.cmake") diff --git a/examples/lighting-app/esp32/main/CMakeLists.txt b/examples/lighting-app/esp32/main/CMakeLists.txt index a7cc4136145981..8b2a2fdce397cb 100644 --- a/examples/lighting-app/esp32/main/CMakeLists.txt +++ b/examples/lighting-app/esp32/main/CMakeLists.txt @@ -67,13 +67,6 @@ set(SRC_DIRS_LIST "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/scenes-server" ) -set(PRIV_REQUIRES_LIST chip QRCode bt led_strip app_update openthread driver nvs_flash spi_flash) - -if(${IDF_TARGET} STREQUAL "esp32") - list(APPEND PRIV_REQUIRES_LIST spidriver screen-framework) -endif() - - if (CONFIG_ENABLE_PW_RPC) # Append additional directories for RPC build set(PRIV_INCLUDE_DIRS_LIST "${PRIV_INCLUDE_DIRS_LIST}" @@ -98,8 +91,7 @@ set(SRC_DIRS_LIST "${SRC_DIRS_LIST}" endif (CONFIG_ENABLE_PW_RPC) idf_component_register(PRIV_INCLUDE_DIRS ${PRIV_INCLUDE_DIRS_LIST} - SRC_DIRS ${SRC_DIRS_LIST} - PRIV_REQUIRES ${PRIV_REQUIRES_LIST}) + SRC_DIRS ${SRC_DIRS_LIST}) get_filename_component(CHIP_ROOT ${CMAKE_SOURCE_DIR}/third_party/connectedhomeip REALPATH) include("${CHIP_ROOT}/build/chip/esp32/esp32_codegen.cmake") diff --git a/examples/lock-app/esp32/main/CMakeLists.txt b/examples/lock-app/esp32/main/CMakeLists.txt index e7266908ff3c1d..5c5f46abdd1860 100644 --- a/examples/lock-app/esp32/main/CMakeLists.txt +++ b/examples/lock-app/esp32/main/CMakeLists.txt @@ -74,8 +74,8 @@ idf_component_register(INCLUDE_DIRS "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/door-lock-server" "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/identify-server" "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/groups-server" - "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/icd-management-server" - PRIV_REQUIRES bt chip QRCode nvs_flash driver) + "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/icd-management-server") + add_dependencies(${COMPONENT_LIB} app-codegen) set(PIGWEED_ROOT "${CHIP_ROOT}/third_party/pigweed/repo") diff --git a/examples/ota-provider-app/esp32/main/CMakeLists.txt b/examples/ota-provider-app/esp32/main/CMakeLists.txt index a63033f017d8b2..41acd9e9316e00 100644 --- a/examples/ota-provider-app/esp32/main/CMakeLists.txt +++ b/examples/ota-provider-app/esp32/main/CMakeLists.txt @@ -53,8 +53,7 @@ idf_component_register(PRIV_INCLUDE_DIRS "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/examples/platform/esp32/common" "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/examples/providers" EXCLUDE_SRCS - "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/examples/ota-provider-app/ota-provider-common/BdxOtaSender.cpp" - PRIV_REQUIRES chip QRCode bt console spiffs spi_flash nvs_flash) + "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/examples/ota-provider-app/ota-provider-common/BdxOtaSender.cpp") get_filename_component(CHIP_ROOT ${CMAKE_SOURCE_DIR}/third_party/connectedhomeip REALPATH) include("${CHIP_ROOT}/build/chip/esp32/esp32_codegen.cmake") diff --git a/examples/ota-requestor-app/esp32/main/CMakeLists.txt b/examples/ota-requestor-app/esp32/main/CMakeLists.txt index 10c61e162900f2..fbda70f2cec48f 100644 --- a/examples/ota-requestor-app/esp32/main/CMakeLists.txt +++ b/examples/ota-requestor-app/esp32/main/CMakeLists.txt @@ -62,8 +62,6 @@ set(SRC_DIRS_LIST "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/examples/providers" ) -set(PRIV_REQUIRES_LIST chip QRCode bt console app_update nvs_flash) - if (CONFIG_ENABLE_PW_RPC) # Append additional directories for RPC build set(PRIV_INCLUDE_DIRS_LIST "${PRIV_INCLUDE_DIRS_LIST}" @@ -88,8 +86,7 @@ set(SRC_DIRS_LIST "${SRC_DIRS_LIST}" endif (CONFIG_ENABLE_PW_RPC) idf_component_register(PRIV_INCLUDE_DIRS ${PRIV_INCLUDE_DIRS_LIST} - SRC_DIRS ${SRC_DIRS_LIST} - PRIV_REQUIRES ${PRIV_REQUIRES_LIST}) + SRC_DIRS ${SRC_DIRS_LIST}) include("${CHIP_ROOT}/build/chip/esp32/esp32_codegen.cmake") chip_app_component_codegen("${CHIP_ROOT}/examples/ota-requestor-app/ota-requestor-common/ota-requestor-app.matter") diff --git a/examples/persistent-storage/esp32/main/CMakeLists.txt b/examples/persistent-storage/esp32/main/CMakeLists.txt index 30c85accfbe36d..e21c2eef5985b2 100644 --- a/examples/persistent-storage/esp32/main/CMakeLists.txt +++ b/examples/persistent-storage/esp32/main/CMakeLists.txt @@ -20,8 +20,7 @@ idf_component_register(PRIV_INCLUDE_DIRS "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/examples/persistent-storage" SRC_DIRS "${CMAKE_CURRENT_LIST_DIR}" - "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/examples/persistent-storage" - PRIV_REQUIRES chip nvs_flash) + "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/examples/persistent-storage") set_property(TARGET ${COMPONENT_LIB} PROPERTY CXX_STANDARD 17) target_compile_options(${COMPONENT_LIB} PRIVATE "-DCHIP_HAVE_CONFIG_H") diff --git a/examples/pigweed-app/esp32/main/CMakeLists.txt b/examples/pigweed-app/esp32/main/CMakeLists.txt index e06bb5a5296a14..7ac0373b72b612 100644 --- a/examples/pigweed-app/esp32/main/CMakeLists.txt +++ b/examples/pigweed-app/esp32/main/CMakeLists.txt @@ -33,8 +33,7 @@ idf_component_register(INCLUDE_DIRS "${CMAKE_CURRENT_LIST_DIR}" "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/examples/platform/esp32" "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/examples/common/pigweed" - "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/examples/common/pigweed/esp32" - PRIV_REQUIRES bt chip) + "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/examples/common/pigweed/esp32") get_filename_component(CHIP_ROOT ${CMAKE_SOURCE_DIR}/third_party/connectedhomeip REALPATH) set(PIGWEED_ROOT "${CHIP_ROOT}/third_party/pigweed/repo") diff --git a/examples/shell/esp32/main/CMakeLists.txt b/examples/shell/esp32/main/CMakeLists.txt index 5a565edb90a6d5..147b10bc7e1c88 100644 --- a/examples/shell/esp32/main/CMakeLists.txt +++ b/examples/shell/esp32/main/CMakeLists.txt @@ -22,5 +22,4 @@ set(CHIP_SHELL_DIR "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/examples/she idf_component_register(SRCS main.cpp "${CHIP_SHELL_DIR}/shell_common/globals.cpp" PRIV_INCLUDE_DIRS - "${CHIP_SHELL_DIR}/shell_common/include" - PRIV_REQUIRES chip nvs_flash bt) + "${CHIP_SHELL_DIR}/shell_common/include") diff --git a/examples/temperature-measurement-app/esp32/main/CMakeLists.txt b/examples/temperature-measurement-app/esp32/main/CMakeLists.txt index 89fa5e9f755455..8bc94f7b97969a 100644 --- a/examples/temperature-measurement-app/esp32/main/CMakeLists.txt +++ b/examples/temperature-measurement-app/esp32/main/CMakeLists.txt @@ -55,8 +55,6 @@ set(SRC_DIRS_LIST "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/examples/providers" ) -set(PRIV_REQUIRES_LIST chip QRCode bt nvs_flash espcoredump) - if (CONFIG_ENABLE_PW_RPC) # Append additional directories for RPC build set(PRIV_INCLUDE_DIRS_LIST "${PRIV_INCLUDE_DIRS_LIST}" @@ -82,7 +80,6 @@ endif (CONFIG_ENABLE_PW_RPC) idf_component_register(PRIV_INCLUDE_DIRS ${PRIV_INCLUDE_DIRS_LIST} SRC_DIRS ${SRC_DIRS_LIST} - PRIV_REQUIRES ${PRIV_REQUIRES_LIST} EMBED_FILES diagnostic_logs/end_user_support.log diagnostic_logs/network_diag.log) include("${CHIP_ROOT}/build/chip/esp32/esp32_codegen.cmake") From 3062e9162f856597b25b3d04366485990ca4d59f Mon Sep 17 00:00:00 2001 From: mkardous-silabs <84793247+mkardous-silabs@users.noreply.github.com> Date: Tue, 30 Apr 2024 15:33:03 -0400 Subject: [PATCH 17/33] [ICD] Convert TestICDMonitoringTable to gTest (#33239) * Move tests to icd/server/tests * Remove App dependency from the TestICDManager and build it on its own * Convert TestICDMonitoringTable to gtest * Fix build and address review comments * Add define guards in case some builds dont use TCP / UDP endpoints --- src/BUILD.gn | 2 + src/app/icd/server/tests/BUILD.gn | 50 ++ .../{ => icd/server}/tests/TestICDManager.cpp | 46 +- .../server/tests/TestICDMonitoringTable.cpp | 413 +++++++++++++++ src/app/tests/BUILD.gn | 13 - src/app/tests/TestICDMonitoringTable.cpp | 493 ------------------ src/inet/tests/TestInetCommonPosix.cpp | 16 +- .../openiotsdk/unit-tests/test_components.txt | 1 + .../unit-tests/test_components_nl.txt | 1 + .../raw/tests/NetworkTestHelpers.cpp | 7 +- 10 files changed, 514 insertions(+), 528 deletions(-) create mode 100644 src/app/icd/server/tests/BUILD.gn rename src/app/{ => icd/server}/tests/TestICDManager.cpp (98%) create mode 100644 src/app/icd/server/tests/TestICDMonitoringTable.cpp delete mode 100644 src/app/tests/TestICDMonitoringTable.cpp diff --git a/src/BUILD.gn b/src/BUILD.gn index 6bf4a2ed6d7071..8fedfa15e43fd8 100644 --- a/src/BUILD.gn +++ b/src/BUILD.gn @@ -66,6 +66,8 @@ if (chip_build_tests) { "${chip_root}/src/protocols/interaction_model/tests", "${chip_root}/src/protocols/user_directed_commissioning/tests", "${chip_root}/src/transport/retransmit/tests", + "${chip_root}/src/app/icd/server/tests", + "${chip_root}/src/app/icd/server/tests:tests_nltest", ] # Skip DNSSD tests for Mbed platform due to flash memory size limitations diff --git a/src/app/icd/server/tests/BUILD.gn b/src/app/icd/server/tests/BUILD.gn new file mode 100644 index 00000000000000..727dd135d41c2d --- /dev/null +++ b/src/app/icd/server/tests/BUILD.gn @@ -0,0 +1,50 @@ +# Copyright (c) 2024 Project CHIP Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build_overrides/build.gni") +import("//build_overrides/chip.gni") +import("//build_overrides/nlunit_test.gni") +import("//build_overrides/pigweed.gni") +import("${chip_root}/build/chip/chip_test_suite.gni") +import("${chip_root}/src/app/icd/icd.gni") + +chip_test_suite_using_nltest("tests_nltest") { + output_name = "libICDServerTestsNL" + + test_sources = [ "TestICDManager.cpp" ] + + public_deps = [ + "${chip_root}/src/app/icd/server:manager", + "${chip_root}/src/app/icd/server:monitoring-table", + "${chip_root}/src/lib/support:test_utils", + "${chip_root}/src/lib/support:testing", + "${chip_root}/src/lib/support:testing_nlunit", + "${chip_root}/src/messaging/tests:helpers", + "${nlunit_test_root}:nlunit-test", + ] +} + +chip_test_suite("tests") { + output_name = "libICDServerTests" + + test_sources = [ "TestICDMonitoringTable.cpp" ] + + public_deps = [ + "${chip_root}/src/app/icd/server:monitoring-table", + "${chip_root}/src/lib/support:test_utils", + "${chip_root}/src/lib/support:testing", + ] + + cflags = [ "-Wconversion" ] +} diff --git a/src/app/tests/TestICDManager.cpp b/src/app/icd/server/tests/TestICDManager.cpp similarity index 98% rename from src/app/tests/TestICDManager.cpp rename to src/app/icd/server/tests/TestICDManager.cpp index ea49e0ac557fc8..79b1ee817632bd 100644 --- a/src/app/tests/TestICDManager.cpp +++ b/src/app/icd/server/tests/TestICDManager.cpp @@ -15,14 +15,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#include #include #include #include #include +#include #include #include -#include +#include #include #include #include @@ -30,11 +30,10 @@ #include #include #include +#include #include #include -#include - using namespace chip; using namespace chip::app; using namespace chip::System; @@ -119,16 +118,19 @@ class TestSubscriptionsInfoProvider : public SubscriptionsInfoProvider bool mHasPersistedSubscription = false; }; -class TestContext : public chip::Test::AppContext +class TestContext : public chip::Test::LoopbackMessagingContext { public: // Performs shared setup for all tests in the test suite CHIP_ERROR SetUpTestSuite() override { - ReturnErrorOnFailure(chip::Test::AppContext::SetUpTestSuite()); + ReturnErrorOnFailure(LoopbackMessagingContext::SetUpTestSuite()); + ReturnErrorOnFailure(chip::DeviceLayer::PlatformMgr().InitChipStack()); + DeviceLayer::SetSystemLayerForTesting(&GetSystemLayer()); mRealClock = &chip::System::SystemClock(); System::Clock::Internal::SetSystemClockForTesting(&mMockClock); + return CHIP_NO_ERROR; } @@ -137,16 +139,20 @@ class TestContext : public chip::Test::AppContext { System::Clock::Internal::SetSystemClockForTesting(mRealClock); DeviceLayer::SetSystemLayerForTesting(nullptr); - chip::Test::AppContext::TearDownTestSuite(); + + chip::DeviceLayer::PlatformMgr().Shutdown(); + LoopbackMessagingContext::TearDownTestSuite(); } // Performs setup for each individual test in the test suite CHIP_ERROR SetUp() override { - ReturnErrorOnFailure(chip::Test::AppContext::SetUp()); + ReturnErrorOnFailure(LoopbackMessagingContext::SetUp()); + mICDStateObserver.ResetAll(); mICDManager.RegisterObserver(&mICDStateObserver); mICDManager.Init(&testStorage, &GetFabricTable(), &mKeystore, &GetExchangeManager(), &mSubInfoProvider); + return CHIP_NO_ERROR; } @@ -154,7 +160,7 @@ class TestContext : public chip::Test::AppContext void TearDown() override { mICDManager.Shutdown(); - chip::Test::AppContext::TearDown(); + LoopbackMessagingContext::TearDown(); } System::Clock::Internal::MockClock mMockClock; @@ -653,6 +659,7 @@ class TestICDManager NL_TEST_ASSERT(aSuite, stayActivePromisedMs == 20000); } +#if CHIP_CONFIG_ENABLE_ICD_CIP #if CHIP_CONFIG_PERSIST_SUBSCRIPTIONS #if CHIP_CONFIG_SUBSCRIPTION_TIMEOUT_RESUMPTION static void TestShouldCheckInMsgsBeSentAtActiveModeFunction(nlTestSuite * aSuite, void * aContext) @@ -723,6 +730,7 @@ class TestICDManager NL_TEST_ASSERT(aSuite, ctx->mICDManager.ShouldCheckInMsgsBeSentAtActiveModeFunction(kTestFabricIndex1, kClientNodeId11)); } #endif // CHIP_CONFIG_PERSIST_SUBSCRIPTIONS +#endif // CHIP_CONFIG_ENABLE_ICD_CIP static void TestHandleTestEventTriggerActiveModeReq(nlTestSuite * aSuite, void * aContext) { @@ -1117,27 +1125,29 @@ namespace { static const nlTest sTests[] = { NL_TEST_DEF("TestICDModeDurations", TestICDManager::TestICDModeDurations), NL_TEST_DEF("TestOnSubscriptionReport", TestICDManager::TestOnSubscriptionReport), - NL_TEST_DEF("TestICDModeDurationsWith0ActiveModeDurationWithoutActiveSub", - TestICDManager::TestICDModeDurationsWith0ActiveModeDurationWithoutActiveSub), - NL_TEST_DEF("TestICDModeDurationsWith0ActiveModeDurationWithActiveSub", - TestICDManager::TestICDModeDurationsWith0ActiveModeDurationWithActiveSub), NL_TEST_DEF("TestKeepActivemodeRequests", TestICDManager::TestKeepActivemodeRequests), - NL_TEST_DEF("TestICDMRegisterUnregisterEvents", TestICDManager::TestICDMRegisterUnregisterEvents), - NL_TEST_DEF("TestICDCounter", TestICDManager::TestICDCounter), NL_TEST_DEF("TestICDStayActive", TestICDManager::TestICDMStayActive), +#if CHIP_CONFIG_ENABLE_ICD_CIP + NL_TEST_DEF("TestICDCounter", TestICDManager::TestICDCounter), + NL_TEST_DEF("TestICDMRegisterUnregisterEvents", TestICDManager::TestICDMRegisterUnregisterEvents), + NL_TEST_DEF("TestICDModeDurationsWith0ActiveModeDurationWithActiveSub", + TestICDManager::TestICDModeDurationsWith0ActiveModeDurationWithActiveSub), + NL_TEST_DEF("TestICDModeDurationsWith0ActiveModeDurationWithoutActiveSub", + TestICDManager::TestICDModeDurationsWith0ActiveModeDurationWithoutActiveSub), NL_TEST_DEF("TestShouldCheckInMsgsBeSentAtActiveModeFunction", TestICDManager::TestShouldCheckInMsgsBeSentAtActiveModeFunction), - NL_TEST_DEF("TestHandleTestEventTriggerActiveModeReq", TestICDManager::TestHandleTestEventTriggerActiveModeReq), NL_TEST_DEF("TestHandleTestEventTriggerInvalidateHalfCounterValues", TestICDManager::TestHandleTestEventTriggerInvalidateHalfCounterValues), NL_TEST_DEF("TestHandleTestEventTriggerInvalidateAllCounterValues", TestICDManager::TestHandleTestEventTriggerInvalidateAllCounterValues), + NL_TEST_DEF("TestICDStateObserverOnICDModeChange", TestICDManager::TestICDStateObserverOnICDModeChange), + NL_TEST_DEF("TestICDStateObserverOnICDModeChangeOnInit", TestICDManager::TestICDStateObserverOnICDModeChangeOnInit), +#endif // CHIP_CONFIG_ENABLE_ICD_CIP + NL_TEST_DEF("TestHandleTestEventTriggerActiveModeReq", TestICDManager::TestHandleTestEventTriggerActiveModeReq), NL_TEST_DEF("TestICDStateObserverOnEnterIdleModeActiveModeDuration", TestICDManager::TestICDStateObserverOnEnterIdleModeActiveModeDuration), NL_TEST_DEF("TestICDStateObserverOnEnterIdleModeActiveModeThreshold", TestICDManager::TestICDStateObserverOnEnterIdleModeActiveModeThreshold), NL_TEST_DEF("TestICDStateObserverOnEnterActiveMode", TestICDManager::TestICDStateObserverOnEnterActiveMode), - NL_TEST_DEF("TestICDStateObserverOnICDModeChange", TestICDManager::TestICDStateObserverOnICDModeChange), - NL_TEST_DEF("TestICDStateObserverOnICDModeChangeOnInit", TestICDManager::TestICDStateObserverOnICDModeChangeOnInit), NL_TEST_DEF("TestICDStateObserverOnTransitionToIdleModeGreaterActiveModeDuration", TestICDManager::TestICDStateObserverOnTransitionToIdleModeGreaterActiveModeDuration), NL_TEST_DEF("TestICDStateObserverOnTransitionToIdleModeEqualActiveModeDuration", diff --git a/src/app/icd/server/tests/TestICDMonitoringTable.cpp b/src/app/icd/server/tests/TestICDMonitoringTable.cpp new file mode 100644 index 00000000000000..ef1e5b32468b7a --- /dev/null +++ b/src/app/icd/server/tests/TestICDMonitoringTable.cpp @@ -0,0 +1,413 @@ +/* + * + * Copyright (c) 2022 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include + +using namespace chip; + +using TestSessionKeystoreImpl = Crypto::DefaultSessionKeystore; + +namespace { + +constexpr uint16_t kMaxTestClients1 = 2; +constexpr uint16_t kMaxTestClients2 = 1; +constexpr FabricIndex kTestFabricIndex1 = 1; +constexpr FabricIndex kTestFabricIndex2 = kMaxValidFabricIndex; +constexpr uint64_t kClientNodeId11 = 0x100001; +constexpr uint64_t kClientNodeId12 = 0x100002; +constexpr uint64_t kClientNodeId13 = 0x100003; +constexpr uint64_t kClientNodeId21 = 0x200001; +constexpr uint64_t kClientNodeId22 = 0x200002; + +constexpr uint8_t kKeyBuffer0a[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; +constexpr uint8_t kKeyBuffer0b[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + +constexpr uint8_t kKeyBuffer1a[] = { + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f +}; +constexpr uint8_t kKeyBuffer1b[] = { + 0xf1, 0xe1, 0xd1, 0xc1, 0xb1, 0xa1, 0x91, 0x81, 0x71, 0x61, 0x51, 0x14, 0x31, 0x21, 0x11, 0x01 +}; +constexpr uint8_t kKeyBuffer2a[] = { + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f +}; +constexpr uint8_t kKeyBuffer2b[] = { + 0xf2, 0xe2, 0xd2, 0xc2, 0xb2, 0xa2, 0x92, 0x82, 0x72, 0x62, 0x52, 0x42, 0x32, 0x22, 0x12, 0x02 +}; +constexpr uint8_t kKeyBuffer3a[] = { + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f +}; + +TEST(TestICDMonitoringTable, TestEntryAssignationOverload) +{ + TestSessionKeystoreImpl keystore; + ICDMonitoringEntry entry(&keystore); + + // Test Setting Key + EXPECT_EQ(entry.SetKey(ByteSpan(kKeyBuffer1a)), CHIP_NO_ERROR); + + entry.fabricIndex = 2; + + EXPECT_FALSE(entry.IsValid()); + + entry.checkInNodeID = 34; + entry.monitoredSubject = 32; + + // Entry should be valid now + EXPECT_TRUE(entry.IsValid()); + + ICDMonitoringEntry entry2; + + EXPECT_FALSE(entry2.IsValid()); + + entry2 = entry; + + EXPECT_TRUE(entry2.IsValid()); + + EXPECT_EQ(entry.fabricIndex, entry2.fabricIndex); + EXPECT_EQ(entry.checkInNodeID, entry2.checkInNodeID); + EXPECT_EQ(entry.monitoredSubject, entry2.monitoredSubject); + + EXPECT_TRUE(entry2.IsKeyEquivalent(ByteSpan(kKeyBuffer1a))); +} + +TEST(TestICDMonitoringTable, TestEntryKeyFunctions) +{ + TestSessionKeystoreImpl keystore; + ICDMonitoringEntry entry(&keystore); + + // Test Setting Key + EXPECT_EQ(entry.SetKey(ByteSpan(kKeyBuffer1a)), CHIP_NO_ERROR); + + // Test Setting Key again + EXPECT_EQ(entry.SetKey(ByteSpan(kKeyBuffer1b)), CHIP_ERROR_INTERNAL); + + // Test Key Deletion + EXPECT_EQ(entry.DeleteKey(), CHIP_NO_ERROR); + + // Test Setting Key again + EXPECT_EQ(entry.SetKey(ByteSpan(kKeyBuffer1b)), CHIP_NO_ERROR); + + // Test Comparing Key + EXPECT_FALSE(entry.IsKeyEquivalent(ByteSpan(kKeyBuffer1a))); + + EXPECT_TRUE(entry.IsKeyEquivalent(ByteSpan(kKeyBuffer1b))); + + // Test Deleting Key + EXPECT_EQ(entry.DeleteKey(), CHIP_NO_ERROR); +} + +TEST(TestICDMonitoringTable, TestSaveAndLoadRegistrationValue) +{ + TestPersistentStorageDelegate storage; + TestSessionKeystoreImpl keystore; + ICDMonitoringTable saving(storage, kTestFabricIndex1, kMaxTestClients1, &keystore); + ICDMonitoringTable loading(storage, kTestFabricIndex1, kMaxTestClients1, &keystore); + ICDMonitoringEntry entry(&keystore); + + // Insert first entry + ICDMonitoringEntry entry1(&keystore); + entry1.checkInNodeID = kClientNodeId11; + entry1.monitoredSubject = kClientNodeId12; + EXPECT_EQ(CHIP_NO_ERROR, entry1.SetKey(ByteSpan(kKeyBuffer1a))); + EXPECT_EQ(CHIP_NO_ERROR, saving.Set(0, entry1)); + + // Insert second entry + ICDMonitoringEntry entry2(&keystore); + entry2.checkInNodeID = kClientNodeId12; + entry2.monitoredSubject = kClientNodeId11; + EXPECT_EQ(CHIP_NO_ERROR, entry2.SetKey(ByteSpan(kKeyBuffer2a))); + EXPECT_EQ(CHIP_NO_ERROR, saving.Set(1, entry2)); + + // Insert one too many + ICDMonitoringEntry entry3(&keystore); + entry3.checkInNodeID = kClientNodeId13; + entry3.monitoredSubject = kClientNodeId13; + EXPECT_EQ(CHIP_NO_ERROR, entry3.SetKey(ByteSpan(kKeyBuffer3a))); + EXPECT_EQ(CHIP_ERROR_INVALID_ARGUMENT, saving.Set(2, entry3)); + + // Retrieve first entry + EXPECT_EQ(CHIP_NO_ERROR, loading.Get(0, entry)); + EXPECT_EQ(kTestFabricIndex1, entry.fabricIndex); + EXPECT_EQ(kClientNodeId11, entry.checkInNodeID); + EXPECT_EQ(kClientNodeId12, entry.monitoredSubject); + EXPECT_TRUE(entry.IsKeyEquivalent(ByteSpan(kKeyBuffer1a))); + EXPECT_EQ(memcmp(entry1.hmacKeyHandle.As(), + entry.hmacKeyHandle.As(), sizeof(Crypto::Symmetric128BitsKeyByteArray)), + 0); + + // Retrieve second entry + EXPECT_EQ(CHIP_NO_ERROR, loading.Get(1, entry)); + EXPECT_EQ(kTestFabricIndex1, entry.fabricIndex); + EXPECT_EQ(kClientNodeId12, entry.checkInNodeID); + EXPECT_EQ(kClientNodeId11, entry.monitoredSubject); + EXPECT_TRUE(entry.IsKeyEquivalent(ByteSpan(kKeyBuffer2a))); + EXPECT_EQ(memcmp(entry2.hmacKeyHandle.As(), + entry.hmacKeyHandle.As(), sizeof(Crypto::Symmetric128BitsKeyByteArray)), + 0); + + // No more entries + EXPECT_EQ(CHIP_ERROR_NOT_FOUND, loading.Get(2, entry)); + EXPECT_EQ(2, loading.Limit()); + + // Remove first entry + saving.Remove(0); + + ICDMonitoringEntry entry4(&keystore); + entry4.checkInNodeID = kClientNodeId13; + entry4.monitoredSubject = kClientNodeId11; + EXPECT_EQ(CHIP_NO_ERROR, entry4.SetKey(ByteSpan(kKeyBuffer1b))); + EXPECT_EQ(CHIP_NO_ERROR, saving.Set(1, entry4)); + + // Retrieve first entry (not modified but shifted) + EXPECT_EQ(CHIP_NO_ERROR, loading.Get(0, entry)); + EXPECT_EQ(kTestFabricIndex1, entry.fabricIndex); + EXPECT_EQ(kClientNodeId12, entry.checkInNodeID); + EXPECT_EQ(kClientNodeId11, entry.monitoredSubject); + EXPECT_TRUE(entry.IsKeyEquivalent(ByteSpan(kKeyBuffer2a))); + EXPECT_EQ(memcmp(entry2.hmacKeyHandle.As(), + entry.hmacKeyHandle.As(), sizeof(Crypto::Symmetric128BitsKeyByteArray)), + 0); + + // Retrieve second entry + EXPECT_EQ(CHIP_NO_ERROR, loading.Get(1, entry)); + EXPECT_EQ(kTestFabricIndex1, entry.fabricIndex); + EXPECT_EQ(kClientNodeId13, entry.checkInNodeID); + EXPECT_EQ(kClientNodeId11, entry.monitoredSubject); + EXPECT_TRUE(entry.IsKeyEquivalent(ByteSpan(kKeyBuffer1b))); + EXPECT_EQ(memcmp(entry4.hmacKeyHandle.As(), + entry.hmacKeyHandle.As(), sizeof(Crypto::Symmetric128BitsKeyByteArray)), + 0); +} + +TEST(TestICDMonitoringTable, TestSaveAllInvalidRegistrationValues) +{ + TestPersistentStorageDelegate storage; + TestSessionKeystoreImpl keystore; + ICDMonitoringTable table(storage, kTestFabricIndex1, kMaxTestClients1, &keystore); + + // Invalid checkInNodeID + ICDMonitoringEntry entry1(&keystore); + entry1.checkInNodeID = kUndefinedNodeId; + entry1.monitoredSubject = kClientNodeId12; + EXPECT_EQ(CHIP_NO_ERROR, entry1.SetKey(ByteSpan(kKeyBuffer1a))); + EXPECT_EQ(CHIP_ERROR_INVALID_ARGUMENT, table.Set(0, entry1)); + + // Invalid monitoredSubject + ICDMonitoringEntry entry2(&keystore); + entry2.checkInNodeID = kClientNodeId11; + entry2.monitoredSubject = kUndefinedNodeId; + EXPECT_EQ(CHIP_NO_ERROR, entry2.SetKey(ByteSpan(kKeyBuffer1a))); + EXPECT_EQ(CHIP_ERROR_INVALID_ARGUMENT, table.Set(0, entry2)); + + // Invalid key (empty) + ICDMonitoringEntry entry3(&keystore); + entry3.checkInNodeID = kClientNodeId11; + entry3.monitoredSubject = kClientNodeId12; + EXPECT_EQ(CHIP_ERROR_INVALID_ARGUMENT, entry3.SetKey(ByteSpan())); + EXPECT_EQ(CHIP_ERROR_INVALID_ARGUMENT, table.Set(0, entry3)); + + // Invalid key (too short) + ICDMonitoringEntry entry4(&keystore); + entry4.checkInNodeID = kClientNodeId11; + entry4.monitoredSubject = kClientNodeId12; + EXPECT_EQ(CHIP_ERROR_INVALID_ARGUMENT, entry4.SetKey(ByteSpan(kKeyBuffer0a))); + EXPECT_EQ(CHIP_ERROR_INVALID_ARGUMENT, table.Set(0, entry4)); + + // Invalid key (too long) + ICDMonitoringEntry entry5(&keystore); + entry5.checkInNodeID = kClientNodeId11; + entry5.monitoredSubject = kClientNodeId12; + EXPECT_EQ(CHIP_ERROR_INVALID_ARGUMENT, entry5.SetKey(ByteSpan(kKeyBuffer0b))); + EXPECT_EQ(CHIP_ERROR_INVALID_ARGUMENT, table.Set(0, entry5)); +} + +TEST(TestICDMonitoringTable, TestSaveLoadRegistrationValueForMultipleFabrics) +{ + TestPersistentStorageDelegate storage; + TestSessionKeystoreImpl keystore; + ICDMonitoringTable table1(storage, kTestFabricIndex1, kMaxTestClients1, &keystore); + ICDMonitoringTable table2(storage, kTestFabricIndex2, kMaxTestClients2, &keystore); + ICDMonitoringEntry entry(&keystore); + + // Insert in first fabric + ICDMonitoringEntry entry1(&keystore); + entry1.checkInNodeID = kClientNodeId11; + entry1.monitoredSubject = kClientNodeId12; + EXPECT_EQ(CHIP_NO_ERROR, entry1.SetKey(ByteSpan(kKeyBuffer1a))); + EXPECT_EQ(CHIP_NO_ERROR, table1.Set(0, entry1)); + + // Insert in first fabric + ICDMonitoringEntry entry2(&keystore); + entry2.checkInNodeID = kClientNodeId12; + entry2.monitoredSubject = kClientNodeId11; + EXPECT_EQ(CHIP_NO_ERROR, entry2.SetKey(ByteSpan(kKeyBuffer1b))); + EXPECT_EQ(CHIP_NO_ERROR, table1.Set(1, entry2)); + + // Insert in second fabric + ICDMonitoringEntry entry3(&keystore); + entry3.checkInNodeID = kClientNodeId21; + entry3.monitoredSubject = kClientNodeId22; + EXPECT_EQ(CHIP_NO_ERROR, entry3.SetKey(ByteSpan(kKeyBuffer2a))); + EXPECT_EQ(CHIP_NO_ERROR, table2.Set(0, entry3)); + + // Insert in second fabric (one too many) + ICDMonitoringEntry entry4(&keystore); + entry4.checkInNodeID = kClientNodeId22; + entry4.monitoredSubject = kClientNodeId21; + EXPECT_EQ(CHIP_NO_ERROR, entry4.SetKey(ByteSpan(kKeyBuffer2b))); + EXPECT_EQ(CHIP_ERROR_INVALID_ARGUMENT, table2.Set(1, entry4)); + + // Retrieve fabric1, first entry + + EXPECT_EQ(CHIP_NO_ERROR, table1.Get(0, entry)); + EXPECT_EQ(kTestFabricIndex1, entry.fabricIndex); + EXPECT_EQ(kClientNodeId11, entry.checkInNodeID); + EXPECT_EQ(kClientNodeId12, entry.monitoredSubject); + EXPECT_TRUE(entry.IsKeyEquivalent(ByteSpan(kKeyBuffer1a))); + EXPECT_EQ(memcmp(entry1.hmacKeyHandle.As(), + entry.hmacKeyHandle.As(), sizeof(Crypto::Symmetric128BitsKeyByteArray)), + 0); + + // Retrieve fabric1, second entry + EXPECT_EQ(CHIP_NO_ERROR, table1.Get(1, entry)); + EXPECT_EQ(kTestFabricIndex1, entry.fabricIndex); + EXPECT_EQ(kClientNodeId12, entry.checkInNodeID); + EXPECT_EQ(kClientNodeId11, entry.monitoredSubject); + EXPECT_TRUE(entry.IsKeyEquivalent(ByteSpan(kKeyBuffer1b))); + EXPECT_EQ(memcmp(entry2.hmacKeyHandle.As(), + entry.hmacKeyHandle.As(), sizeof(Crypto::Symmetric128BitsKeyByteArray)), + 0); + + // Retrieve fabric2, first entry + EXPECT_EQ(CHIP_NO_ERROR, table2.Get(0, entry)); + EXPECT_EQ(kTestFabricIndex2, entry.fabricIndex); + EXPECT_EQ(kClientNodeId21, entry.checkInNodeID); + EXPECT_EQ(kClientNodeId22, entry.monitoredSubject); + EXPECT_TRUE(entry.IsKeyEquivalent(ByteSpan(kKeyBuffer2a))); + EXPECT_EQ(memcmp(entry3.hmacKeyHandle.As(), + entry.hmacKeyHandle.As(), sizeof(Crypto::Symmetric128BitsKeyByteArray)), + 0); +} + +TEST(TestICDMonitoringTable, TestDeleteValidEntryFromStorage) +{ + TestPersistentStorageDelegate storage; + TestSessionKeystoreImpl keystore; + ICDMonitoringTable table1(storage, kTestFabricIndex1, kMaxTestClients1, &keystore); + ICDMonitoringTable table2(storage, kTestFabricIndex2, kMaxTestClients2, &keystore); + ICDMonitoringEntry entry(&keystore); + CHIP_ERROR err; + + // Insert in first fabric + ICDMonitoringEntry entry1(&keystore); + entry1.checkInNodeID = kClientNodeId11; + entry1.monitoredSubject = kClientNodeId12; + EXPECT_EQ(CHIP_NO_ERROR, entry1.SetKey(ByteSpan(kKeyBuffer1a))); + EXPECT_EQ(CHIP_NO_ERROR, table1.Set(0, entry1)); + + // Insert in first fabric + ICDMonitoringEntry entry2(&keystore); + entry2.checkInNodeID = kClientNodeId12; + entry2.monitoredSubject = kClientNodeId11; + EXPECT_EQ(CHIP_NO_ERROR, entry2.SetKey(ByteSpan(kKeyBuffer2a))); + err = table1.Set(1, entry2); + EXPECT_EQ(CHIP_NO_ERROR, err); + + // Insert in second fabric + ICDMonitoringEntry entry3(&keystore); + entry3.checkInNodeID = kClientNodeId21; + entry3.monitoredSubject = kClientNodeId22; + EXPECT_EQ(CHIP_NO_ERROR, entry3.SetKey(ByteSpan(kKeyBuffer1b))); + EXPECT_EQ(CHIP_NO_ERROR, table2.Set(0, entry3)); + + // Remove (invalid) + EXPECT_NE(CHIP_NO_ERROR, table1.Remove(2)); + + // Retrieve fabric1 + EXPECT_EQ(CHIP_NO_ERROR, table1.Get(0, entry)); + EXPECT_EQ(kTestFabricIndex1, entry.fabricIndex); + EXPECT_EQ(kClientNodeId11, entry.checkInNodeID); + EXPECT_EQ(kClientNodeId12, entry.monitoredSubject); + EXPECT_TRUE(entry.IsKeyEquivalent(ByteSpan(kKeyBuffer1a))); + EXPECT_EQ(memcmp(entry1.hmacKeyHandle.As(), + entry.hmacKeyHandle.As(), sizeof(Crypto::Symmetric128BitsKeyByteArray)), + 0); + + // Retrieve second entry (not modified) + EXPECT_EQ(CHIP_NO_ERROR, table1.Get(1, entry)); + EXPECT_EQ(kTestFabricIndex1, entry.fabricIndex); + EXPECT_EQ(kClientNodeId12, entry.checkInNodeID); + EXPECT_EQ(kClientNodeId11, entry.monitoredSubject); + EXPECT_TRUE(entry.IsKeyEquivalent(ByteSpan(kKeyBuffer2a))); + EXPECT_EQ(memcmp(entry2.hmacKeyHandle.As(), + entry.hmacKeyHandle.As(), sizeof(Crypto::Symmetric128BitsKeyByteArray)), + 0); + + // Remove (existing) + EXPECT_EQ(CHIP_NO_ERROR, table1.Remove(0)); + + // Retrieve second entry (shifted down) + EXPECT_EQ(CHIP_ERROR_NOT_FOUND, table1.Get(1, entry)); + + err = table1.Get(0, entry); + EXPECT_EQ(CHIP_NO_ERROR, err); + EXPECT_EQ(kTestFabricIndex1, entry.fabricIndex); + EXPECT_EQ(kClientNodeId12, entry.checkInNodeID); + EXPECT_EQ(kClientNodeId11, entry.monitoredSubject); + EXPECT_TRUE(entry.IsKeyEquivalent(ByteSpan(kKeyBuffer2a))); + EXPECT_EQ(memcmp(entry2.hmacKeyHandle.As(), + entry.hmacKeyHandle.As(), sizeof(Crypto::Symmetric128BitsKeyByteArray)), + 0); + + // Retrieve fabric2, first entry + EXPECT_EQ(CHIP_NO_ERROR, table2.Get(0, entry)); + EXPECT_EQ(kTestFabricIndex2, entry.fabricIndex); + EXPECT_EQ(kClientNodeId21, entry.checkInNodeID); + EXPECT_EQ(kClientNodeId22, entry.monitoredSubject); + EXPECT_TRUE(entry.IsKeyEquivalent(ByteSpan(kKeyBuffer1b))); + EXPECT_EQ(memcmp(entry3.hmacKeyHandle.As(), + entry.hmacKeyHandle.As(), sizeof(Crypto::Symmetric128BitsKeyByteArray)), + 0); + + // Remove all (fabric 1) + EXPECT_EQ(CHIP_NO_ERROR, table1.RemoveAll()); + EXPECT_EQ(CHIP_ERROR_NOT_FOUND, table1.Get(0, entry)); + + // Check fabric 2 + EXPECT_EQ(CHIP_NO_ERROR, table2.Get(0, entry)); + EXPECT_EQ(kTestFabricIndex2, entry.fabricIndex); + EXPECT_EQ(kClientNodeId21, entry.checkInNodeID); + EXPECT_EQ(kClientNodeId22, entry.monitoredSubject); + EXPECT_TRUE(entry.IsKeyEquivalent(ByteSpan(kKeyBuffer1b))); + EXPECT_EQ(memcmp(entry3.hmacKeyHandle.As(), + entry.hmacKeyHandle.As(), sizeof(Crypto::Symmetric128BitsKeyByteArray)), + 0); + + // Remove all (fabric 2) + EXPECT_EQ(CHIP_NO_ERROR, table2.RemoveAll()); + EXPECT_EQ(CHIP_ERROR_NOT_FOUND, table2.Get(0, entry)); +} + +} // namespace diff --git a/src/app/tests/BUILD.gn b/src/app/tests/BUILD.gn index 78b9c8f69e87df..49196f2fdaaf8f 100644 --- a/src/app/tests/BUILD.gn +++ b/src/app/tests/BUILD.gn @@ -219,16 +219,6 @@ chip_test_suite_using_nltest("tests") { "${nlunit_test_root}:nlunit-test", ] - if (chip_enable_icd_server) { - public_deps += [ "${chip_root}/src/app/icd/server:manager" ] - - test_sources += [ "TestICDManager.cpp" ] - } - - if (chip_enable_icd_checkin) { - test_sources += [ "TestICDMonitoringTable.cpp" ] - } - if (chip_device_platform != "android") { test_sources += [ "TestExtensionFieldSets.cpp", @@ -240,9 +230,6 @@ chip_test_suite_using_nltest("tests") { ] } - # Do not run TestCommissionManager when running ICD specific unit tests. - # ICDManager has a dependency on the Accessors.h file which causes a link error - # when building the TestCommissionManager if (chip_config_network_layer_ble && (chip_device_platform == "linux" || chip_device_platform == "darwin")) { test_sources += [ "TestCommissionManager.cpp" ] diff --git a/src/app/tests/TestICDMonitoringTable.cpp b/src/app/tests/TestICDMonitoringTable.cpp deleted file mode 100644 index f5de7ed59ba3e1..00000000000000 --- a/src/app/tests/TestICDMonitoringTable.cpp +++ /dev/null @@ -1,493 +0,0 @@ -/* - * - * Copyright (c) 2022 Project CHIP Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include -#include -#include -#include -#include -#include - -#include - -using namespace chip; - -using TestSessionKeystoreImpl = Crypto::DefaultSessionKeystore; - -namespace { - -constexpr uint16_t kMaxTestClients1 = 2; -constexpr uint16_t kMaxTestClients2 = 1; -constexpr FabricIndex kTestFabricIndex1 = 1; -constexpr FabricIndex kTestFabricIndex2 = kMaxValidFabricIndex; -constexpr uint64_t kClientNodeId11 = 0x100001; -constexpr uint64_t kClientNodeId12 = 0x100002; -constexpr uint64_t kClientNodeId13 = 0x100003; -constexpr uint64_t kClientNodeId21 = 0x200001; -constexpr uint64_t kClientNodeId22 = 0x200002; - -constexpr uint8_t kKeyBuffer0a[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; -constexpr uint8_t kKeyBuffer0b[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; - -constexpr uint8_t kKeyBuffer1a[] = { - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f -}; -constexpr uint8_t kKeyBuffer1b[] = { - 0xf1, 0xe1, 0xd1, 0xc1, 0xb1, 0xa1, 0x91, 0x81, 0x71, 0x61, 0x51, 0x14, 0x31, 0x21, 0x11, 0x01 -}; -constexpr uint8_t kKeyBuffer2a[] = { - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f -}; -constexpr uint8_t kKeyBuffer2b[] = { - 0xf2, 0xe2, 0xd2, 0xc2, 0xb2, 0xa2, 0x92, 0x82, 0x72, 0x62, 0x52, 0x42, 0x32, 0x22, 0x12, 0x02 -}; -constexpr uint8_t kKeyBuffer3a[] = { - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f -}; - -void TestEntryAssignationOverload(nlTestSuite * aSuite, void * aContext) -{ - TestSessionKeystoreImpl keystore; - ICDMonitoringEntry entry(&keystore); - - // Test Setting Key - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == entry.SetKey(ByteSpan(kKeyBuffer1a))); - - entry.fabricIndex = 2; - - NL_TEST_ASSERT(aSuite, !entry.IsValid()); - - entry.checkInNodeID = 34; - entry.monitoredSubject = 32; - - // Entry should be valid now - NL_TEST_ASSERT(aSuite, entry.IsValid()); - - ICDMonitoringEntry entry2; - - NL_TEST_ASSERT(aSuite, !entry2.IsValid()); - - entry2 = entry; - - NL_TEST_ASSERT(aSuite, entry2.IsValid()); - - NL_TEST_ASSERT(aSuite, entry2.fabricIndex == entry.fabricIndex); - NL_TEST_ASSERT(aSuite, entry2.checkInNodeID == entry.checkInNodeID); - NL_TEST_ASSERT(aSuite, entry2.monitoredSubject == entry.monitoredSubject); - - NL_TEST_ASSERT(aSuite, entry2.IsKeyEquivalent(ByteSpan(kKeyBuffer1a))); -} - -void TestEntryKeyFunctions(nlTestSuite * aSuite, void * aContext) -{ - TestSessionKeystoreImpl keystore; - ICDMonitoringEntry entry(&keystore); - - // Test Setting Key - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == entry.SetKey(ByteSpan(kKeyBuffer1a))); - - // Test Setting Key again - NL_TEST_ASSERT(aSuite, CHIP_ERROR_INTERNAL == entry.SetKey(ByteSpan(kKeyBuffer1b))); - - // Test Key Deletion - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == entry.DeleteKey()); - - // Test Setting Key again - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == entry.SetKey(ByteSpan(kKeyBuffer1b))); - - // Test Comparing Key - NL_TEST_ASSERT(aSuite, !entry.IsKeyEquivalent(ByteSpan(kKeyBuffer1a))); - - NL_TEST_ASSERT(aSuite, entry.IsKeyEquivalent(ByteSpan(kKeyBuffer1b))); - - // Test Deleting Key - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == entry.DeleteKey()); -} - -void TestSaveAndLoadRegistrationValue(nlTestSuite * aSuite, void * aContext) -{ - TestPersistentStorageDelegate storage; - TestSessionKeystoreImpl keystore; - ICDMonitoringTable saving(storage, kTestFabricIndex1, kMaxTestClients1, &keystore); - ICDMonitoringTable loading(storage, kTestFabricIndex1, kMaxTestClients1, &keystore); - ICDMonitoringEntry entry(&keystore); - CHIP_ERROR err; - - // Insert first entry - ICDMonitoringEntry entry1(&keystore); - entry1.checkInNodeID = kClientNodeId11; - entry1.monitoredSubject = kClientNodeId12; - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == entry1.SetKey(ByteSpan(kKeyBuffer1a))); - err = saving.Set(0, entry1); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == err); - - // Insert second entry - ICDMonitoringEntry entry2(&keystore); - entry2.checkInNodeID = kClientNodeId12; - entry2.monitoredSubject = kClientNodeId11; - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == entry2.SetKey(ByteSpan(kKeyBuffer2a))); - err = saving.Set(1, entry2); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == err); - - // Insert one too many - ICDMonitoringEntry entry3(&keystore); - entry3.checkInNodeID = kClientNodeId13; - entry3.monitoredSubject = kClientNodeId13; - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == entry3.SetKey(ByteSpan(kKeyBuffer3a))); - err = saving.Set(2, entry3); - NL_TEST_ASSERT(aSuite, CHIP_ERROR_INVALID_ARGUMENT == err); - - // Retrieve first entry - err = loading.Get(0, entry); - - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == err); - NL_TEST_ASSERT(aSuite, kTestFabricIndex1 == entry.fabricIndex); - NL_TEST_ASSERT(aSuite, kClientNodeId11 == entry.checkInNodeID); - NL_TEST_ASSERT(aSuite, kClientNodeId12 == entry.monitoredSubject); - NL_TEST_ASSERT(aSuite, entry.IsKeyEquivalent(ByteSpan(kKeyBuffer1a))); - NL_TEST_ASSERT(aSuite, - memcmp(entry1.hmacKeyHandle.As(), - entry.hmacKeyHandle.As(), - sizeof(Crypto::Symmetric128BitsKeyByteArray)) == 0); - - // Retrieve second entry - err = loading.Get(1, entry); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == err); - NL_TEST_ASSERT(aSuite, kTestFabricIndex1 == entry.fabricIndex); - NL_TEST_ASSERT(aSuite, kClientNodeId12 == entry.checkInNodeID); - NL_TEST_ASSERT(aSuite, kClientNodeId11 == entry.monitoredSubject); - NL_TEST_ASSERT(aSuite, entry.IsKeyEquivalent(ByteSpan(kKeyBuffer2a))); - NL_TEST_ASSERT(aSuite, - memcmp(entry2.hmacKeyHandle.As(), - entry.hmacKeyHandle.As(), - sizeof(Crypto::Symmetric128BitsKeyByteArray)) == 0); - - // No more entries - err = loading.Get(2, entry); - NL_TEST_ASSERT(aSuite, 2 == loading.Limit()); - NL_TEST_ASSERT(aSuite, CHIP_ERROR_NOT_FOUND == err); - - // Remove first entry - saving.Remove(0); - - ICDMonitoringEntry entry4(&keystore); - entry4.checkInNodeID = kClientNodeId13; - entry4.monitoredSubject = kClientNodeId11; - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == entry4.SetKey(ByteSpan(kKeyBuffer1b))); - err = saving.Set(1, entry4); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == err); - - // Retrieve first entry (not modified but shifted) - err = loading.Get(0, entry); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == err); - NL_TEST_ASSERT(aSuite, kTestFabricIndex1 == entry.fabricIndex); - NL_TEST_ASSERT(aSuite, kClientNodeId12 == entry.checkInNodeID); - NL_TEST_ASSERT(aSuite, kClientNodeId11 == entry.monitoredSubject); - NL_TEST_ASSERT(aSuite, entry.IsKeyEquivalent(ByteSpan(kKeyBuffer2a))); - NL_TEST_ASSERT(aSuite, - memcmp(entry2.hmacKeyHandle.As(), - entry.hmacKeyHandle.As(), - sizeof(Crypto::Symmetric128BitsKeyByteArray)) == 0); - - // Retrieve second entry - err = loading.Get(1, entry); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == err); - NL_TEST_ASSERT(aSuite, kTestFabricIndex1 == entry.fabricIndex); - NL_TEST_ASSERT(aSuite, kClientNodeId13 == entry.checkInNodeID); - NL_TEST_ASSERT(aSuite, kClientNodeId11 == entry.monitoredSubject); - NL_TEST_ASSERT(aSuite, entry.IsKeyEquivalent(ByteSpan(kKeyBuffer1b))); - NL_TEST_ASSERT(aSuite, - memcmp(entry4.hmacKeyHandle.As(), - entry.hmacKeyHandle.As(), - sizeof(Crypto::Symmetric128BitsKeyByteArray)) == 0); -} - -void TestSaveAllInvalidRegistrationValues(nlTestSuite * aSuite, void * aContext) -{ - TestPersistentStorageDelegate storage; - TestSessionKeystoreImpl keystore; - ICDMonitoringTable table(storage, kTestFabricIndex1, kMaxTestClients1, &keystore); - CHIP_ERROR err; - - // Invalid checkInNodeID - ICDMonitoringEntry entry1(&keystore); - entry1.checkInNodeID = kUndefinedNodeId; - entry1.monitoredSubject = kClientNodeId12; - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == entry1.SetKey(ByteSpan(kKeyBuffer1a))); - err = table.Set(0, entry1); - NL_TEST_ASSERT(aSuite, CHIP_ERROR_INVALID_ARGUMENT == err); - - // Invalid monitoredSubject - ICDMonitoringEntry entry2(&keystore); - entry2.checkInNodeID = kClientNodeId11; - entry2.monitoredSubject = kUndefinedNodeId; - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == entry2.SetKey(ByteSpan(kKeyBuffer1a))); - err = table.Set(0, entry2); - NL_TEST_ASSERT(aSuite, CHIP_ERROR_INVALID_ARGUMENT == err); - - // Invalid key (empty) - ICDMonitoringEntry entry3(&keystore); - entry3.checkInNodeID = kClientNodeId11; - entry3.monitoredSubject = kClientNodeId12; - NL_TEST_ASSERT(aSuite, CHIP_ERROR_INVALID_ARGUMENT == entry3.SetKey(ByteSpan())); - err = table.Set(0, entry3); - NL_TEST_ASSERT(aSuite, CHIP_ERROR_INVALID_ARGUMENT == err); - - // Invalid key (too short) - ICDMonitoringEntry entry4(&keystore); - entry4.checkInNodeID = kClientNodeId11; - entry4.monitoredSubject = kClientNodeId12; - NL_TEST_ASSERT(aSuite, CHIP_ERROR_INVALID_ARGUMENT == entry4.SetKey(ByteSpan(kKeyBuffer0a))); - err = table.Set(0, entry4); - NL_TEST_ASSERT(aSuite, CHIP_ERROR_INVALID_ARGUMENT == err); - - // Invalid key (too long) - ICDMonitoringEntry entry5(&keystore); - entry5.checkInNodeID = kClientNodeId11; - entry5.monitoredSubject = kClientNodeId12; - NL_TEST_ASSERT(aSuite, CHIP_ERROR_INVALID_ARGUMENT == entry5.SetKey(ByteSpan(kKeyBuffer0b))); - err = table.Set(0, entry5); - NL_TEST_ASSERT(aSuite, CHIP_ERROR_INVALID_ARGUMENT == err); -} - -void TestSaveLoadRegistrationValueForMultipleFabrics(nlTestSuite * aSuite, void * aContext) -{ - TestPersistentStorageDelegate storage; - TestSessionKeystoreImpl keystore; - ICDMonitoringTable table1(storage, kTestFabricIndex1, kMaxTestClients1, &keystore); - ICDMonitoringTable table2(storage, kTestFabricIndex2, kMaxTestClients2, &keystore); - ICDMonitoringEntry entry(&keystore); - CHIP_ERROR err; - - // Insert in first fabric - ICDMonitoringEntry entry1(&keystore); - entry1.checkInNodeID = kClientNodeId11; - entry1.monitoredSubject = kClientNodeId12; - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == entry1.SetKey(ByteSpan(kKeyBuffer1a))); - err = table1.Set(0, entry1); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == err); - - // Insert in first fabric - ICDMonitoringEntry entry2(&keystore); - entry2.checkInNodeID = kClientNodeId12; - entry2.monitoredSubject = kClientNodeId11; - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == entry2.SetKey(ByteSpan(kKeyBuffer1b))); - err = table1.Set(1, entry2); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == err); - - // Insert in second fabric - ICDMonitoringEntry entry3(&keystore); - entry3.checkInNodeID = kClientNodeId21; - entry3.monitoredSubject = kClientNodeId22; - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == entry3.SetKey(ByteSpan(kKeyBuffer2a))); - err = table2.Set(0, entry3); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == err); - - // Insert in second fabric (one too many) - ICDMonitoringEntry entry4(&keystore); - entry4.checkInNodeID = kClientNodeId22; - entry4.monitoredSubject = kClientNodeId21; - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == entry4.SetKey(ByteSpan(kKeyBuffer2b))); - err = table2.Set(1, entry4); - NL_TEST_ASSERT(aSuite, CHIP_ERROR_INVALID_ARGUMENT == err); - - // Retrieve fabric1, first entry - err = table1.Get(0, entry); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == err); - NL_TEST_ASSERT(aSuite, kTestFabricIndex1 == entry.fabricIndex); - NL_TEST_ASSERT(aSuite, kClientNodeId11 == entry.checkInNodeID); - NL_TEST_ASSERT(aSuite, kClientNodeId12 == entry.monitoredSubject); - NL_TEST_ASSERT(aSuite, entry.IsKeyEquivalent(ByteSpan(kKeyBuffer1a))); - NL_TEST_ASSERT(aSuite, - memcmp(entry1.hmacKeyHandle.As(), - entry.hmacKeyHandle.As(), - sizeof(Crypto::Symmetric128BitsKeyByteArray)) == 0); - - // Retrieve fabric1, second entry - err = table1.Get(1, entry); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == err); - NL_TEST_ASSERT(aSuite, kTestFabricIndex1 == entry.fabricIndex); - NL_TEST_ASSERT(aSuite, kClientNodeId12 == entry.checkInNodeID); - NL_TEST_ASSERT(aSuite, kClientNodeId11 == entry.monitoredSubject); - NL_TEST_ASSERT(aSuite, entry.IsKeyEquivalent(ByteSpan(kKeyBuffer1b))); - NL_TEST_ASSERT(aSuite, - memcmp(entry2.hmacKeyHandle.As(), - entry.hmacKeyHandle.As(), - sizeof(Crypto::Symmetric128BitsKeyByteArray)) == 0); - - // Retrieve fabric2, first entry - err = table2.Get(0, entry); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == err); - NL_TEST_ASSERT(aSuite, kTestFabricIndex2 == entry.fabricIndex); - NL_TEST_ASSERT(aSuite, kClientNodeId21 == entry.checkInNodeID); - NL_TEST_ASSERT(aSuite, kClientNodeId22 == entry.monitoredSubject); - NL_TEST_ASSERT(aSuite, entry.IsKeyEquivalent(ByteSpan(kKeyBuffer2a))); - NL_TEST_ASSERT(aSuite, - memcmp(entry3.hmacKeyHandle.As(), - entry.hmacKeyHandle.As(), - sizeof(Crypto::Symmetric128BitsKeyByteArray)) == 0); -} - -void TestDeleteValidEntryFromStorage(nlTestSuite * aSuite, void * context) -{ - TestPersistentStorageDelegate storage; - TestSessionKeystoreImpl keystore; - ICDMonitoringTable table1(storage, kTestFabricIndex1, kMaxTestClients1, &keystore); - ICDMonitoringTable table2(storage, kTestFabricIndex2, kMaxTestClients2, &keystore); - ICDMonitoringEntry entry(&keystore); - CHIP_ERROR err; - - // Insert in first fabric - ICDMonitoringEntry entry1(&keystore); - entry1.checkInNodeID = kClientNodeId11; - entry1.monitoredSubject = kClientNodeId12; - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == entry1.SetKey(ByteSpan(kKeyBuffer1a))); - err = table1.Set(0, entry1); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == err); - - // Insert in first fabric - ICDMonitoringEntry entry2(&keystore); - entry2.checkInNodeID = kClientNodeId12; - entry2.monitoredSubject = kClientNodeId11; - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == entry2.SetKey(ByteSpan(kKeyBuffer2a))); - err = table1.Set(1, entry2); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == err); - - // Insert in second fabric - ICDMonitoringEntry entry3(&keystore); - entry3.checkInNodeID = kClientNodeId21; - entry3.monitoredSubject = kClientNodeId22; - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == entry3.SetKey(ByteSpan(kKeyBuffer1b))); - err = table2.Set(0, entry3); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == err); - - // Remove (invalid) - err = table1.Remove(2); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR != err); - - // Retrieve fabric1 - err = table1.Get(0, entry); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == err); - NL_TEST_ASSERT(aSuite, kTestFabricIndex1 == entry.fabricIndex); - NL_TEST_ASSERT(aSuite, kClientNodeId11 == entry.checkInNodeID); - NL_TEST_ASSERT(aSuite, kClientNodeId12 == entry.monitoredSubject); - NL_TEST_ASSERT(aSuite, entry.IsKeyEquivalent(ByteSpan(kKeyBuffer1a))); - NL_TEST_ASSERT(aSuite, - memcmp(entry1.hmacKeyHandle.As(), - entry.hmacKeyHandle.As(), - sizeof(Crypto::Symmetric128BitsKeyByteArray)) == 0); - - // Retrieve second entry (not modified) - err = table1.Get(1, entry); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == err); - NL_TEST_ASSERT(aSuite, kTestFabricIndex1 == entry.fabricIndex); - NL_TEST_ASSERT(aSuite, kClientNodeId12 == entry.checkInNodeID); - NL_TEST_ASSERT(aSuite, kClientNodeId11 == entry.monitoredSubject); - NL_TEST_ASSERT(aSuite, entry.IsKeyEquivalent(ByteSpan(kKeyBuffer2a))); - NL_TEST_ASSERT(aSuite, - memcmp(entry2.hmacKeyHandle.As(), - entry.hmacKeyHandle.As(), - sizeof(Crypto::Symmetric128BitsKeyByteArray)) == 0); - - // Remove (existing) - err = table1.Remove(0); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == err); - - // Retrieve second entry (shifted down) - err = table1.Get(1, entry); - NL_TEST_ASSERT(aSuite, CHIP_ERROR_NOT_FOUND == err); - - err = table1.Get(0, entry); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == err); - NL_TEST_ASSERT(aSuite, kTestFabricIndex1 == entry.fabricIndex); - NL_TEST_ASSERT(aSuite, kClientNodeId12 == entry.checkInNodeID); - NL_TEST_ASSERT(aSuite, kClientNodeId11 == entry.monitoredSubject); - NL_TEST_ASSERT(aSuite, entry.IsKeyEquivalent(ByteSpan(kKeyBuffer2a))); - NL_TEST_ASSERT(aSuite, - memcmp(entry2.hmacKeyHandle.As(), - entry.hmacKeyHandle.As(), - sizeof(Crypto::Symmetric128BitsKeyByteArray)) == 0); - - // Retrieve fabric2, first entry - err = table2.Get(0, entry); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == err); - NL_TEST_ASSERT(aSuite, kTestFabricIndex2 == entry.fabricIndex); - NL_TEST_ASSERT(aSuite, kClientNodeId21 == entry.checkInNodeID); - NL_TEST_ASSERT(aSuite, kClientNodeId22 == entry.monitoredSubject); - NL_TEST_ASSERT(aSuite, entry.IsKeyEquivalent(ByteSpan(kKeyBuffer1b))); - NL_TEST_ASSERT(aSuite, - memcmp(entry3.hmacKeyHandle.As(), - entry.hmacKeyHandle.As(), - sizeof(Crypto::Symmetric128BitsKeyByteArray)) == 0); - - // Remove all (fabric 1) - err = table1.RemoveAll(); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == err); - - err = table1.Get(0, entry); - NL_TEST_ASSERT(aSuite, CHIP_ERROR_NOT_FOUND == err); - - // Check fabric 2 - err = table2.Get(0, entry); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == err); - NL_TEST_ASSERT(aSuite, kTestFabricIndex2 == entry.fabricIndex); - NL_TEST_ASSERT(aSuite, kClientNodeId21 == entry.checkInNodeID); - NL_TEST_ASSERT(aSuite, kClientNodeId22 == entry.monitoredSubject); - NL_TEST_ASSERT(aSuite, entry.IsKeyEquivalent(ByteSpan(kKeyBuffer1b))); - NL_TEST_ASSERT(aSuite, - memcmp(entry3.hmacKeyHandle.As(), - entry.hmacKeyHandle.As(), - sizeof(Crypto::Symmetric128BitsKeyByteArray)) == 0); - - // Remove all (fabric 2) - err = table2.RemoveAll(); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == err); - - err = table2.Get(0, entry); - NL_TEST_ASSERT(aSuite, CHIP_ERROR_NOT_FOUND == err); -} - -} // namespace - -/** - * Set up the test suite. - */ -int Test_Setup(void * inContext) -{ - return SUCCESS; -} - -int TestClientMonitoringRegistrationTable() -{ - static nlTest sTests[] = { NL_TEST_DEF("TestEntryKeyFunctions", TestEntryKeyFunctions), - NL_TEST_DEF("TestEntryAssignationOverload", TestEntryAssignationOverload), - NL_TEST_DEF("TestSaveAndLoadRegistrationValue", TestSaveAndLoadRegistrationValue), - NL_TEST_DEF("TestSaveAllInvalidRegistrationValues", TestSaveAllInvalidRegistrationValues), - NL_TEST_DEF("TestSaveLoadRegistrationValueForMultipleFabrics", - TestSaveLoadRegistrationValueForMultipleFabrics), - NL_TEST_DEF("TestDeleteValidEntryFromStorage", TestDeleteValidEntryFromStorage), - NL_TEST_SENTINEL() }; - - nlTestSuite cmSuite = { "TestClientMonitoringRegistrationTable", &sTests[0], &Test_Setup, nullptr }; - - nlTestRunner(&cmSuite, nullptr); - return (nlTestRunnerStats(&cmSuite)); -} - -CHIP_REGISTER_TEST_SUITE(TestClientMonitoringRegistrationTable) diff --git a/src/inet/tests/TestInetCommonPosix.cpp b/src/inet/tests/TestInetCommonPosix.cpp index 71437913819c24..9d5e4588979d1a 100644 --- a/src/inet/tests/TestInetCommonPosix.cpp +++ b/src/inet/tests/TestInetCommonPosix.cpp @@ -71,8 +71,13 @@ using namespace chip::Inet; System::LayerImpl gSystemLayer; +#if INET_CONFIG_ENABLE_UDP_ENDPOINT Inet::UDPEndPointManagerImpl gUDP; +#endif + +#if INET_CONFIG_ENABLE_TCP_ENDPOINT Inet::TCPEndPointManagerImpl gTCP; +#endif #if CHIP_SYSTEM_CONFIG_USE_LWIP && !(CHIP_SYSTEM_CONFIG_LWIP_SKIP_INIT) static sys_mbox_t * sLwIPEventQueue = NULL; @@ -329,9 +334,12 @@ void InitNetwork() AcquireLwIP(); #endif // CHIP_SYSTEM_CONFIG_USE_LWIP && !(CHIP_SYSTEM_CONFIG_LWIP_SKIP_INIT) - +#if INET_CONFIG_ENABLE_TCP_ENDPOINT gTCP.Init(gSystemLayer); +#endif +#if INET_CONFIG_ENABLE_TCP_ENDPOINT gUDP.Init(gSystemLayer); +#endif } void ServiceEvents(uint32_t aSleepTimeMilliseconds) @@ -413,17 +421,21 @@ static void OnLwIPInitComplete(void * arg) void ShutdownNetwork() { + +#if INET_CONFIG_ENABLE_TCP_ENDPOINT gTCP.ForEachEndPoint([](TCPEndPoint * lEndPoint) -> Loop { gTCP.ReleaseEndPoint(lEndPoint); return Loop::Continue; }); gTCP.Shutdown(); - +#endif +#if INET_CONFIG_ENABLE_UDP_ENDPOINT gUDP.ForEachEndPoint([](UDPEndPoint * lEndPoint) -> Loop { gUDP.ReleaseEndPoint(lEndPoint); return Loop::Continue; }); gUDP.Shutdown(); +#endif #if CHIP_SYSTEM_CONFIG_USE_LWIP && !(CHIP_SYSTEM_CONFIG_LWIP_SKIP_INIT) ReleaseLwIP(); #endif diff --git a/src/test_driver/openiotsdk/unit-tests/test_components.txt b/src/test_driver/openiotsdk/unit-tests/test_components.txt index e6e64c61106c9a..5887de730725df 100644 --- a/src/test_driver/openiotsdk/unit-tests/test_components.txt +++ b/src/test_driver/openiotsdk/unit-tests/test_components.txt @@ -17,3 +17,4 @@ SetupPayloadTests SupportTests UserDirectedCommissioningTests SecureChannelTests +ICDServerTests diff --git a/src/test_driver/openiotsdk/unit-tests/test_components_nl.txt b/src/test_driver/openiotsdk/unit-tests/test_components_nl.txt index 93c9c1389e0a5b..e3d66b49d3f644 100644 --- a/src/test_driver/openiotsdk/unit-tests/test_components_nl.txt +++ b/src/test_driver/openiotsdk/unit-tests/test_components_nl.txt @@ -1,5 +1,6 @@ AppTests DataModelTests +ICDServerTestsNL InetLayerTests MessagingLayerTests SecureChannelTestsNL diff --git a/src/transport/raw/tests/NetworkTestHelpers.cpp b/src/transport/raw/tests/NetworkTestHelpers.cpp index 5d967ebed3d2fc..a4cd6329975c0e 100644 --- a/src/transport/raw/tests/NetworkTestHelpers.cpp +++ b/src/transport/raw/tests/NetworkTestHelpers.cpp @@ -35,10 +35,13 @@ CHIP_ERROR IOContext::Init() InitSystemLayer(); InitNetwork(); - mSystemLayer = &gSystemLayer; + mSystemLayer = &gSystemLayer; +#if INET_CONFIG_ENABLE_TCP_ENDPOINT mTCPEndPointManager = &gTCP; +#endif +#if INET_CONFIG_ENABLE_UDP_ENDPOINT mUDPEndPointManager = &gUDP; - +#endif return err; } From 335ae1912d9356e3710fb74ee1e7d1ddeda9515e Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Tue, 30 Apr 2024 17:09:54 -0400 Subject: [PATCH 18/33] Add some better logging around PASE session setup in Matter.framework. (#33231) Log the device ID being used. --- .../Framework/CHIP/MTRDeviceController.mm | 9 ++++++++- src/darwin/Framework/CHIP/MTRSetupPayload.h | 2 ++ src/darwin/Framework/CHIP/MTRSetupPayload.mm | 20 +++++++++++++++++++ .../Framework/CHIPTests/MTRDeviceTests.m | 10 ++++++++++ 4 files changed, 40 insertions(+), 1 deletion(-) diff --git a/src/darwin/Framework/CHIP/MTRDeviceController.mm b/src/darwin/Framework/CHIP/MTRDeviceController.mm index 94d9882b4cd9d1..fe266c22a2fff9 100644 --- a/src/darwin/Framework/CHIP/MTRDeviceController.mm +++ b/src/darwin/Framework/CHIP/MTRDeviceController.mm @@ -616,6 +616,8 @@ - (BOOL)setupCommissioningSessionWithPayload:(MTRSetupPayload *)payload newNodeID:(NSNumber *)newNodeID error:(NSError * __autoreleasing *)error { + MTR_LOG_DEFAULT("Setting up commissioning session for device ID 0x%016llX with setup payload %@", newNodeID.unsignedLongLongValue, payload); + [[MTRMetricsCollector sharedInstance] resetMetrics]; // Track overall commissioning @@ -663,6 +665,8 @@ - (BOOL)setupCommissioningSessionWithDiscoveredDevice:(MTRCommissionableBrowserR newNodeID:(NSNumber *)newNodeID error:(NSError * __autoreleasing *)error { + MTR_LOG_DEFAULT("Setting up commissioning session for already-discovered device %@ and device ID 0x%016llX with setup payload %@", discoveredDevice, newNodeID.unsignedLongLongValue, payload); + [[MTRMetricsCollector sharedInstance] resetMetrics]; // Track overall commissioning @@ -912,7 +916,10 @@ - (MTRBaseDevice *)deviceBeingCommissionedWithNodeID:(NSNumber *)nodeID error:(N return [[MTRBaseDevice alloc] initWithPASEDevice:deviceProxy controller:self]; }; - return [self syncRunOnWorkQueueWithReturnValue:block error:error]; + MTRBaseDevice * device = [self syncRunOnWorkQueueWithReturnValue:block error:error]; + MTR_LOG_DEFAULT("Getting device being commissioned with node ID 0x%016llX: %@ (error: %@)", + nodeID.unsignedLongLongValue, device, (error ? *error : nil)); + return device; } - (MTRBaseDevice *)baseDeviceForNodeID:(NSNumber *)nodeID diff --git a/src/darwin/Framework/CHIP/MTRSetupPayload.h b/src/darwin/Framework/CHIP/MTRSetupPayload.h index 9d6466b9cbdc32..7f11fc582ba4b3 100644 --- a/src/darwin/Framework/CHIP/MTRSetupPayload.h +++ b/src/darwin/Framework/CHIP/MTRSetupPayload.h @@ -28,6 +28,8 @@ typedef NS_OPTIONS(NSUInteger, MTRDiscoveryCapabilities) { MTRDiscoveryCapabilitiesBLE = 1 << 1, // Device supports BLE MTRDiscoveryCapabilitiesOnNetwork = 1 << 2, // Device supports On Network setup + // If new values are added here, update the "description" method to include them. + MTRDiscoveryCapabilitiesAllMask = MTRDiscoveryCapabilitiesSoftAP | MTRDiscoveryCapabilitiesBLE | MTRDiscoveryCapabilitiesOnNetwork, }; diff --git a/src/darwin/Framework/CHIP/MTRSetupPayload.mm b/src/darwin/Framework/CHIP/MTRSetupPayload.mm index 11afc2a15c1cde..d5788c63dc6f6c 100644 --- a/src/darwin/Framework/CHIP/MTRSetupPayload.mm +++ b/src/darwin/Framework/CHIP/MTRSetupPayload.mm @@ -246,6 +246,26 @@ + (MTRSetupPayload * _Nullable)setupPayloadWithOnboardingPayload:(NSString *)onb return payload; } +- (NSString *)description +{ + NSMutableArray * capabilities = [NSMutableArray array]; + if (self.discoveryCapabilities & MTRDiscoveryCapabilitiesSoftAP) { + [capabilities addObject:@"SoftAP"]; + } + if (self.discoveryCapabilities & MTRDiscoveryCapabilitiesBLE) { + [capabilities addObject:@"BLE"]; + } + if (self.discoveryCapabilities & MTRDiscoveryCapabilitiesOnNetwork) { + [capabilities addObject:@"OnNetwork"]; + } + if (capabilities.count == 0) { + [capabilities addObject:@"Unknown"]; + } + + return [NSString stringWithFormat:@"", + self.discriminator.unsignedIntValue, self.hasShortDiscriminator ? @"YES" : @"NO", [capabilities componentsJoinedByString:@"|"]]; +} + #pragma mark - NSSecureCoding static NSString * const MTRSetupPayloadCodingKeyVersion = @"MTRSP.ck.version"; diff --git a/src/darwin/Framework/CHIPTests/MTRDeviceTests.m b/src/darwin/Framework/CHIPTests/MTRDeviceTests.m index da6ba88650a448..2dc01461826b40 100644 --- a/src/darwin/Framework/CHIPTests/MTRDeviceTests.m +++ b/src/darwin/Framework/CHIPTests/MTRDeviceTests.m @@ -95,6 +95,16 @@ - (void)controller:(MTRDeviceController *)controller commissioningSessionEstabli { XCTAssertEqual(error.code, 0); + NSError * getDeviceError = nil; + __auto_type * device = [controller deviceBeingCommissionedWithNodeID:@(kDeviceId) error:&getDeviceError]; + XCTAssertNil(getDeviceError); + XCTAssertNotNil(device); + + // Now check that getting with some other random id fails. + device = [controller deviceBeingCommissionedWithNodeID:@(kDeviceId + 1) error:&getDeviceError]; + XCTAssertNil(device); + XCTAssertNotNil(getDeviceError); + __auto_type * params = [[MTRCommissioningParameters alloc] init]; params.countryCode = @("au"); From a8cfbac07730816dbc68cd797332ea81227892d5 Mon Sep 17 00:00:00 2001 From: Pradip De Date: Tue, 26 Mar 2024 20:59:15 -0700 Subject: [PATCH 19/33] TCP connection setup/management and CASESession association. Add TCPConnect()/TCPDisconnect() API for explicit connection setup. Currently, connecting to a peer is coupled with sending a message to the peer. This decouples the two and creates a clear API for connecting to a peer address. Goes along with the existing Disconnect() API. This would be essential during activation of retained sessions by solely connecting to the peer and associating with the retained session. Surface Connection completion and Closure callbacks and hook them through SessionManager(TransportMgr delegate) and CASESession. Mark SecureSession as defunct on connection closures. Modify ActiveConnectionState in TCPBase to hold state for each connection, so that it is able to handle the various control flow paths. Associate a session with a connection object. Associate the PeerAddress with the session early. Pass the PeerAddress in the Find APIs. This helps check against the correct TransportType when searching for a Sesssion in the SessionTable. Add a `large payload` flag in EstablishSession() and Session lookup functions to create/associate with the correct session and transport. Have default configurations for TCP in a separate TCPConfig.h. Refactor echo_requester.cpp and echo_responder.cpp to use the session associated with the connection. Handle Connection closure at ExchangeMgr and uplevel to corresponding ExchangeContext using the corresponding session handle. Add tests around connection establishment in TestTCP. --- examples/shell/shell_common/include/Globals.h | 2 + src/app/CASESessionManager.cpp | 65 ++- src/app/CASESessionManager.h | 35 +- src/app/OperationalSessionSetup.cpp | 28 +- src/app/OperationalSessionSetup.h | 17 +- src/app/server/Server.cpp | 9 + src/app/server/Server.h | 10 + src/app/tests/TestCommissionManager.cpp | 4 + .../CHIPDeviceControllerFactory.cpp | 6 + .../CHIPDeviceControllerSystemState.h | 23 +- .../internal/GenericPlatformManagerImpl.ipp | 14 + src/messaging/ExchangeContext.cpp | 7 + src/messaging/ExchangeContext.h | 3 + src/messaging/ExchangeMgr.cpp | 16 + src/messaging/ExchangeMgr.h | 7 + src/messaging/tests/echo/common.cpp | 5 - src/messaging/tests/echo/echo_requester.cpp | 146 +++++- src/messaging/tests/echo/echo_responder.cpp | 2 + src/protocols/secure_channel/CASESession.cpp | 130 +++++- src/protocols/secure_channel/CASESession.h | 17 + .../secure_channel/PairingSession.cpp | 13 + .../UserDirectedCommissioning.h | 6 +- .../UserDirectedCommissioningClient.cpp | 4 +- .../UserDirectedCommissioningServer.cpp | 4 +- src/transport/BUILD.gn | 1 + src/transport/Session.h | 21 + src/transport/SessionConnectionDelegate.h | 46 ++ src/transport/SessionDelegate.h | 4 + src/transport/SessionManager.cpp | 289 ++++++++++-- src/transport/SessionManager.h | 81 +++- src/transport/TransportMgr.h | 23 +- src/transport/TransportMgrBase.cpp | 79 +++- src/transport/TransportMgrBase.h | 23 +- src/transport/UnauthenticatedSessionTable.h | 42 +- src/transport/raw/ActiveTCPConnectionState.h | 125 ++++++ src/transport/raw/BUILD.gn | 12 +- src/transport/raw/Base.h | 63 ++- src/transport/raw/TCP.cpp | 424 ++++++++++++------ src/transport/raw/TCP.h | 155 ++++--- src/transport/raw/TCPConfig.h | 127 ++++++ src/transport/raw/Tuple.h | 79 +++- src/transport/raw/tests/BUILD.gn | 7 +- src/transport/raw/tests/TestTCP.cpp | 253 ++++++++++- src/transport/raw/tests/TestUDP.cpp | 3 +- 44 files changed, 2062 insertions(+), 368 deletions(-) create mode 100644 src/transport/SessionConnectionDelegate.h create mode 100644 src/transport/raw/ActiveTCPConnectionState.h create mode 100644 src/transport/raw/TCPConfig.h diff --git a/examples/shell/shell_common/include/Globals.h b/examples/shell/shell_common/include/Globals.h index d91620ca0ad171..69162be92f5204 100644 --- a/examples/shell/shell_common/include/Globals.h +++ b/examples/shell/shell_common/include/Globals.h @@ -24,7 +24,9 @@ #include #include #include +#if INET_CONFIG_ENABLE_TCP_ENDPOINT #include +#endif // INET_CONFIG_ENABLE_TCP_ENDPOINT #include #if INET_CONFIG_ENABLE_TCP_ENDPOINT diff --git a/src/app/CASESessionManager.cpp b/src/app/CASESessionManager.cpp index c15ddcabe01c04..162ae7021a9f9f 100644 --- a/src/app/CASESessionManager.cpp +++ b/src/app/CASESessionManager.cpp @@ -30,62 +30,55 @@ CHIP_ERROR CASESessionManager::Init(chip::System::Layer * systemLayer, const CAS } void CASESessionManager::FindOrEstablishSession(const ScopedNodeId & peerId, Callback::Callback * onConnection, - Callback::Callback * onFailure + Callback::Callback * onFailure, #if CHIP_DEVICE_CONFIG_ENABLE_AUTOMATIC_CASE_RETRIES - , - uint8_t attemptCount, Callback::Callback * onRetry + uint8_t attemptCount, Callback::Callback * onRetry, #endif // CHIP_DEVICE_CONFIG_ENABLE_AUTOMATIC_CASE_RETRIES -) + TransportPayloadCapability transportPayloadCapability) { - FindOrEstablishSessionHelper(peerId, onConnection, onFailure, nullptr + FindOrEstablishSessionHelper(peerId, onConnection, onFailure, nullptr, #if CHIP_DEVICE_CONFIG_ENABLE_AUTOMATIC_CASE_RETRIES - , - attemptCount, onRetry + attemptCount, onRetry, #endif - ); + transportPayloadCapability); } void CASESessionManager::FindOrEstablishSession(const ScopedNodeId & peerId, Callback::Callback * onConnection, - Callback::Callback * onSetupFailure + Callback::Callback * onSetupFailure, #if CHIP_DEVICE_CONFIG_ENABLE_AUTOMATIC_CASE_RETRIES - , - uint8_t attemptCount, Callback::Callback * onRetry + uint8_t attemptCount, Callback::Callback * onRetry, #endif -) + TransportPayloadCapability transportPayloadCapability) { - FindOrEstablishSessionHelper(peerId, onConnection, nullptr, onSetupFailure + FindOrEstablishSessionHelper(peerId, onConnection, nullptr, onSetupFailure, #if CHIP_DEVICE_CONFIG_ENABLE_AUTOMATIC_CASE_RETRIES - , - attemptCount, onRetry + attemptCount, onRetry, #endif - ); + transportPayloadCapability); } void CASESessionManager::FindOrEstablishSession(const ScopedNodeId & peerId, Callback::Callback * onConnection, - std::nullptr_t + std::nullptr_t, #if CHIP_DEVICE_CONFIG_ENABLE_AUTOMATIC_CASE_RETRIES - , - uint8_t attemptCount, Callback::Callback * onRetry + uint8_t attemptCount, Callback::Callback * onRetry, #endif -) + TransportPayloadCapability transportPayloadCapability) { - FindOrEstablishSessionHelper(peerId, onConnection, nullptr, nullptr + FindOrEstablishSessionHelper(peerId, onConnection, nullptr, nullptr, #if CHIP_DEVICE_CONFIG_ENABLE_AUTOMATIC_CASE_RETRIES - , - attemptCount, onRetry + attemptCount, onRetry, #endif - ); + transportPayloadCapability); } void CASESessionManager::FindOrEstablishSessionHelper(const ScopedNodeId & peerId, Callback::Callback * onConnection, Callback::Callback * onFailure, - Callback::Callback * onSetupFailure + Callback::Callback * onSetupFailure, #if CHIP_DEVICE_CONFIG_ENABLE_AUTOMATIC_CASE_RETRIES - , - uint8_t attemptCount, Callback::Callback * onRetry + uint8_t attemptCount, Callback::Callback * onRetry, #endif -) + TransportPayloadCapability transportPayloadCapability) { ChipLogDetail(CASESessionManager, "FindOrEstablishSession: PeerId = [%d:" ChipLogFormatX64 "]", peerId.GetFabricIndex(), ChipLogValueX64(peerId.GetNodeId())); @@ -124,12 +117,12 @@ void CASESessionManager::FindOrEstablishSessionHelper(const ScopedNodeId & peerI if (onFailure != nullptr) { - session->Connect(onConnection, onFailure); + session->Connect(onConnection, onFailure, transportPayloadCapability); } if (onSetupFailure != nullptr) { - session->Connect(onConnection, onSetupFailure); + session->Connect(onConnection, onSetupFailure, transportPayloadCapability); } } @@ -143,10 +136,11 @@ void CASESessionManager::ReleaseAllSessions() mConfig.sessionSetupPool->ReleaseAllSessionSetup(); } -CHIP_ERROR CASESessionManager::GetPeerAddress(const ScopedNodeId & peerId, Transport::PeerAddress & addr) +CHIP_ERROR CASESessionManager::GetPeerAddress(const ScopedNodeId & peerId, Transport::PeerAddress & addr, + TransportPayloadCapability transportPayloadCapability) { ReturnErrorOnFailure(mConfig.sessionInitParams.Validate()); - auto optionalSessionHandle = FindExistingSession(peerId); + auto optionalSessionHandle = FindExistingSession(peerId, transportPayloadCapability); ReturnErrorCodeIf(!optionalSessionHandle.HasValue(), CHIP_ERROR_NOT_CONNECTED); addr = optionalSessionHandle.Value()->AsSecureSession()->GetPeerAddress(); return CHIP_NO_ERROR; @@ -182,10 +176,11 @@ OperationalSessionSetup * CASESessionManager::FindExistingSessionSetup(const Sco return mConfig.sessionSetupPool->FindSessionSetup(peerId, forAddressUpdate); } -Optional CASESessionManager::FindExistingSession(const ScopedNodeId & peerId) const +Optional CASESessionManager::FindExistingSession(const ScopedNodeId & peerId, + const TransportPayloadCapability transportPayloadCapability) const { - return mConfig.sessionInitParams.sessionManager->FindSecureSessionForNode(peerId, - MakeOptional(Transport::SecureSession::Type::kCASE)); + return mConfig.sessionInitParams.sessionManager->FindSecureSessionForNode( + peerId, MakeOptional(Transport::SecureSession::Type::kCASE), transportPayloadCapability); } void CASESessionManager::ReleaseSession(OperationalSessionSetup * session) diff --git a/src/app/CASESessionManager.h b/src/app/CASESessionManager.h index e78478852b640e..38b39108b43b7e 100644 --- a/src/app/CASESessionManager.h +++ b/src/app/CASESessionManager.h @@ -26,6 +26,7 @@ #include #include #include +#include #include namespace chip { @@ -78,12 +79,11 @@ class CASESessionManager : public OperationalSessionReleaseDelegate, public Sess * setup is not successful. */ void FindOrEstablishSession(const ScopedNodeId & peerId, Callback::Callback * onConnection, - Callback::Callback * onFailure + Callback::Callback * onFailure, #if CHIP_DEVICE_CONFIG_ENABLE_AUTOMATIC_CASE_RETRIES - , - uint8_t attemptCount = 1, Callback::Callback * onRetry = nullptr + uint8_t attemptCount = 1, Callback::Callback * onRetry = nullptr, #endif // CHIP_DEVICE_CONFIG_ENABLE_AUTOMATIC_CASE_RETRIES - ); + TransportPayloadCapability transportPayloadCapability = TransportPayloadCapability::kMRPPayload); /** * Find an existing session for the given node ID or trigger a new session request. @@ -106,14 +106,14 @@ class CASESessionManager : public OperationalSessionReleaseDelegate, public Sess * @param onSetupFailure A callback to be called upon an extended device connection failure. * @param attemptCount The number of retry attempts if session setup fails (default is 1). * @param onRetry A callback to be called on a retry attempt (enabled by a config flag). + * @param transportPayloadCapability An indicator of what payload types the session needs to be able to transport. */ void FindOrEstablishSession(const ScopedNodeId & peerId, Callback::Callback * onConnection, - Callback::Callback * onSetupFailure + Callback::Callback * onSetupFailure, #if CHIP_DEVICE_CONFIG_ENABLE_AUTOMATIC_CASE_RETRIES - , - uint8_t attemptCount = 1, Callback::Callback * onRetry = nullptr + uint8_t attemptCount = 1, Callback::Callback * onRetry = nullptr, #endif // CHIP_DEVICE_CONFIG_ENABLE_AUTOMATIC_CASE_RETRIES - ); + TransportPayloadCapability transportPayloadCapability = TransportPayloadCapability::kMRPPayload); /** * Find an existing session for the given node ID or trigger a new session request. @@ -134,13 +134,13 @@ class CASESessionManager : public OperationalSessionReleaseDelegate, public Sess * @param onConnection A callback to be called upon successful connection establishment. * @param attemptCount The number of retry attempts if session setup fails (default is 1). * @param onRetry A callback to be called on a retry attempt (enabled by a config flag). + * @param transportPayloadCapability An indicator of what payload types the session needs to be able to transport. */ - void FindOrEstablishSession(const ScopedNodeId & peerId, Callback::Callback * onConnection, std::nullptr_t + void FindOrEstablishSession(const ScopedNodeId & peerId, Callback::Callback * onConnection, std::nullptr_t, #if CHIP_DEVICE_CONFIG_ENABLE_AUTOMATIC_CASE_RETRIES - , - uint8_t attemptCount = 1, Callback::Callback * onRetry = nullptr + uint8_t attemptCount = 1, Callback::Callback * onRetry = nullptr, #endif // CHIP_DEVICE_CONFIG_ENABLE_AUTOMATIC_CASE_RETRIES - ); + TransportPayloadCapability transportPayloadCapability = TransportPayloadCapability::kMRPPayload); void ReleaseSessionsForFabric(FabricIndex fabricIndex); @@ -154,7 +154,8 @@ class CASESessionManager : public OperationalSessionReleaseDelegate, public Sess * an ongoing session with the peer node. If the session doesn't exist, the API will return * `CHIP_ERROR_NOT_CONNECTED` error. */ - CHIP_ERROR GetPeerAddress(const ScopedNodeId & peerId, Transport::PeerAddress & addr); + CHIP_ERROR GetPeerAddress(const ScopedNodeId & peerId, Transport::PeerAddress & addr, + TransportPayloadCapability transportPayloadCapability = TransportPayloadCapability::kMRPPayload); //////////// OperationalSessionReleaseDelegate Implementation /////////////// void ReleaseSession(OperationalSessionSetup * device) override; @@ -165,15 +166,17 @@ class CASESessionManager : public OperationalSessionReleaseDelegate, public Sess private: OperationalSessionSetup * FindExistingSessionSetup(const ScopedNodeId & peerId, bool forAddressUpdate = false) const; - Optional FindExistingSession(const ScopedNodeId & peerId) const; + Optional FindExistingSession( + const ScopedNodeId & peerId, + const TransportPayloadCapability transportPayloadCapability = TransportPayloadCapability::kMRPPayload) const; void FindOrEstablishSessionHelper(const ScopedNodeId & peerId, Callback::Callback * onConnection, Callback::Callback * onFailure, Callback::Callback * onSetupFailure, #if CHIP_DEVICE_CONFIG_ENABLE_AUTOMATIC_CASE_RETRIES - uint8_t attemptCount, Callback::Callback * onRetry + uint8_t attemptCount, Callback::Callback * onRetry, #endif - ); + TransportPayloadCapability transportPayloadCapability); CASESessionManagerConfig mConfig; }; diff --git a/src/app/OperationalSessionSetup.cpp b/src/app/OperationalSessionSetup.cpp index 157de953116ef5..9d91b7b573a59f 100644 --- a/src/app/OperationalSessionSetup.cpp +++ b/src/app/OperationalSessionSetup.cpp @@ -76,8 +76,8 @@ bool OperationalSessionSetup::AttachToExistingSecureSession() mState == State::WaitingForRetry, false); - auto sessionHandle = - mInitParams.sessionManager->FindSecureSessionForNode(mPeerId, MakeOptional(Transport::SecureSession::Type::kCASE)); + auto sessionHandle = mInitParams.sessionManager->FindSecureSessionForNode( + mPeerId, MakeOptional(Transport::SecureSession::Type::kCASE), mTransportPayloadCapability); if (!sessionHandle.HasValue()) return false; @@ -93,11 +93,13 @@ bool OperationalSessionSetup::AttachToExistingSecureSession() void OperationalSessionSetup::Connect(Callback::Callback * onConnection, Callback::Callback * onFailure, - Callback::Callback * onSetupFailure) + Callback::Callback * onSetupFailure, + TransportPayloadCapability transportPayloadCapability) { CHIP_ERROR err = CHIP_NO_ERROR; bool isConnected = false; + mTransportPayloadCapability = transportPayloadCapability; // // Always enqueue our user provided callbacks into our callback list. // If anything goes wrong below, we'll trigger failures (including any queued from @@ -180,15 +182,17 @@ void OperationalSessionSetup::Connect(Callback::Callback * on } void OperationalSessionSetup::Connect(Callback::Callback * onConnection, - Callback::Callback * onFailure) + Callback::Callback * onFailure, + TransportPayloadCapability transportPayloadCapability) { - Connect(onConnection, onFailure, nullptr); + Connect(onConnection, onFailure, nullptr, transportPayloadCapability); } void OperationalSessionSetup::Connect(Callback::Callback * onConnection, - Callback::Callback * onSetupFailure) + Callback::Callback * onSetupFailure, + TransportPayloadCapability transportPayloadCapability) { - Connect(onConnection, nullptr, onSetupFailure); + Connect(onConnection, nullptr, onSetupFailure, transportPayloadCapability); } void OperationalSessionSetup::UpdateDeviceData(const Transport::PeerAddress & addr, const ReliableMessageProtocolConfig & config) @@ -288,6 +292,16 @@ void OperationalSessionSetup::UpdateDeviceData(const Transport::PeerAddress & ad CHIP_ERROR OperationalSessionSetup::EstablishConnection(const ReliableMessageProtocolConfig & config) { +#if INET_CONFIG_ENABLE_TCP_ENDPOINT + // TODO: Combine LargePayload flag with DNS-SD advertisements from peer. + // Issue #32348. + if (mTransportPayloadCapability == TransportPayloadCapability::kLargePayload) + { + // Set the transport type for carrying large payloads + mDeviceAddress.SetTransportType(chip::Transport::Type::kTcp); + } +#endif + mCASEClient = mClientPool->Allocate(); ReturnErrorCodeIf(mCASEClient == nullptr, CHIP_ERROR_NO_MEMORY); diff --git a/src/app/OperationalSessionSetup.h b/src/app/OperationalSessionSetup.h index 1de8c305353314..5955dbab0713bd 100644 --- a/src/app/OperationalSessionSetup.h +++ b/src/app/OperationalSessionSetup.h @@ -210,8 +210,12 @@ class DLL_EXPORT OperationalSessionSetup : public SessionEstablishmentDelegate, * `onFailure` may be called before the Connect call returns, for error * cases that are detected synchronously (e.g. inability to start an address * lookup). + * + * `transportPayloadCapability` is set to kLargePayload when the session needs to be established + * over a transport that allows large payloads to be transferred, e.g., TCP. */ - void Connect(Callback::Callback * onConnection, Callback::Callback * onFailure); + void Connect(Callback::Callback * onConnection, Callback::Callback * onFailure, + TransportPayloadCapability transportPayloadCapability = TransportPayloadCapability::kMRPPayload); /* * This function can be called to establish a secure session with the device. @@ -227,8 +231,12 @@ class DLL_EXPORT OperationalSessionSetup : public SessionEstablishmentDelegate, * * `onSetupFailure` may be called before the Connect call returns, for error cases that are detected synchronously * (e.g. inability to start an address lookup). + * + * `transportPayloadCapability` is set to kLargePayload when the session needs to be established + * over a transport that allows large payloads to be transferred, e.g., TCP. */ - void Connect(Callback::Callback * onConnection, Callback::Callback * onSetupFailure); + void Connect(Callback::Callback * onConnection, Callback::Callback * onSetupFailure, + TransportPayloadCapability transportPayloadCapability = TransportPayloadCapability::kMRPPayload); bool IsForAddressUpdate() const { return mPerformingAddressUpdate; } @@ -318,6 +326,8 @@ class DLL_EXPORT OperationalSessionSetup : public SessionEstablishmentDelegate, System::Clock::Milliseconds16 mRequestedBusyDelay = System::Clock::kZero; #endif // CHIP_DEVICE_CONFIG_ENABLE_AUTOMATIC_CASE_RETRIES || CHIP_CONFIG_ENABLE_BUSY_HANDLING_FOR_OPERATIONAL_SESSION_SETUP + TransportPayloadCapability mTransportPayloadCapability = TransportPayloadCapability::kMRPPayload; + #if CHIP_DEVICE_CONFIG_ENABLE_AUTOMATIC_CASE_RETRIES // When we TryNextResult on the resolver, it will synchronously call back // into our OnNodeAddressResolved when it succeeds. We need to track @@ -351,7 +361,8 @@ class DLL_EXPORT OperationalSessionSetup : public SessionEstablishmentDelegate, void CleanupCASEClient(); void Connect(Callback::Callback * onConnection, Callback::Callback * onFailure, - Callback::Callback * onSetupFailure); + Callback::Callback * onSetupFailure, + TransportPayloadCapability transportPayloadCapability = TransportPayloadCapability::kMRPPayload); void EnqueueConnectionCallbacks(Callback::Callback * onConnection, Callback::Callback * onFailure, diff --git a/src/app/server/Server.cpp b/src/app/server/Server.cpp index cd9c56f9f021f7..1ad98d271262da 100644 --- a/src/app/server/Server.cpp +++ b/src/app/server/Server.cpp @@ -71,6 +71,9 @@ using chip::Transport::BleListenParameters; #endif using chip::Transport::PeerAddress; using chip::Transport::UdpListenParameters; +#if INET_CONFIG_ENABLE_TCP_ENDPOINT +using chip::Transport::TcpListenParameters; +#endif namespace { @@ -201,6 +204,12 @@ CHIP_ERROR Server::Init(const ServerInitParams & initParams) #if CONFIG_NETWORK_LAYER_BLE , BleListenParameters(DeviceLayer::ConnectivityMgr().GetBleLayer()) +#endif +#if INET_CONFIG_ENABLE_TCP_ENDPOINT + , + TcpListenParameters(DeviceLayer::TCPEndPointManager()) + .SetAddressType(IPAddressType::kIPv6) + .SetListenPort(mOperationalServicePort) #endif ); diff --git a/src/app/server/Server.h b/src/app/server/Server.h index 8f6fcd5abecc66..d649e0fc923896 100644 --- a/src/app/server/Server.h +++ b/src/app/server/Server.h @@ -77,6 +77,12 @@ namespace chip { inline constexpr size_t kMaxBlePendingPackets = 1; +#if INET_CONFIG_ENABLE_TCP_ENDPOINT +inline constexpr size_t kMaxTcpActiveConnectionCount = CHIP_CONFIG_MAX_ACTIVE_TCP_CONNECTIONS; + +inline constexpr size_t kMaxTcpPendingPackets = CHIP_CONFIG_MAX_TCP_PENDING_PACKETS; +#endif // INET_CONFIG_ENABLE_TCP_ENDPOINT + // // NOTE: Please do not alter the order of template specialization here as the logic // in the Server impl depends on this. @@ -89,6 +95,10 @@ using ServerTransportMgr = chip::TransportMgr +#endif +#if INET_CONFIG_ENABLE_TCP_ENDPOINT + , + chip::Transport::TCP #endif >; diff --git a/src/app/tests/TestCommissionManager.cpp b/src/app/tests/TestCommissionManager.cpp index 0076fd6a55718f..188f51aee6a609 100644 --- a/src/app/tests/TestCommissionManager.cpp +++ b/src/app/tests/TestCommissionManager.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -104,6 +105,9 @@ void InitializeChip(nlTestSuite * suite) static chip::SimpleTestEventTriggerDelegate sSimpleTestEventTriggerDelegate; initParams.testEventTriggerDelegate = &sSimpleTestEventTriggerDelegate; (void) initParams.InitializeStaticResourcesBeforeServerInit(); + // Set a randomized server port(slightly shifted from CHIP_PORT) for testing + initParams.operationalServicePort = static_cast(initParams.operationalServicePort + chip::Crypto::GetRandU16() % 20); + err = chip::Server::GetInstance().Init(initParams); NL_TEST_ASSERT(suite, err == CHIP_NO_ERROR); diff --git a/src/controller/CHIPDeviceControllerFactory.cpp b/src/controller/CHIPDeviceControllerFactory.cpp index 198d0c47c9f614..eb52e389a6b9d6 100644 --- a/src/controller/CHIPDeviceControllerFactory.cpp +++ b/src/controller/CHIPDeviceControllerFactory.cpp @@ -161,6 +161,12 @@ CHIP_ERROR DeviceControllerFactory::InitSystemState(FactoryInitParams params) #if CONFIG_NETWORK_LAYER_BLE , Transport::BleListenParameters(stateParams.bleLayer) +#endif +#if INET_CONFIG_ENABLE_TCP_ENDPOINT + , + Transport::TcpListenParameters(stateParams.tcpEndPointManager) + .SetAddressType(IPAddressType::kIPv6) + .SetListenPort(params.listenPort) #endif )); diff --git a/src/controller/CHIPDeviceControllerSystemState.h b/src/controller/CHIPDeviceControllerSystemState.h index 389bb557f6c0cc..1ea0593d594993 100644 --- a/src/controller/CHIPDeviceControllerSystemState.h +++ b/src/controller/CHIPDeviceControllerSystemState.h @@ -57,16 +57,27 @@ namespace chip { inline constexpr size_t kMaxDeviceTransportBlePendingPackets = 1; -using DeviceTransportMgr = TransportMgr /* BLE */ + , + Transport::BLE /* BLE */ +#endif +#if INET_CONFIG_ENABLE_TCP_ENDPOINT + , + Transport::TCP #endif - >; + >; namespace Controller { diff --git a/src/include/platform/internal/GenericPlatformManagerImpl.ipp b/src/include/platform/internal/GenericPlatformManagerImpl.ipp index d6f29ed515e034..64878f5928cd9b 100644 --- a/src/include/platform/internal/GenericPlatformManagerImpl.ipp +++ b/src/include/platform/internal/GenericPlatformManagerImpl.ipp @@ -89,6 +89,16 @@ CHIP_ERROR GenericPlatformManagerImpl::_InitChipStack() } SuccessOrExit(err); +#if INET_CONFIG_ENABLE_TCP_ENDPOINT + // Initialize the CHIP TCP layer. + err = TCPEndPointManager()->Init(SystemLayer()); + if (err != CHIP_NO_ERROR) + { + ChipLogError(DeviceLayer, "TCP initialization failed: %" CHIP_ERROR_FORMAT, err.Format()); + } + SuccessOrExit(err); +#endif + // TODO Perform dynamic configuration of the core CHIP objects based on stored settings. // Initialize the CHIP BLE manager. @@ -132,6 +142,10 @@ void GenericPlatformManagerImpl::_Shutdown() ChipLogError(DeviceLayer, "Inet Layer shutdown"); UDPEndPointManager()->Shutdown(); +#if INET_CONFIG_ENABLE_TCP_ENDPOINT + TCPEndPointManager()->Shutdown(); +#endif + #if CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE ChipLogError(DeviceLayer, "BLE shutdown"); BLEMgr().Shutdown(); diff --git a/src/messaging/ExchangeContext.cpp b/src/messaging/ExchangeContext.cpp index f36a274be1da2a..bca044d91f230d 100644 --- a/src/messaging/ExchangeContext.cpp +++ b/src/messaging/ExchangeContext.cpp @@ -670,5 +670,12 @@ void ExchangeContext::ExchangeSessionHolder::GrabExpiredSession(const SessionHan GrabUnchecked(session); } +#if INET_CONFIG_ENABLE_TCP_ENDPOINT +void ExchangeContext::OnSessionConnectionClosed(CHIP_ERROR conErr) +{ + // TODO: Handle connection closure at the ExchangeContext level. +} +#endif // INET_CONFIG_ENABLE_TCP_ENDPOINT + } // namespace Messaging } // namespace chip diff --git a/src/messaging/ExchangeContext.h b/src/messaging/ExchangeContext.h index fc20a5aace5273..47cf0ddbef2783 100644 --- a/src/messaging/ExchangeContext.h +++ b/src/messaging/ExchangeContext.h @@ -86,6 +86,9 @@ class DLL_EXPORT ExchangeContext : public ReliableMessageContext, NewSessionHandlingPolicy GetNewSessionHandlingPolicy() override { return NewSessionHandlingPolicy::kStayAtOldSession; } void OnSessionReleased() override; +#if INET_CONFIG_ENABLE_TCP_ENDPOINT + void OnSessionConnectionClosed(CHIP_ERROR conErr) override; +#endif // INET_CONFIG_ENABLE_TCP_ENDPOINT /** * Send a CHIP message on this exchange. * diff --git a/src/messaging/ExchangeMgr.cpp b/src/messaging/ExchangeMgr.cpp index 3971864bb7e06e..a184723726781e 100644 --- a/src/messaging/ExchangeMgr.cpp +++ b/src/messaging/ExchangeMgr.cpp @@ -77,6 +77,9 @@ CHIP_ERROR ExchangeManager::Init(SessionManager * sessionManager) sessionManager->SetMessageDelegate(this); +#if INET_CONFIG_ENABLE_TCP_ENDPOINT + sessionManager->SetConnectionDelegate(this); +#endif // INET_CONFIG_ENABLE_TCP_ENDPOINT mReliableMessageMgr.Init(sessionManager->SystemLayer()); mState = State::kState_Initialized; @@ -413,5 +416,18 @@ void ExchangeManager::CloseAllContextsForDelegate(const ExchangeDelegate * deleg }); } +#if INET_CONFIG_ENABLE_TCP_ENDPOINT +void ExchangeManager::OnTCPConnectionClosed(const SessionHandle & session, CHIP_ERROR conErr) +{ + mContextPool.ForEachActiveObject([&](auto * ec) { + if (ec->HasSessionHandle() && ec->GetSessionHandle() == session) + { + ec->OnSessionConnectionClosed(conErr); + } + return Loop::Continue; + }); +} +#endif // INET_CONFIG_ENABLE_TCP_ENDPOINT + } // namespace Messaging } // namespace chip diff --git a/src/messaging/ExchangeMgr.h b/src/messaging/ExchangeMgr.h index 48c6f8df673fb6..b6e416cdbf74e7 100644 --- a/src/messaging/ExchangeMgr.h +++ b/src/messaging/ExchangeMgr.h @@ -49,6 +49,10 @@ static constexpr int16_t kAnyMessageType = -1; * handling the registration/unregistration of unsolicited message handlers. */ class DLL_EXPORT ExchangeManager : public SessionMessageDelegate +#if INET_CONFIG_ENABLE_TCP_ENDPOINT + , + public SessionConnectionDelegate +#endif // INET_CONFIG_ENABLE_TCP_ENDPOINT { friend class ExchangeContext; @@ -242,6 +246,9 @@ class DLL_EXPORT ExchangeManager : public SessionMessageDelegate DuplicateMessage isDuplicate, System::PacketBufferHandle && msgBuf) override; void SendStandaloneAckIfNeeded(const PacketHeader & packetHeader, const PayloadHeader & payloadHeader, const SessionHandle & session, MessageFlags msgFlags, System::PacketBufferHandle && msgBuf); +#if INET_CONFIG_ENABLE_TCP_ENDPOINT + void OnTCPConnectionClosed(const SessionHandle & session, CHIP_ERROR conErr) override; +#endif // INET_CONFIG_ENABLE_TCP_ENDPOINT }; } // namespace Messaging diff --git a/src/messaging/tests/echo/common.cpp b/src/messaging/tests/echo/common.cpp index 80befc92d27ae6..10eeeb67738024 100644 --- a/src/messaging/tests/echo/common.cpp +++ b/src/messaging/tests/echo/common.cpp @@ -51,10 +51,6 @@ void InitializeChip() err = chip::DeviceLayer::PlatformMgr().InitChipStack(); SuccessOrExit(err); - // Initialize TCP. - err = chip::DeviceLayer::TCPEndPointManager()->Init(chip::DeviceLayer::SystemLayer()); - SuccessOrExit(err); - exit: if (err != CHIP_NO_ERROR) { @@ -68,6 +64,5 @@ void ShutdownChip() gMessageCounterManager.Shutdown(); gExchangeManager.Shutdown(); gSessionManager.Shutdown(); - (void) chip::DeviceLayer::TCPEndPointManager()->Shutdown(); chip::DeviceLayer::PlatformMgr().Shutdown(); } diff --git a/src/messaging/tests/echo/echo_requester.cpp b/src/messaging/tests/echo/echo_requester.cpp index 1bff8e70f55d8d..b06edb359b989f 100644 --- a/src/messaging/tests/echo/echo_requester.cpp +++ b/src/messaging/tests/echo/echo_requester.cpp @@ -35,7 +35,9 @@ #include #include #include +#if INET_CONFIG_ENABLE_TCP_ENDPOINT #include +#endif // INET_CONFIG_ENABLE_TCP_ENDPOINT #include #include @@ -49,6 +51,9 @@ namespace { // Max value for the number of EchoRequests sent. constexpr size_t kMaxEchoCount = 3; +// Max value for the number of tcp connect attempts. +constexpr size_t kMaxTCPConnectAttempts = 3; + // The CHIP Echo interval time. constexpr chip::System::Clock::Timeout gEchoInterval = chip::System::Clock::Seconds16(1); @@ -62,9 +67,21 @@ chip::TransportMgrAsSecureSession()->SetTCPConnection(conn); + } + + printf("Successfully established secure session with peer at %s\n", peerAddrBuf); } return err; } +void CloseConnection() +{ + char peerAddrBuf[chip::Transport::PeerAddress::kMaxToStringSize]; + chip::Transport::PeerAddress peerAddr = chip::Transport::PeerAddress::TCP(gDestAddr, CHIP_PORT); + + gSessionManager.TCPDisconnect(peerAddr); + + peerAddr.ToString(peerAddrBuf); + printf("Connection closed to peer at %s\n", peerAddrBuf); + + gClientConEstablished = false; + gClientConInProgress = false; +} + +void HandleConnectionAttemptComplete(chip::Transport::ActiveTCPConnectionState * conn, CHIP_ERROR err) +{ + chip::DeviceLayer::PlatformMgr().StopEventLoopTask(); + + if (err != CHIP_NO_ERROR) + { + printf("Connection FAILED with err: %s\n", chip::ErrorStr(err)); + + gLastEchoTime = chip::System::SystemClock().GetMonotonicTimestamp(); + CloseConnection(); + gTCPConnAttemptCount++; + return; + } + + err = EstablishSecureSession(conn); + if (err != CHIP_NO_ERROR) + { + printf("Secure session FAILED with err: %s\n", chip::ErrorStr(err)); + + gLastEchoTime = chip::System::SystemClock().GetMonotonicTimestamp(); + CloseConnection(); + return; + } + + gClientConEstablished = true; + gClientConInProgress = false; +} + +void HandleConnectionClosed(chip::Transport::ActiveTCPConnectionState * conn, CHIP_ERROR conErr) +{ + CloseConnection(); +} + +void EstablishTCPConnection() +{ + CHIP_ERROR err = CHIP_NO_ERROR; + // Previous connection attempt underway. + if (gClientConInProgress) + { + return; + } + + gClientConEstablished = false; + + chip::Transport::PeerAddress peerAddr = chip::Transport::PeerAddress::TCP(gDestAddr, CHIP_PORT); + + // Connect to the peer + err = gSessionManager.TCPConnect(peerAddr, &gAppTCPConnCbCtxt, &gActiveTCPConnState); + if (err != CHIP_NO_ERROR) + { + printf("Connection FAILED with err: %s\n", chip::ErrorStr(err)); + + gLastEchoTime = chip::System::SystemClock().GetMonotonicTimestamp(); + CloseConnection(); + gTCPConnAttemptCount++; + return; + } + + gClientConInProgress = true; +} + void HandleEchoResponseReceived(chip::Messaging::ExchangeContext * ec, chip::System::PacketBufferHandle && payload) { chip::System::Clock::Timestamp respTime = chip::System::SystemClock().GetMonotonicTimestamp(); @@ -236,6 +342,10 @@ int main(int argc, char * argv[]) err = gSessionManager.Init(&chip::DeviceLayer::SystemLayer(), &gTCPManager, &gMessageCounterManager, &gStorage, &gFabricTable, gSessionKeystore); SuccessOrExit(err); + + gAppTCPConnCbCtxt.appContext = nullptr; + gAppTCPConnCbCtxt.connCompleteCb = HandleConnectionAttemptComplete; + gAppTCPConnCbCtxt.connClosedCb = HandleConnectionClosed; } else { @@ -255,9 +365,29 @@ int main(int argc, char * argv[]) err = gMessageCounterManager.Init(&gExchangeManager); SuccessOrExit(err); - // Start the CHIP connection to the CHIP echo responder. - err = EstablishSecureSession(); - SuccessOrExit(err); + if (gUseTCP) + { + + while (!gClientConEstablished) + { + // For TCP transport, attempt to establish the connection to the CHIP echo responder. + // On Connection completion, call EstablishSecureSession(conn); + EstablishTCPConnection(); + + chip::DeviceLayer::PlatformMgr().RunEventLoop(); + + if (gTCPConnAttemptCount > kMaxTCPConnectAttempts) + { + ExitNow(); + } + } + } + else + { + // Start the CHIP session to the CHIP echo responder. + err = EstablishSecureSession(nullptr); + SuccessOrExit(err); + } err = gEchoClient.Init(&gExchangeManager, gSession.Get().Value()); SuccessOrExit(err); @@ -274,14 +404,14 @@ int main(int argc, char * argv[]) if (gUseTCP) { - gTCPManager.Disconnect(chip::Transport::PeerAddress::TCP(gDestAddr)); + gTCPManager.TCPDisconnect(chip::Transport::PeerAddress::TCP(gDestAddr)); } gTCPManager.Close(); Shutdown(); exit: - if ((err != CHIP_NO_ERROR) || (gEchoRespCount != kMaxEchoCount)) + if ((err != CHIP_NO_ERROR) || (gEchoRespCount != kMaxEchoCount) || (gTCPConnAttemptCount > kMaxTCPConnectAttempts)) { printf("ChipEchoClient failed: %s\n", chip::ErrorStr(err)); exit(EXIT_FAILURE); diff --git a/src/messaging/tests/echo/echo_responder.cpp b/src/messaging/tests/echo/echo_responder.cpp index 140aab00b0ff23..0cd2366a1f6c2b 100644 --- a/src/messaging/tests/echo/echo_responder.cpp +++ b/src/messaging/tests/echo/echo_responder.cpp @@ -35,7 +35,9 @@ #include #include #include +#if INET_CONFIG_ENABLE_TCP_ENDPOINT #include +#endif // INET_CONFIG_ENABLE_TCP_ENDPOINT #include namespace { diff --git a/src/protocols/secure_channel/CASESession.cpp b/src/protocols/secure_channel/CASESession.cpp index 745bd3898fa865..ccc2bc2188d176 100644 --- a/src/protocols/secure_channel/CASESession.cpp +++ b/src/protocols/secure_channel/CASESession.cpp @@ -419,6 +419,21 @@ void CASESession::Clear() mPeerNodeId = kUndefinedNodeId; mFabricsTable = nullptr; mFabricIndex = kUndefinedFabricIndex; +#if INET_CONFIG_ENABLE_TCP_ENDPOINT + // Clear the context object. + mTCPConnCbCtxt.appContext = nullptr; + mTCPConnCbCtxt.connCompleteCb = nullptr; + mTCPConnCbCtxt.connClosedCb = nullptr; + mTCPConnCbCtxt.connReceivedCb = nullptr; + + if (mPeerConnState && mPeerConnState->mConnectionState != Transport::TCPState::kConnected) + { + // Abort the connection if the CASESession is being destroyed and the + // connection is in the middle of being set up. + mSessionManager->TCPDisconnect(mPeerConnState, /* shouldAbort = */ true); + mPeerConnState = nullptr; + } +#endif // INET_CONFIG_ENABLE_TCP_ENDPOINT } void CASESession::InvalidateIfPendingEstablishmentOnFabric(FabricIndex fabricIndex) @@ -446,7 +461,9 @@ CHIP_ERROR CASESession::Init(SessionManager & sessionManager, Credentials::Certi ReturnErrorOnFailure(mCommissioningHash.Begin()); - mDelegate = delegate; + mDelegate = delegate; + mSessionManager = &sessionManager; + ReturnErrorOnFailure(AllocateSecureSession(sessionManager, sessionEvictionHint)); mValidContext.Reset(); @@ -454,6 +471,11 @@ CHIP_ERROR CASESession::Init(SessionManager & sessionManager, Credentials::Certi mValidContext.mRequiredKeyPurposes.Set(KeyPurposeFlags::kServerAuth); mValidContext.mValidityPolicy = policy; +#if INET_CONFIG_ENABLE_TCP_ENDPOINT + mTCPConnCbCtxt.appContext = this; + mTCPConnCbCtxt.connCompleteCb = HandleConnectionAttemptComplete; + mTCPConnCbCtxt.connClosedCb = HandleConnectionClosed; +#endif // INET_CONFIG_ENABLE_TCP_ENDPOINT return CHIP_NO_ERROR; } @@ -516,12 +538,18 @@ CHIP_ERROR CASESession::EstablishSession(SessionManager & sessionManager, Fabric // This is to make sure the exchange will get closed if Init() returned an error. mExchangeCtxt.Emplace(*exchangeCtxt); + Transport::PeerAddress peerAddress = mExchangeCtxt.Value()->GetSessionHandle()->AsUnauthenticatedSession()->GetPeerAddress(); + // From here onwards, let's go to exit on error, as some state might have already // been initialized SuccessOrExit(err); SuccessOrExit(err = fabricTable->AddFabricDelegate(this)); + // Set the PeerAddress in the secure session up front to indicate the + // Transport Type of the session that is being set up. + mSecureSessionHolder->AsSecureSession()->SetPeerAddress(peerAddress); + mFabricsTable = fabricTable; mFabricIndex = fabricInfo->GetFabricIndex(); mSessionResumptionStorage = sessionResumptionStorage; @@ -534,8 +562,18 @@ CHIP_ERROR CASESession::EstablishSession(SessionManager & sessionManager, Fabric ChipLogProgress(SecureChannel, "Initiating session on local FabricIndex %u from 0x" ChipLogFormatX64 " -> 0x" ChipLogFormatX64, static_cast(mFabricIndex), ChipLogValueX64(mLocalNodeId), ChipLogValueX64(mPeerNodeId)); - err = SendSigma1(); - SuccessOrExit(err); + if (peerAddress.GetTransportType() == Transport::Type::kTcp) + { +#if INET_CONFIG_ENABLE_TCP_ENDPOINT + err = sessionManager.TCPConnect(peerAddress, &mTCPConnCbCtxt, &mPeerConnState); + SuccessOrExit(err); +#endif // INET_CONFIG_ENABLE_TCP_ENDPOINT + } + else + { + err = SendSigma1(); + SuccessOrExit(err); + } exit: if (err != CHIP_NO_ERROR) @@ -648,6 +686,78 @@ CHIP_ERROR CASESession::RecoverInitiatorIpk() return CHIP_NO_ERROR; } +#if INET_CONFIG_ENABLE_TCP_ENDPOINT +void CASESession::HandleConnectionAttemptComplete(Transport::ActiveTCPConnectionState * conn, CHIP_ERROR err) +{ + VerifyOrReturn(conn != nullptr); + // conn->mAppState should not be NULL. SessionManager has already checked + // before calling this callback. + VerifyOrDie(conn->mAppState != nullptr); + + char peerAddrBuf[chip::Transport::PeerAddress::kMaxToStringSize]; + conn->mPeerAddr.ToString(peerAddrBuf); + + CASESession * caseSession = reinterpret_cast(conn->mAppState->appContext); + VerifyOrReturn(caseSession != nullptr); + + // Exit and disconnect if connection setup encountered an error. + SuccessOrExit(err); + + ChipLogDetail(SecureChannel, "TCP Connection established with %s before session establishment", peerAddrBuf); + + // Associate the connection with the current unauthenticated session for the + // CASE exchange. + caseSession->mExchangeCtxt.Value()->GetSessionHandle()->AsUnauthenticatedSession()->SetTCPConnection(conn); + + // Associate the connection with the current secure session that is being + // set up. + caseSession->mSecureSessionHolder.Get().Value()->AsSecureSession()->SetTCPConnection(conn); + + // Send Sigma1 after connection is established for sessions over TCP + err = caseSession->SendSigma1(); + SuccessOrExit(err); + +exit: + if (err != CHIP_NO_ERROR) + { + ChipLogError(SecureChannel, "Connection establishment failed with peer at %s: %" CHIP_ERROR_FORMAT, peerAddrBuf, + err.Format()); + + // Close the underlying connection and ensure that the CASESession is + // not holding on to a stale ActiveTCPConnectionState. We call + // TCPDisconnect() here explicitly in order to abort the connection + // even after it establishes successfully, but SendSigma1() fails for + // some reason. + caseSession->mSessionManager->TCPDisconnect(conn, /* shouldAbort = */ true); + caseSession->mPeerConnState = nullptr; + + caseSession->Clear(); + } +} + +void CASESession::HandleConnectionClosed(Transport::ActiveTCPConnectionState * conn, CHIP_ERROR conErr) +{ + VerifyOrReturn(conn != nullptr); + // conn->mAppState should not be NULL. SessionManager has already checked + // before calling this callback. + VerifyOrDie(conn->mAppState != nullptr); + + CASESession * caseSession = reinterpret_cast(conn->mAppState->appContext); + VerifyOrReturn(caseSession != nullptr); + + // Drop our pointer to the now-invalid connection state. + // + // Since the connection is closed, message sends over the ExchangeContext + // will just fail and be handled like normal send errors. + // + // Additionally, SessionManager notifies (via ExchangeMgr) all ExchangeContexts on the + // connection closures for the attached sessions and the ExchangeContexts + // can close proactively if that's appropriate. + caseSession->mPeerConnState = nullptr; + ChipLogDetail(SecureChannel, "TCP Connection for this session has closed"); +} +#endif // INET_CONFIG_ENABLE_TCP_ENDPOINT + CHIP_ERROR CASESession::SendSigma1() { MATTER_TRACE_SCOPE("SendSigma1", "CASESession"); @@ -2143,10 +2253,16 @@ CHIP_ERROR CASESession::OnMessageReceived(ExchangeContext * ec, const PayloadHea #endif // CONFIG_BUILD_FOR_HOST_UNIT_TEST #if CHIP_CONFIG_SLOW_CRYPTO - if (msgType == Protocols::SecureChannel::MsgType::CASE_Sigma1 || msgType == Protocols::SecureChannel::MsgType::CASE_Sigma2 || - msgType == Protocols::SecureChannel::MsgType::CASE_Sigma2Resume || - msgType == Protocols::SecureChannel::MsgType::CASE_Sigma3) - { + if ((msgType == Protocols::SecureChannel::MsgType::CASE_Sigma1 || msgType == Protocols::SecureChannel::MsgType::CASE_Sigma2 || + msgType == Protocols::SecureChannel::MsgType::CASE_Sigma2Resume || + msgType == Protocols::SecureChannel::MsgType::CASE_Sigma3) && + mExchangeCtxt.Value()->GetSessionHandle()->AsUnauthenticatedSession()->GetPeerAddress().GetTransportType() != + Transport::Type::kTcp) + { + // TODO: Rename FlushAcks() to something more semantically correct and + // call unconditionally for TCP or MRP from here. Inside, the + // PeerAddress type could be consulted to selectively flush MRP Acks + // when transport is not TCP. Issue #33183 SuccessOrExit(err = mExchangeCtxt.Value()->FlushAcks()); } #endif // CHIP_CONFIG_SLOW_CRYPTO diff --git a/src/protocols/secure_channel/CASESession.h b/src/protocols/secure_channel/CASESession.h index b7c6b429b950ad..045d1982dd723c 100644 --- a/src/protocols/secure_channel/CASESession.h +++ b/src/protocols/secure_channel/CASESession.h @@ -286,6 +286,22 @@ class DLL_EXPORT CASESession : public Messaging::UnsolicitedMessageHandler, void InvalidateIfPendingEstablishmentOnFabric(FabricIndex fabricIndex); +#if INET_CONFIG_ENABLE_TCP_ENDPOINT + static void HandleConnectionAttemptComplete(Transport::ActiveTCPConnectionState * conn, CHIP_ERROR conErr); + static void HandleConnectionClosed(Transport::ActiveTCPConnectionState * conn, CHIP_ERROR conErr); + + // Context to pass down when connecting to peer + Transport::AppTCPConnectionCallbackCtxt mTCPConnCbCtxt; + // Pointer to the underlying TCP connection state. Returned by the + // TCPConnect() method (on the connection Initiator side) when an + // ActiveTCPConnectionState object is allocated. This connection + // context is used on the CASE Initiator side to facilitate the + // invocation of the callbacks when the connection is established/closed. + // + // This pointer must be nulled out when the connection is closed. + Transport::ActiveTCPConnectionState * mPeerConnState = nullptr; +#endif // INET_CONFIG_ENABLE_TCP_ENDPOINT + #if CONFIG_BUILD_FOR_HOST_UNIT_TEST void SetStopSigmaHandshakeAt(Optional state) { mStopHandshakeAtState = state; } #endif // CONFIG_BUILD_FOR_HOST_UNIT_TEST @@ -301,6 +317,7 @@ class DLL_EXPORT CASESession : public Messaging::UnsolicitedMessageHandler, uint8_t mIPK[kIPKSize]; SessionResumptionStorage * mSessionResumptionStorage = nullptr; + SessionManager * mSessionManager = nullptr; FabricTable * mFabricsTable = nullptr; FabricIndex mFabricIndex = kUndefinedFabricIndex; diff --git a/src/protocols/secure_channel/PairingSession.cpp b/src/protocols/secure_channel/PairingSession.cpp index 1f7874bdf115dc..ae4ca272858a78 100644 --- a/src/protocols/secure_channel/PairingSession.cpp +++ b/src/protocols/secure_channel/PairingSession.cpp @@ -22,6 +22,7 @@ #include #include #include +#include namespace chip { @@ -58,6 +59,18 @@ void PairingSession::Finish() { Transport::PeerAddress address = mExchangeCtxt.Value()->GetSessionHandle()->AsUnauthenticatedSession()->GetPeerAddress(); +#if INET_CONFIG_ENABLE_TCP_ENDPOINT + if (address.GetTransportType() == Transport::Type::kTcp) + { + // Fetch the connection for the unauthenticated session used to set up + // the secure session. + Transport::ActiveTCPConnectionState * conn = + mExchangeCtxt.Value()->GetSessionHandle()->AsUnauthenticatedSession()->GetTCPConnection(); + + // Associate the connection with the secure session being activated. + mSecureSessionHolder->AsSecureSession()->SetTCPConnection(conn); + } +#endif // INET_CONFIG_ENABLE_TCP_ENDPOINT // Discard the exchange so that Clear() doesn't try closing it. The exchange will handle that. DiscardExchange(); diff --git a/src/protocols/user_directed_commissioning/UserDirectedCommissioning.h b/src/protocols/user_directed_commissioning/UserDirectedCommissioning.h index 86fd4d51ed4e48..7a496e5a2f0a33 100644 --- a/src/protocols/user_directed_commissioning/UserDirectedCommissioning.h +++ b/src/protocols/user_directed_commissioning/UserDirectedCommissioning.h @@ -539,7 +539,8 @@ class DLL_EXPORT UserDirectedCommissioningClient : public TransportMgrDelegate } private: - void OnMessageReceived(const Transport::PeerAddress & source, System::PacketBufferHandle && msgBuf) override; + void OnMessageReceived(const Transport::PeerAddress & source, System::PacketBufferHandle && msgBuf, + Transport::MessageTransportContext * ctxt = nullptr) override; CommissionerDeclarationHandler * mCommissionerDeclarationHandler = nullptr; }; @@ -652,7 +653,8 @@ class DLL_EXPORT UserDirectedCommissioningServer : public TransportMgrDelegate void HandleNewUDC(const Transport::PeerAddress & source, IdentificationDeclaration & id); void HandleUDCCancel(IdentificationDeclaration & id); void HandleUDCCommissionerPasscodeReady(IdentificationDeclaration & id); - void OnMessageReceived(const Transport::PeerAddress & source, System::PacketBufferHandle && msgBuf) override; + void OnMessageReceived(const Transport::PeerAddress & source, System::PacketBufferHandle && msgBuf, + Transport::MessageTransportContext * ctxt = nullptr) override; UDCClients mUdcClients; // < Active UDC clients diff --git a/src/protocols/user_directed_commissioning/UserDirectedCommissioningClient.cpp b/src/protocols/user_directed_commissioning/UserDirectedCommissioningClient.cpp index 9fc43634d7ec7d..6d7c315ffb5308 100644 --- a/src/protocols/user_directed_commissioning/UserDirectedCommissioningClient.cpp +++ b/src/protocols/user_directed_commissioning/UserDirectedCommissioningClient.cpp @@ -24,6 +24,7 @@ */ #include "UserDirectedCommissioning.h" +#include #ifdef __ZEPHYR__ #include @@ -235,7 +236,8 @@ CHIP_ERROR CommissionerDeclaration::ReadPayload(uint8_t * udcPayload, size_t pay return CHIP_NO_ERROR; } -void UserDirectedCommissioningClient::OnMessageReceived(const Transport::PeerAddress & source, System::PacketBufferHandle && msg) +void UserDirectedCommissioningClient::OnMessageReceived(const Transport::PeerAddress & source, System::PacketBufferHandle && msg, + Transport::MessageTransportContext * ctxt) { char addrBuffer[chip::Transport::PeerAddress::kMaxToStringSize]; source.ToString(addrBuffer); diff --git a/src/protocols/user_directed_commissioning/UserDirectedCommissioningServer.cpp b/src/protocols/user_directed_commissioning/UserDirectedCommissioningServer.cpp index 2efd8d0a33de28..a06bffcec62b3a 100644 --- a/src/protocols/user_directed_commissioning/UserDirectedCommissioningServer.cpp +++ b/src/protocols/user_directed_commissioning/UserDirectedCommissioningServer.cpp @@ -26,6 +26,7 @@ #include "UserDirectedCommissioning.h" #include #include +#include #include @@ -33,7 +34,8 @@ namespace chip { namespace Protocols { namespace UserDirectedCommissioning { -void UserDirectedCommissioningServer::OnMessageReceived(const Transport::PeerAddress & source, System::PacketBufferHandle && msg) +void UserDirectedCommissioningServer::OnMessageReceived(const Transport::PeerAddress & source, System::PacketBufferHandle && msg, + Transport::MessageTransportContext * ctxt) { char addrBuffer[chip::Transport::PeerAddress::kMaxToStringSize]; source.ToString(addrBuffer); diff --git a/src/transport/BUILD.gn b/src/transport/BUILD.gn index fa556d40afd5b0..c4649c9b92d27c 100644 --- a/src/transport/BUILD.gn +++ b/src/transport/BUILD.gn @@ -37,6 +37,7 @@ static_library("transport") { "SecureSessionTable.h", "Session.cpp", "Session.h", + "SessionConnectionDelegate.h", "SessionDelegate.h", "SessionHolder.cpp", "SessionHolder.h", diff --git a/src/transport/Session.h b/src/transport/Session.h index 0b6048d5c077c0..d9840ec3ee33f1 100644 --- a/src/transport/Session.h +++ b/src/transport/Session.h @@ -28,6 +28,9 @@ #include #include #include +#if INET_CONFIG_ENABLE_TCP_ENDPOINT +#include +#endif // INET_CONFIG_ENABLE_TCP_ENDPOINT namespace chip { namespace Transport { @@ -225,6 +228,15 @@ class Session bool IsUnauthenticatedSession() const { return GetSessionType() == SessionType::kUnauthenticated; } +#if INET_CONFIG_ENABLE_TCP_ENDPOINT + // This API is used to associate the connection with the session when the + // latter is about to be marked active. It is also used to reset the + // connection to a nullptr when the connection is lost and the session + // is marked as Defunct. + ActiveTCPConnectionState * GetTCPConnection() const { return mTCPConnection; } + void SetTCPConnection(ActiveTCPConnectionState * conn) { mTCPConnection = conn; } +#endif // INET_CONFIG_ENABLE_TCP_ENDPOINT + void DispatchSessionEvent(SessionDelegate::Event event) { // Holders might remove themselves when notified. @@ -264,6 +276,15 @@ class Session private: FabricIndex mFabricIndex = kUndefinedFabricIndex; +#if INET_CONFIG_ENABLE_TCP_ENDPOINT + // The underlying TCP connection object over which the session is + // established. + // The lifetime of this member connection pointer is, essentially, the same + // as that of the underlying connection with the peer. + // It would remain as a nullptr for all sessions that are not set up over + // a TCP connection. + ActiveTCPConnectionState * mTCPConnection = nullptr; +#endif // INET_CONFIG_ENABLE_TCP_ENDPOINT }; // diff --git a/src/transport/SessionConnectionDelegate.h b/src/transport/SessionConnectionDelegate.h new file mode 100644 index 00000000000000..4557d0ae107e68 --- /dev/null +++ b/src/transport/SessionConnectionDelegate.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2023 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +namespace chip { + +/** + * @brief + * This class defines a delegate that will be called by the SessionManager on + * specific connection-related (e.g. for TCP) events. If the user of SessionManager + * is interested in receiving these callbacks, they can specialize this class and + * handle each trigger in their implementation of this class. + */ +class DLL_EXPORT SessionConnectionDelegate +{ +public: + virtual ~SessionConnectionDelegate() {} + + /** + * @brief + * Called when the underlying connection for the session is closed. + * + * @param session The handle to the secure session + * @param conErr The connection error code + */ + virtual void OnTCPConnectionClosed(const SessionHandle & session, CHIP_ERROR conErr) = 0; +}; + +} // namespace chip diff --git a/src/transport/SessionDelegate.h b/src/transport/SessionDelegate.h index b9e0a7b8b38b0c..503aaa2b0c4f5c 100644 --- a/src/transport/SessionDelegate.h +++ b/src/transport/SessionDelegate.h @@ -66,6 +66,10 @@ class DLL_EXPORT SessionDelegate * SessionManager to allocate a new session. If they desire to do so, it MUST be done asynchronously. */ virtual void OnSessionHang() {} + +#if INET_CONFIG_ENABLE_TCP_ENDPOINT + virtual void OnSessionConnectionClosed(CHIP_ERROR conErr) {} +#endif // INET_CONFIG_ENABLE_TCP_ENDPOINT }; } // namespace chip diff --git a/src/transport/SessionManager.cpp b/src/transport/SessionManager.cpp index 5adfde18b47ff4..d49e66fb6f5116 100644 --- a/src/transport/SessionManager.cpp +++ b/src/transport/SessionManager.cpp @@ -147,6 +147,11 @@ CHIP_ERROR SessionManager::Init(System::Layer * systemLayer, TransportMgrBase * mTransportMgr->SetSessionManager(this); +#if INET_CONFIG_ENABLE_TCP_ENDPOINT + mConnCompleteCb = nullptr; + mConnClosedCb = nullptr; +#endif // INET_CONFIG_ENABLE_TCP_ENDPOINT + return CHIP_NO_ERROR; } @@ -602,7 +607,8 @@ CHIP_ERROR SessionManager::InjectCaseSessionWithTestKey(SessionHolder & sessionH return CHIP_NO_ERROR; } -void SessionManager::OnMessageReceived(const PeerAddress & peerAddress, System::PacketBufferHandle && msg) +void SessionManager::OnMessageReceived(const PeerAddress & peerAddress, System::PacketBufferHandle && msg, + Transport::MessageTransportContext * ctxt) { PacketHeader partialPacketHeader; @@ -621,20 +627,151 @@ void SessionManager::OnMessageReceived(const PeerAddress & peerAddress, System:: } else { - SecureUnicastMessageDispatch(partialPacketHeader, peerAddress, std::move(msg)); + SecureUnicastMessageDispatch(partialPacketHeader, peerAddress, std::move(msg), ctxt); } } else { - UnauthenticatedMessageDispatch(partialPacketHeader, peerAddress, std::move(msg)); + UnauthenticatedMessageDispatch(partialPacketHeader, peerAddress, std::move(msg), ctxt); + } +} + +#if INET_CONFIG_ENABLE_TCP_ENDPOINT +void SessionManager::HandleConnectionReceived(Transport::ActiveTCPConnectionState * conn) +{ + char peerAddrBuf[chip::Transport::PeerAddress::kMaxToStringSize]; + + VerifyOrReturn(conn != nullptr); + conn->mPeerAddr.ToString(peerAddrBuf); + ChipLogProgress(Inet, "Received TCP connection request from %s.", peerAddrBuf); + + Transport::AppTCPConnectionCallbackCtxt * appTCPConnCbCtxt = conn->mAppState; + if (appTCPConnCbCtxt != nullptr && appTCPConnCbCtxt->connReceivedCb != nullptr) + { + appTCPConnCbCtxt->connReceivedCb(conn); + } +} + +void SessionManager::HandleConnectionAttemptComplete(Transport::ActiveTCPConnectionState * conn, CHIP_ERROR conErr) +{ + VerifyOrReturn(conn != nullptr); + + Transport::AppTCPConnectionCallbackCtxt * appTCPConnCbCtxt = conn->mAppState; + if (appTCPConnCbCtxt == nullptr) + { + TCPDisconnect(conn, /* shouldAbort = */ true); + return; + } + + if (appTCPConnCbCtxt->connCompleteCb != nullptr) + { + appTCPConnCbCtxt->connCompleteCb(conn, conErr); + } + else + { + char peerAddrBuf[chip::Transport::PeerAddress::kMaxToStringSize]; + conn->mPeerAddr.ToString(peerAddrBuf); + + ChipLogProgress(Inet, "TCP Connection established with peer %s, but no registered handler. Disconnecting.", peerAddrBuf); + + // Close the connection + TCPDisconnect(conn, /* shouldAbort = */ true); + } +} + +void SessionManager::HandleConnectionClosed(Transport::ActiveTCPConnectionState * conn, CHIP_ERROR conErr) +{ + VerifyOrReturn(conn != nullptr); + + // Mark the corresponding secure sessions as defunct + mSecureSessions.ForEachSession([&](auto session) { + if (session->IsActiveSession() && session->GetTCPConnection() == conn) + { + SessionHandle handle(*session); + // Notify the SessionConnection delegate of the connection + // closure. + if (mConnDelegate != nullptr) + { + mConnDelegate->OnTCPConnectionClosed(handle, conErr); + } + + // Dis-associate the connection from session by setting it to a + // nullptr. + session->SetTCPConnection(nullptr); + // Mark session as defunct + session->MarkAsDefunct(); + } + + return Loop::Continue; + }); + + // TODO: A mechanism to mark an unauthenticated session as unusable when + // the underlying connection is broken. Issue #32323 + + Transport::AppTCPConnectionCallbackCtxt * appTCPConnCbCtxt = conn->mAppState; + VerifyOrReturn(appTCPConnCbCtxt != nullptr); + + if (appTCPConnCbCtxt->connClosedCb != nullptr) + { + appTCPConnCbCtxt->connClosedCb(conn, conErr); + } +} + +CHIP_ERROR SessionManager::TCPConnect(const PeerAddress & peerAddress, Transport::AppTCPConnectionCallbackCtxt * appState, + Transport::ActiveTCPConnectionState ** peerConnState) +{ + char peerAddrBuf[chip::Transport::PeerAddress::kMaxToStringSize]; + peerAddress.ToString(peerAddrBuf); + if (mTransportMgr != nullptr) + { + ChipLogProgress(Inet, "Connecting over TCP with peer at %s.", peerAddrBuf); + return mTransportMgr->TCPConnect(peerAddress, appState, peerConnState); + } + + ChipLogError(Inet, "The transport manager is not initialized. Unable to connect to peer at %s.", peerAddrBuf); + + return CHIP_ERROR_INCORRECT_STATE; +} + +CHIP_ERROR SessionManager::TCPDisconnect(const PeerAddress & peerAddress) +{ + if (mTransportMgr != nullptr) + { + char peerAddrBuf[chip::Transport::PeerAddress::kMaxToStringSize]; + peerAddress.ToString(peerAddrBuf); + ChipLogProgress(Inet, "Disconnecting TCP connection from peer at %s.", peerAddrBuf); + mTransportMgr->TCPDisconnect(peerAddress); } + + return CHIP_NO_ERROR; } +void SessionManager::TCPDisconnect(Transport::ActiveTCPConnectionState * conn, bool shouldAbort) +{ + if (mTransportMgr != nullptr && conn != nullptr) + { + char peerAddrBuf[chip::Transport::PeerAddress::kMaxToStringSize]; + conn->mPeerAddr.ToString(peerAddrBuf); + ChipLogProgress(Inet, "Disconnecting TCP connection from peer at %s.", peerAddrBuf); + mTransportMgr->TCPDisconnect(conn, shouldAbort); + } +} +#endif // INET_CONFIG_ENABLE_TCP_ENDPOINT + void SessionManager::UnauthenticatedMessageDispatch(const PacketHeader & partialPacketHeader, - const Transport::PeerAddress & peerAddress, System::PacketBufferHandle && msg) + const Transport::PeerAddress & peerAddress, System::PacketBufferHandle && msg, + Transport::MessageTransportContext * ctxt) { MATTER_TRACE_SCOPE("Unauthenticated Message Dispatch", "SessionManager"); +#if INET_CONFIG_ENABLE_TCP_ENDPOINT + if (peerAddress.GetTransportType() == Transport::Type::kTcp && ctxt->conn == nullptr) + { + ChipLogError(Inet, "Connection object is missing for received message."); + return; + } +#endif // INET_CONFIG_ENABLE_TCP_ENDPOINT + // Drop unsecured messages with privacy enabled. if (partialPacketHeader.HasPrivacyFlag()) { @@ -660,7 +797,7 @@ void SessionManager::UnauthenticatedMessageDispatch(const PacketHeader & partial if (source.HasValue()) { // Assume peer is the initiator, we are the responder. - optionalSession = mUnauthenticatedSessions.FindOrAllocateResponder(source.Value(), GetDefaultMRPConfig()); + optionalSession = mUnauthenticatedSessions.FindOrAllocateResponder(source.Value(), GetDefaultMRPConfig(), peerAddress); if (!optionalSession.HasValue()) { ChipLogError(Inet, "UnauthenticatedSession exhausted"); @@ -670,7 +807,7 @@ void SessionManager::UnauthenticatedMessageDispatch(const PacketHeader & partial else { // Assume peer is the responder, we are the initiator. - optionalSession = mUnauthenticatedSessions.FindInitiator(destination.Value()); + optionalSession = mUnauthenticatedSessions.FindInitiator(destination.Value(), peerAddress); if (!optionalSession.HasValue()) { ChipLogProgress(Inet, "Received unknown unsecure packet for initiator 0x" ChipLogFormatX64, @@ -685,6 +822,25 @@ void SessionManager::UnauthenticatedMessageDispatch(const PacketHeader & partial CorrectPeerAddressInterfaceID(mutablePeerAddress); unsecuredSession->SetPeerAddress(mutablePeerAddress); SessionMessageDelegate::DuplicateMessage isDuplicate = SessionMessageDelegate::DuplicateMessage::No; +#if INET_CONFIG_ENABLE_TCP_ENDPOINT + // Associate the unauthenticated session with the connection, if not done already. + if (peerAddress.GetTransportType() == Transport::Type::kTcp) + { + Transport::ActiveTCPConnectionState * sessionConn = unsecuredSession->GetTCPConnection(); + if (sessionConn == nullptr) + { + unsecuredSession->SetTCPConnection(ctxt->conn); + } + else + { + if (sessionConn != ctxt->conn) + { + ChipLogError(Inet, "Data received over wrong connection %p. Dropping it!", ctxt->conn); + return; + } + } + } +#endif // INET_CONFIG_ENABLE_TCP_ENDPOINT unsecuredSession->MarkActiveRx(); @@ -723,13 +879,55 @@ void SessionManager::UnauthenticatedMessageDispatch(const PacketHeader & partial } void SessionManager::SecureUnicastMessageDispatch(const PacketHeader & partialPacketHeader, - const Transport::PeerAddress & peerAddress, System::PacketBufferHandle && msg) + const Transport::PeerAddress & peerAddress, System::PacketBufferHandle && msg, + Transport::MessageTransportContext * ctxt) { MATTER_TRACE_SCOPE("Secure Unicast Message Dispatch", "SessionManager"); CHIP_ERROR err = CHIP_NO_ERROR; +#if INET_CONFIG_ENABLE_TCP_ENDPOINT + if (peerAddress.GetTransportType() == Transport::Type::kTcp && ctxt->conn == nullptr) + { + ChipLogError(Inet, "Connection object is missing for received message."); + return; + } +#endif // INET_CONFIG_ENABLE_TCP_ENDPOINT + Optional session = mSecureSessions.FindSecureSessionByLocalKey(partialPacketHeader.GetSessionId()); + if (!session.HasValue()) + { + ChipLogError(Inet, "Data received on an unknown session (LSID=%d). Dropping it!", partialPacketHeader.GetSessionId()); + return; + } + + Transport::SecureSession * secureSession = session.Value()->AsSecureSession(); + Transport::PeerAddress mutablePeerAddress = peerAddress; + CorrectPeerAddressInterfaceID(mutablePeerAddress); + if (secureSession->GetPeerAddress() != mutablePeerAddress) + { + secureSession->SetPeerAddress(mutablePeerAddress); + } + +#if INET_CONFIG_ENABLE_TCP_ENDPOINT + // Associate the secure session with the connection, if not done already. + if (peerAddress.GetTransportType() == Transport::Type::kTcp) + { + Transport::ActiveTCPConnectionState * sessionConn = secureSession->GetTCPConnection(); + if (sessionConn == nullptr) + { + secureSession->SetTCPConnection(ctxt->conn); + } + else + { + if (sessionConn != ctxt->conn) + { + ChipLogError(Inet, "Data received over wrong connection %p. Dropping it!", ctxt->conn); + return; + } + } + } +#endif // INET_CONFIG_ENABLE_TCP_ENDPOINT PayloadHeader payloadHeader; @@ -751,14 +949,6 @@ void SessionManager::SecureUnicastMessageDispatch(const PacketHeader & partialPa return; } - if (!session.HasValue()) - { - ChipLogError(Inet, "Data received on an unknown session (LSID=%d). Dropping it!", packetHeader.GetSessionId()); - return; - } - - Transport::SecureSession * secureSession = session.Value()->AsSecureSession(); - // We need to allow through messages even on sessions that are pending // evictions, because for some cases (UpdateNOC, RemoveFabric, etc) there // can be a single exchange alive on the session waiting for a MRP ack, and @@ -816,13 +1006,6 @@ void SessionManager::SecureUnicastMessageDispatch(const PacketHeader & partialPa secureSession->GetSessionMessageCounter().GetPeerMessageCounter().CommitEncryptedUnicast(packetHeader.GetMessageCounter()); } - Transport::PeerAddress mutablePeerAddress = peerAddress; - CorrectPeerAddressInterfaceID(mutablePeerAddress); - if (secureSession->GetPeerAddress() != mutablePeerAddress) - { - secureSession->SetPeerAddress(mutablePeerAddress); - } - if (mCB != nullptr) { MATTER_LOG_MESSAGE_RECEIVED(chip::Tracing::IncomingMessageType::kSecureUnicast, &payloadHeader, &packetHeader, @@ -1057,27 +1240,69 @@ void SessionManager::SecureGroupMessageDispatch(const PacketHeader & partialPack } Optional SessionManager::FindSecureSessionForNode(ScopedNodeId peerNodeId, - const Optional & type) + const Optional & type, + TransportPayloadCapability transportPayloadCapability) { - SecureSession * found = nullptr; - - mSecureSessions.ForEachSession([&peerNodeId, &type, &found](auto session) { + SecureSession * mrpSession = nullptr; +#if INET_CONFIG_ENABLE_TCP_ENDPOINT + SecureSession * tcpSession = nullptr; +#endif // INET_CONFIG_ENABLE_TCP_ENDPOINT + + mSecureSessions.ForEachSession([&peerNodeId, &type, &mrpSession, +#if INET_CONFIG_ENABLE_TCP_ENDPOINT + &tcpSession, +#endif // INET_CONFIG_ENABLE_TCP_ENDPOINT + &transportPayloadCapability](auto session) { if (session->IsActiveSession() && session->GetPeer() == peerNodeId && (!type.HasValue() || type.Value() == session->GetSecureSessionType())) { - // - // Select the active session with the most recent activity to return back to the caller. - // - if ((found == nullptr) || (found->GetLastActivityTime() < session->GetLastActivityTime())) +#if INET_CONFIG_ENABLE_TCP_ENDPOINT + if ((transportPayloadCapability == TransportPayloadCapability::kMRPOrTCPCompatiblePayload || + transportPayloadCapability == TransportPayloadCapability::kLargePayload) && + session->GetTCPConnection() != nullptr) { - found = session; + // Set up a TCP transport based session as standby + if ((tcpSession == nullptr) || (tcpSession->GetLastActivityTime() < session->GetLastActivityTime())) + { + tcpSession = session; + } + } +#endif // INET_CONFIG_ENABLE_TCP_ENDPOINT + + if ((mrpSession == nullptr) || (mrpSession->GetLastActivityTime() < session->GetLastActivityTime())) + { + mrpSession = session; } } return Loop::Continue; }); - return found != nullptr ? MakeOptional(*found) : Optional::Missing(); +#if INET_CONFIG_ENABLE_TCP_ENDPOINT + if (transportPayloadCapability == TransportPayloadCapability::kLargePayload) + { + return tcpSession != nullptr ? MakeOptional(*tcpSession) : Optional::Missing(); + } + + if (transportPayloadCapability == TransportPayloadCapability::kMRPOrTCPCompatiblePayload) + { + // If MRP-based session is available, use it. + if (mrpSession != nullptr) + { + return MakeOptional(*mrpSession); + } + + // Otherwise, look for a tcp-based session + if (tcpSession != nullptr) + { + return MakeOptional(*tcpSession); + } + + return Optional::Missing(); + } +#endif // INET_CONFIG_ENABLE_TCP_ENDPOINT + + return mrpSession != nullptr ? MakeOptional(*mrpSession) : Optional::Missing(); } /** diff --git a/src/transport/SessionManager.h b/src/transport/SessionManager.h index 5f2e6f7603cad0..b7a1630b3d2851 100644 --- a/src/transport/SessionManager.h +++ b/src/transport/SessionManager.h @@ -52,8 +52,30 @@ #include #include +#if INET_CONFIG_ENABLE_TCP_ENDPOINT +#include +#endif // INET_CONFIG_ENABLE_TCP_ENDPOINT + namespace chip { +/* + * This enum indicates whether a session needs to be established over a + * suitable transport that meets certain payload size requirements for + * transmitted messages. + * + */ +enum class TransportPayloadCapability : uint8_t +{ + kMRPPayload, // Transport requires the maximum payload size to fit within a single + // IPv6 packet(1280 bytes). + kLargePayload, // Transport needs to handle payloads larger than the single IPv6 + // packet, as supported by MRP. The transport of choice, in this + // case, is TCP. + kMRPOrTCPCompatiblePayload // This option provides the ability to use MRP + // as the preferred transport, but use a large + // payload transport if that is already + // available. +}; /** * @brief * Tracks ownership of a encrypted packet buffer. @@ -151,6 +173,10 @@ class DLL_EXPORT SessionManager : public TransportMgrDelegate, public FabricTabl /// ExchangeManager) void SetMessageDelegate(SessionMessageDelegate * cb) { mCB = cb; } +#if INET_CONFIG_ENABLE_TCP_ENDPOINT + void SetConnectionDelegate(SessionConnectionDelegate * cb) { mConnDelegate = cb; } +#endif // INET_CONFIG_ENABLE_TCP_ENDPOINT + // Test-only: create a session on the fly. CHIP_ERROR InjectPaseSessionWithTestKey(SessionHolder & sessionHolder, uint16_t localSessionId, NodeId peerNodeId, uint16_t peerSessionId, FabricIndex fabricIndex, @@ -413,8 +439,34 @@ class DLL_EXPORT SessionManager : public TransportMgrDelegate, public FabricTabl * * @param source the source address of the package * @param msgBuf the buffer containing a full CHIP message (except for the optional length field). + * @param ctxt pointer to additional context on the underlying transport. For TCP, it is a pointer + * to the underlying connection object. */ - void OnMessageReceived(const Transport::PeerAddress & source, System::PacketBufferHandle && msgBuf) override; + void OnMessageReceived(const Transport::PeerAddress & source, System::PacketBufferHandle && msgBuf, + Transport::MessageTransportContext * ctxt = nullptr) override; + +#if INET_CONFIG_ENABLE_TCP_ENDPOINT + CHIP_ERROR TCPConnect(const Transport::PeerAddress & peerAddress, Transport::AppTCPConnectionCallbackCtxt * appState, + Transport::ActiveTCPConnectionState ** peerConnState); + + CHIP_ERROR TCPDisconnect(const Transport::PeerAddress & peerAddress); + + void TCPDisconnect(Transport::ActiveTCPConnectionState * conn, bool shouldAbort = 0); + + void HandleConnectionReceived(Transport::ActiveTCPConnectionState * conn) override; + + void HandleConnectionAttemptComplete(Transport::ActiveTCPConnectionState * conn, CHIP_ERROR conErr) override; + + void HandleConnectionClosed(Transport::ActiveTCPConnectionState * conn, CHIP_ERROR conErr) override; + + // Functors for callbacks into higher layers + using OnTCPConnectionReceivedCallback = void (*)(Transport::ActiveTCPConnectionState * conn); + + using OnTCPConnectionCompleteCallback = void (*)(Transport::ActiveTCPConnectionState * conn, CHIP_ERROR conErr); + + using OnTCPConnectionClosedCallback = void (*)(Transport::ActiveTCPConnectionState * conn, CHIP_ERROR conErr); + +#endif // INET_CONFIG_ENABLE_TCP_ENDPOINT Optional CreateUnauthenticatedSession(const Transport::PeerAddress & peerAddress, const ReliableMessageProtocolConfig & config) @@ -436,8 +488,9 @@ class DLL_EXPORT SessionManager : public TransportMgrDelegate, public FabricTabl // is returned. Otherwise, an Optional with no value set is returned. // // - Optional FindSecureSessionForNode(ScopedNodeId peerNodeId, - const Optional & type = NullOptional); + Optional + FindSecureSessionForNode(ScopedNodeId peerNodeId, const Optional & type = NullOptional, + TransportPayloadCapability transportPayloadCapability = TransportPayloadCapability::kMRPPayload); using SessionHandleCallback = bool (*)(void * context, SessionHandle & sessionHandle); CHIP_ERROR ForEachSessionHandle(void * context, SessionHandleCallback callback); @@ -477,8 +530,22 @@ class DLL_EXPORT SessionManager : public TransportMgrDelegate, public FabricTabl State mState; // < Initialization state of the object chip::Transport::GroupOutgoingCounters mGroupClientCounter; +#if INET_CONFIG_ENABLE_TCP_ENDPOINT + OnTCPConnectionReceivedCallback mConnReceivedCb = nullptr; + OnTCPConnectionCompleteCallback mConnCompleteCb = nullptr; + OnTCPConnectionClosedCallback mConnClosedCb = nullptr; + + // Hold the TCPConnection callback context for the receiver application in the SessionManager. + // On receipt of a connection from a peer, the SessionManager + Transport::AppTCPConnectionCallbackCtxt * mServerTCPConnCbCtxt = nullptr; +#endif // INET_CONFIG_ENABLE_TCP_ENDPOINT + SessionMessageDelegate * mCB = nullptr; +#if INET_CONFIG_ENABLE_TCP_ENDPOINT + SessionConnectionDelegate * mConnDelegate = nullptr; +#endif // INET_CONFIG_ENABLE_TCP_ENDPOINT + TransportMgrBase * mTransportMgr = nullptr; Transport::MessageCounterManagerInterface * mMessageCounterManager = nullptr; @@ -491,9 +558,11 @@ class DLL_EXPORT SessionManager : public TransportMgrDelegate, public FabricTabl * If the message decrypts successfully, this will be filled with a fully decoded PacketHeader. * @param[in] peerAddress The PeerAddress of the message as provided by the receiving Transport Endpoint. * @param msg The full message buffer, including header fields. + * @param ctxt The pointer to additional context on the underlying transport. For TCP, it is a pointer + * to the underlying connection object. */ void SecureUnicastMessageDispatch(const PacketHeader & partialPacketHeader, const Transport::PeerAddress & peerAddress, - System::PacketBufferHandle && msg); + System::PacketBufferHandle && msg, Transport::MessageTransportContext * ctxt = nullptr); /** * @brief Parse, decrypt, validate, and dispatch a secure group message. @@ -511,9 +580,11 @@ class DLL_EXPORT SessionManager : public TransportMgrDelegate, public FabricTabl * @param partialPacketHeader The partial PacketHeader of the message after processing with DecodeFixed. * @param peerAddress The PeerAddress of the message as provided by the receiving Transport Endpoint. * @param msg The full message buffer, including header fields. + * @param ctxt The pointer to additional context on the underlying transport. For TCP, it is a pointer + * to the underlying connection object. */ void UnauthenticatedMessageDispatch(const PacketHeader & partialPacketHeader, const Transport::PeerAddress & peerAddress, - System::PacketBufferHandle && msg); + System::PacketBufferHandle && msg, Transport::MessageTransportContext * ctxt = nullptr); void OnReceiveError(CHIP_ERROR error, const Transport::PeerAddress & source); diff --git a/src/transport/TransportMgr.h b/src/transport/TransportMgr.h index 494db39de964fd..6e5f03ab4a44a6 100644 --- a/src/transport/TransportMgr.h +++ b/src/transport/TransportMgr.h @@ -34,6 +34,9 @@ #include #include #include +#if INET_CONFIG_ENABLE_TCP_ENDPOINT +#include +#endif // INET_CONFIG_ENABLE_TCP_ENDPOINT namespace chip { @@ -49,8 +52,26 @@ class TransportMgrDelegate * * @param source the source address of the package * @param msgBuf the buffer containing a full CHIP message (except for the optional length field). + * @param ctxt the pointer to additional context on the underlying transport. For TCP, it is a pointer + * to the underlying connection object. */ - virtual void OnMessageReceived(const Transport::PeerAddress & source, System::PacketBufferHandle && msgBuf) = 0; + virtual void OnMessageReceived(const Transport::PeerAddress & source, System::PacketBufferHandle && msgBuf, + Transport::MessageTransportContext * ctxt = nullptr) = 0; + +#if INET_CONFIG_ENABLE_TCP_ENDPOINT + /** + * @brief + * Handle connection attempt completion. + * + * @param conn the connection object + * @param conErr the connection error on the attempt, or CHIP_NO_ERROR. + */ + virtual void HandleConnectionAttemptComplete(Transport::ActiveTCPConnectionState * conn, CHIP_ERROR conErr){}; + + virtual void HandleConnectionClosed(Transport::ActiveTCPConnectionState * conn, CHIP_ERROR conErr){}; + + virtual void HandleConnectionReceived(Transport::ActiveTCPConnectionState * conn){}; +#endif // INET_CONFIG_ENABLE_TCP_ENDPOINT }; template diff --git a/src/transport/TransportMgrBase.cpp b/src/transport/TransportMgrBase.cpp index bde54a96c195b6..98997102eb92ca 100644 --- a/src/transport/TransportMgrBase.cpp +++ b/src/transport/TransportMgrBase.cpp @@ -28,11 +28,24 @@ CHIP_ERROR TransportMgrBase::SendMessage(const Transport::PeerAddress & address, return mTransport->SendMessage(address, std::move(msgBuf)); } -void TransportMgrBase::Disconnect(const Transport::PeerAddress & address) +#if INET_CONFIG_ENABLE_TCP_ENDPOINT +CHIP_ERROR TransportMgrBase::TCPConnect(const Transport::PeerAddress & address, Transport::AppTCPConnectionCallbackCtxt * appState, + Transport::ActiveTCPConnectionState ** peerConnState) { - mTransport->Disconnect(address); + return mTransport->TCPConnect(address, appState, peerConnState); } +void TransportMgrBase::TCPDisconnect(const Transport::PeerAddress & address) +{ + mTransport->TCPDisconnect(address); +} + +void TransportMgrBase::TCPDisconnect(Transport::ActiveTCPConnectionState * conn, bool shouldAbort) +{ + mTransport->TCPDisconnect(conn, shouldAbort); +} +#endif // INET_CONFIG_ENABLE_TCP_ENDPOINT + CHIP_ERROR TransportMgrBase::Init(Transport::Base * transport) { if (mTransport != nullptr) @@ -41,6 +54,7 @@ CHIP_ERROR TransportMgrBase::Init(Transport::Base * transport) } mTransport = transport; mTransport->SetDelegate(this); + ChipLogDetail(Inet, "TransportMgr initialized"); return CHIP_NO_ERROR; } @@ -56,7 +70,8 @@ CHIP_ERROR TransportMgrBase::MulticastGroupJoinLeave(const Transport::PeerAddres return mTransport->MulticastGroupJoinLeave(address, join); } -void TransportMgrBase::HandleMessageReceived(const Transport::PeerAddress & peerAddress, System::PacketBufferHandle && msg) +void TransportMgrBase::HandleMessageReceived(const Transport::PeerAddress & peerAddress, System::PacketBufferHandle && msg, + Transport::MessageTransportContext * ctxt) { // This is the first point all incoming messages funnel through. Ensure // that our message receipts are all synchronized correctly. @@ -73,7 +88,7 @@ void TransportMgrBase::HandleMessageReceived(const Transport::PeerAddress & peer if (mSessionManager != nullptr) { - mSessionManager->OnMessageReceived(peerAddress, std::move(msg)); + mSessionManager->OnMessageReceived(peerAddress, std::move(msg), ctxt); } else { @@ -83,4 +98,60 @@ void TransportMgrBase::HandleMessageReceived(const Transport::PeerAddress & peer } } +#if INET_CONFIG_ENABLE_TCP_ENDPOINT +void TransportMgrBase::HandleConnectionReceived(Transport::ActiveTCPConnectionState * conn) +{ + if (mSessionManager != nullptr) + { + mSessionManager->HandleConnectionReceived(conn); + } + else + { + Transport::TCPBase * tcp = reinterpret_cast(conn->mEndPoint->mAppState); + + // Close connection here since no upper layer is interested in the + // connection. + if (tcp) + { + tcp->TCPDisconnect(conn, /* shouldAbort = */ true); + } + } +} + +void TransportMgrBase::HandleConnectionAttemptComplete(Transport::ActiveTCPConnectionState * conn, CHIP_ERROR conErr) +{ + if (mSessionManager != nullptr) + { + mSessionManager->HandleConnectionAttemptComplete(conn, conErr); + } + else + { + Transport::TCPBase * tcp = reinterpret_cast(conn->mEndPoint->mAppState); + + // Close connection here since no upper layer is interested in the + // connection. + if (tcp) + { + tcp->TCPDisconnect(conn, /* shouldAbort = */ true); + } + } +} + +void TransportMgrBase::HandleConnectionClosed(Transport::ActiveTCPConnectionState * conn, CHIP_ERROR conErr) +{ + if (mSessionManager != nullptr) + { + mSessionManager->HandleConnectionClosed(conn, conErr); + } + else + { + Transport::TCPBase * tcp = reinterpret_cast(conn->mEndPoint->mAppState); + if (tcp) + { + tcp->TCPDisconnect(conn, /* shouldAbort = */ true); + } + } +} +#endif // INET_CONFIG_ENABLE_TCP_ENDPOINT + } // namespace chip diff --git a/src/transport/TransportMgrBase.h b/src/transport/TransportMgrBase.h index e4942ca6ecd90b..2b0f33bfb9e3a7 100644 --- a/src/transport/TransportMgrBase.h +++ b/src/transport/TransportMgrBase.h @@ -21,6 +21,9 @@ #include #include #include +#if INET_CONFIG_ENABLE_TCP_ENDPOINT +#include +#endif // INET_CONFIG_ENABLE_TCP_ENDPOINT namespace chip { @@ -39,13 +42,29 @@ class TransportMgrBase : public Transport::RawTransportDelegate void Close(); - void Disconnect(const Transport::PeerAddress & address); +#if INET_CONFIG_ENABLE_TCP_ENDPOINT + CHIP_ERROR TCPConnect(const Transport::PeerAddress & address, Transport::AppTCPConnectionCallbackCtxt * appState, + Transport::ActiveTCPConnectionState ** peerConnState); + + void TCPDisconnect(const Transport::PeerAddress & address); + + void TCPDisconnect(Transport::ActiveTCPConnectionState * conn, bool shouldAbort = 0); + + void HandleConnectionReceived(Transport::ActiveTCPConnectionState * conn) override; + + void HandleConnectionAttemptComplete(Transport::ActiveTCPConnectionState * conn, CHIP_ERROR conErr) override; + + void HandleConnectionClosed(Transport::ActiveTCPConnectionState * conn, CHIP_ERROR conErr) override; +#endif // INET_CONFIG_ENABLE_TCP_ENDPOINT void SetSessionManager(TransportMgrDelegate * sessionManager) { mSessionManager = sessionManager; } + TransportMgrDelegate * GetSessionManager() { return mSessionManager; }; + CHIP_ERROR MulticastGroupJoinLeave(const Transport::PeerAddress & address, bool join); - void HandleMessageReceived(const Transport::PeerAddress & peerAddress, System::PacketBufferHandle && msg) override; + void HandleMessageReceived(const Transport::PeerAddress & peerAddress, System::PacketBufferHandle && msg, + Transport::MessageTransportContext * ctxt = nullptr) override; private: TransportMgrDelegate * mSessionManager = nullptr; diff --git a/src/transport/UnauthenticatedSessionTable.h b/src/transport/UnauthenticatedSessionTable.h index 1c3ff7ed55586a..913058229e1a6b 100644 --- a/src/transport/UnauthenticatedSessionTable.h +++ b/src/transport/UnauthenticatedSessionTable.h @@ -45,9 +45,10 @@ class UnauthenticatedSession : public Session, public ReferenceCounted & sessionTable) : - UnauthenticatedSession(sessionRole, ephemeralInitiatorNodeID, config) + UnauthenticatedSession(sessionRole, ephemeralInitiatorNodeID, peerAddress, config) #if CHIP_SYSTEM_CONFIG_POOL_USE_HEAP , mSessionTable(sessionTable) @@ -224,13 +225,16 @@ class UnauthenticatedSessionTable * @return the session found or allocated, or Optional::Missing if not found and allocation failed. */ CHECK_RETURN_VALUE - Optional FindOrAllocateResponder(NodeId ephemeralInitiatorNodeID, const ReliableMessageProtocolConfig & config) + Optional FindOrAllocateResponder(NodeId ephemeralInitiatorNodeID, const ReliableMessageProtocolConfig & config, + const Transport::PeerAddress & peerAddress) { - UnauthenticatedSession * result = FindEntry(UnauthenticatedSession::SessionRole::kResponder, ephemeralInitiatorNodeID); + UnauthenticatedSession * result = + FindEntry(UnauthenticatedSession::SessionRole::kResponder, ephemeralInitiatorNodeID, peerAddress); if (result != nullptr) return MakeOptional(*result); - CHIP_ERROR err = AllocEntry(UnauthenticatedSession::SessionRole::kResponder, ephemeralInitiatorNodeID, config, result); + CHIP_ERROR err = + AllocEntry(UnauthenticatedSession::SessionRole::kResponder, ephemeralInitiatorNodeID, peerAddress, config, result); if (err == CHIP_NO_ERROR) { return MakeOptional(*result); @@ -239,9 +243,11 @@ class UnauthenticatedSessionTable return Optional::Missing(); } - CHECK_RETURN_VALUE Optional FindInitiator(NodeId ephemeralInitiatorNodeID) + CHECK_RETURN_VALUE Optional FindInitiator(NodeId ephemeralInitiatorNodeID, + const Transport::PeerAddress & peerAddress) { - UnauthenticatedSession * result = FindEntry(UnauthenticatedSession::SessionRole::kInitiator, ephemeralInitiatorNodeID); + UnauthenticatedSession * result = + FindEntry(UnauthenticatedSession::SessionRole::kInitiator, ephemeralInitiatorNodeID, peerAddress); if (result != nullptr) { return MakeOptional(*result); @@ -254,7 +260,8 @@ class UnauthenticatedSessionTable const ReliableMessageProtocolConfig & config) { UnauthenticatedSession * result = nullptr; - CHIP_ERROR err = AllocEntry(UnauthenticatedSession::SessionRole::kInitiator, ephemeralInitiatorNodeID, config, result); + CHIP_ERROR err = + AllocEntry(UnauthenticatedSession::SessionRole::kInitiator, ephemeralInitiatorNodeID, peerAddress, config, result); if (err == CHIP_NO_ERROR) { result->SetPeerAddress(peerAddress); @@ -276,9 +283,10 @@ class UnauthenticatedSessionTable */ CHECK_RETURN_VALUE CHIP_ERROR AllocEntry(UnauthenticatedSession::SessionRole sessionRole, NodeId ephemeralInitiatorNodeID, - const ReliableMessageProtocolConfig & config, UnauthenticatedSession *& entry) + const PeerAddress & peerAddress, const ReliableMessageProtocolConfig & config, + UnauthenticatedSession *& entry) { - auto entryToUse = mEntries.CreateObject(sessionRole, ephemeralInitiatorNodeID, config, *this); + auto entryToUse = mEntries.CreateObject(sessionRole, ephemeralInitiatorNodeID, peerAddress, config, *this); if (entryToUse != nullptr) { entry = entryToUse; @@ -294,7 +302,7 @@ class UnauthenticatedSessionTable // Drop the least recent entry to allow for a new alloc. mEntries.ReleaseObject(entryToUse); - entryToUse = mEntries.CreateObject(sessionRole, ephemeralInitiatorNodeID, config, *this); + entryToUse = mEntries.CreateObject(sessionRole, ephemeralInitiatorNodeID, peerAddress, config, *this); if (entryToUse == nullptr) { @@ -308,11 +316,13 @@ class UnauthenticatedSessionTable } CHECK_RETURN_VALUE UnauthenticatedSession * FindEntry(UnauthenticatedSession::SessionRole sessionRole, - NodeId ephemeralInitiatorNodeID) + NodeId ephemeralInitiatorNodeID, + const Transport::PeerAddress & peerAddress) { UnauthenticatedSession * result = nullptr; mEntries.ForEachActiveObject([&](UnauthenticatedSession * entry) { - if (entry->GetSessionRole() == sessionRole && entry->GetEphemeralInitiatorNodeID() == ephemeralInitiatorNodeID) + if (entry->GetSessionRole() == sessionRole && entry->GetEphemeralInitiatorNodeID() == ephemeralInitiatorNodeID && + entry->GetPeerAddress().GetTransportType() == peerAddress.GetTransportType()) { result = entry; return Loop::Break; diff --git a/src/transport/raw/ActiveTCPConnectionState.h b/src/transport/raw/ActiveTCPConnectionState.h new file mode 100644 index 00000000000000..0f53d4479e9300 --- /dev/null +++ b/src/transport/raw/ActiveTCPConnectionState.h @@ -0,0 +1,125 @@ +/* + * + * Copyright (c) 2023 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file + * This file defines the CHIP Active Connection object that maintains TCP connections. + */ + +#pragma once + +#include +#include +#include +#include +#include +#include + +namespace chip { +namespace Transport { + +/** + * The State of the TCP connection + */ +enum class TCPState +{ + kNotReady = 0, /**< State before initialization. */ + kInitialized = 1, /**< State after class is listening and ready. */ + kConnecting = 3, /**< Connection with peer has been initiated. */ + kConnected = 4, /**< Connected with peer and ready for Send/Receive. */ + kClosed = 5, /**< Connection is closed. */ +}; + +struct AppTCPConnectionCallbackCtxt; +/** + * State for each active TCP connection + */ +struct ActiveTCPConnectionState +{ + + void Init(Inet::TCPEndPoint * endPoint, const PeerAddress & peerAddr) + { + mEndPoint = endPoint; + mPeerAddr = peerAddr; + mReceived = nullptr; + mAppState = nullptr; + } + + void Free() + { + mEndPoint->Free(); + mPeerAddr = PeerAddress::Uninitialized(); + mEndPoint = nullptr; + mReceived = nullptr; + mAppState = nullptr; + } + + bool InUse() const { return mEndPoint != nullptr; } + + bool IsConnected() const { return (mEndPoint != nullptr && mConnectionState == TCPState::kConnected); } + + bool IsConnecting() const { return (mEndPoint != nullptr && mConnectionState == TCPState::kConnecting); } + + // Associated endpoint. + Inet::TCPEndPoint * mEndPoint; + + // Peer Node Address + PeerAddress mPeerAddr; + + // Buffers received but not yet consumed. + System::PacketBufferHandle mReceived; + + // Current state of the connection + TCPState mConnectionState; + + // A pointer to an application-specific state object. It should + // represent an object that is at a layer above the SessionManager. The + // SessionManager would accept this object at the time of connecting to + // the peer, and percolate it down to the TransportManager that then, + // should store this state in the corresponding connection object that + // is created. + // At various connection events, this state is passed back to the + // corresponding application. + AppTCPConnectionCallbackCtxt * mAppState = nullptr; + + // KeepAlive interval in seconds + uint16_t mTCPKeepAliveIntervalSecs = CHIP_CONFIG_TCP_KEEPALIVE_INTERVAL_SECS; + uint16_t mTCPMaxNumKeepAliveProbes = CHIP_CONFIG_MAX_TCP_KEEPALIVE_PROBES; +}; + +// Functors for callbacks into higher layers +using OnTCPConnectionReceivedCallback = void (*)(ActiveTCPConnectionState * conn); + +using OnTCPConnectionCompleteCallback = void (*)(ActiveTCPConnectionState * conn, CHIP_ERROR conErr); + +using OnTCPConnectionClosedCallback = void (*)(ActiveTCPConnectionState * conn, CHIP_ERROR conErr); + +/* + * Application callback state that is passed down at connection establishment + * stage. + * */ +struct AppTCPConnectionCallbackCtxt +{ + void * appContext = nullptr; // A pointer to an application context object. + OnTCPConnectionReceivedCallback connReceivedCb = nullptr; + OnTCPConnectionCompleteCallback connCompleteCb = nullptr; + OnTCPConnectionClosedCallback connClosedCb = nullptr; +}; + +} // namespace Transport +} // namespace chip diff --git a/src/transport/raw/BUILD.gn b/src/transport/raw/BUILD.gn index 736b16cdb08477..3e8d3d4761dca3 100644 --- a/src/transport/raw/BUILD.gn +++ b/src/transport/raw/BUILD.gn @@ -14,6 +14,7 @@ import("//build_overrides/chip.gni") import("${chip_root}/src/ble/ble.gni") +import("${chip_root}/src/inet/inet.gni") static_library("raw") { output_name = "libRawTransport" @@ -23,13 +24,20 @@ static_library("raw") { "MessageHeader.cpp", "MessageHeader.h", "PeerAddress.h", - "TCP.cpp", - "TCP.h", "Tuple.h", "UDP.cpp", "UDP.h", ] + if (chip_inet_config_enable_tcp_endpoint) { + sources += [ + "ActiveTCPConnectionState.h", + "TCP.cpp", + "TCP.h", + "TCPConfig.h", + ] + } + if (chip_config_network_layer_ble) { sources += [ "BLE.cpp", diff --git a/src/transport/raw/Base.h b/src/transport/raw/Base.h index 66c01a5fcc3d5d..920f932b82be41 100644 --- a/src/transport/raw/Base.h +++ b/src/transport/raw/Base.h @@ -24,20 +24,38 @@ #pragma once #include +#include #include #include #include #include #include +#if INET_CONFIG_ENABLE_TCP_ENDPOINT +#include +#endif // INET_CONFIG_ENABLE_TCP_ENDPOINT namespace chip { namespace Transport { +struct MessageTransportContext +{ +#if INET_CONFIG_ENABLE_TCP_ENDPOINT + ActiveTCPConnectionState * conn = nullptr; +#endif // INET_CONFIG_ENABLE_TCP_ENDPOINT +}; + class RawTransportDelegate { public: virtual ~RawTransportDelegate() {} - virtual void HandleMessageReceived(const Transport::PeerAddress & peerAddress, System::PacketBufferHandle && msg) = 0; + virtual void HandleMessageReceived(const Transport::PeerAddress & peerAddress, System::PacketBufferHandle && msg, + MessageTransportContext * ctxt = nullptr) = 0; + +#if INET_CONFIG_ENABLE_TCP_ENDPOINT + virtual void HandleConnectionReceived(ActiveTCPConnectionState * conn){}; + virtual void HandleConnectionAttemptComplete(ActiveTCPConnectionState * conn, CHIP_ERROR conErr){}; + virtual void HandleConnectionClosed(ActiveTCPConnectionState * conn, CHIP_ERROR conErr){}; +#endif // INET_CONFIG_ENABLE_TCP_ENDPOINT }; /** @@ -77,10 +95,26 @@ class Base */ virtual bool CanListenMulticast() { return false; } +#if INET_CONFIG_ENABLE_TCP_ENDPOINT + /** + * Connect to the specified peer. + */ + virtual CHIP_ERROR TCPConnect(const PeerAddress & address, Transport::AppTCPConnectionCallbackCtxt * appState, + Transport::ActiveTCPConnectionState ** peerConnState) + { + return CHIP_NO_ERROR; + } + /** * Handle disconnection from the specified peer if currently connected to it. */ - virtual void Disconnect(const PeerAddress & address) {} + virtual void TCPDisconnect(const PeerAddress & address) {} + + /** + * Disconnect on the active connection that is passed in. + */ + virtual void TCPDisconnect(Transport::ActiveTCPConnectionState * conn, bool shouldAbort = 0) {} +#endif // INET_CONFIG_ENABLE_TCP_ENDPOINT /** * Enable Listening for multicast messages ( IPV6 UDP only) @@ -97,12 +131,31 @@ class Base * Method used by subclasses to notify that a packet has been received after * any associated headers have been decoded. */ - void HandleMessageReceived(const PeerAddress & source, System::PacketBufferHandle && buffer) + void HandleMessageReceived(const PeerAddress & source, System::PacketBufferHandle && buffer, + MessageTransportContext * ctxt = nullptr) + { + mDelegate->HandleMessageReceived(source, std::move(buffer), ctxt); + } + +#if INET_CONFIG_ENABLE_TCP_ENDPOINT + // Handle an incoming connection request from a peer. + void HandleConnectionReceived(ActiveTCPConnectionState * conn) { mDelegate->HandleConnectionReceived(conn); } + + // Callback during connection establishment to notify of success or any + // error. + void HandleConnectionAttemptComplete(ActiveTCPConnectionState * conn, CHIP_ERROR conErr) + { + mDelegate->HandleConnectionAttemptComplete(conn, conErr); + } + + // Callback to notify the higher layer of an unexpected connection closure. + void HandleConnectionClosed(ActiveTCPConnectionState * conn, CHIP_ERROR conErr) { - mDelegate->HandleMessageReceived(source, std::move(buffer)); + mDelegate->HandleConnectionClosed(conn, conErr); } +#endif // INET_CONFIG_ENABLE_TCP_ENDPOINT - RawTransportDelegate * mDelegate; + RawTransportDelegate * mDelegate = nullptr; }; } // namespace Transport diff --git a/src/transport/raw/TCP.cpp b/src/transport/raw/TCP.cpp index a1b1df1fe45a2d..e33590a63a6fdf 100644 --- a/src/transport/raw/TCP.cpp +++ b/src/transport/raw/TCP.cpp @@ -67,8 +67,7 @@ void TCPBase::CloseActiveConnections() { if (mActiveConnections[i].InUse()) { - mActiveConnections[i].Free(); - mUsedEndPointCount--; + CloseConnectionInternal(&mActiveConnections[i], CHIP_NO_ERROR, SuppressCallback::Yes); } } } @@ -77,7 +76,7 @@ CHIP_ERROR TCPBase::Init(TcpListenParameters & params) { CHIP_ERROR err = CHIP_NO_ERROR; - VerifyOrExit(mState == State::kNotReady, err = CHIP_ERROR_INCORRECT_STATE); + VerifyOrExit(mState == TCPState::kNotReady, err = CHIP_ERROR_INCORRECT_STATE); #if INET_CONFIG_ENABLE_TCP_ENDPOINT err = params.GetEndPointManager()->NewEndPoint(&mListenSocket); @@ -90,23 +89,21 @@ CHIP_ERROR TCPBase::Init(TcpListenParameters & params) params.GetInterfaceId().IsPresent()); SuccessOrExit(err); + mListenSocket->mAppState = reinterpret_cast(this); + mListenSocket->OnConnectionReceived = HandleIncomingConnection; + mListenSocket->OnAcceptError = HandleAcceptError; + + mEndpointType = params.GetAddressType(); + err = mListenSocket->Listen(kListenBacklogSize); SuccessOrExit(err); - mListenSocket->mAppState = reinterpret_cast(this); - mListenSocket->OnDataReceived = OnTcpReceive; - mListenSocket->OnConnectComplete = OnConnectionComplete; - mListenSocket->OnConnectionClosed = OnConnectionClosed; - mListenSocket->OnConnectionReceived = OnConnectionReceived; - mListenSocket->OnAcceptError = OnAcceptError; - mEndpointType = params.GetAddressType(); - - mState = State::kInitialized; + mState = TCPState::kInitialized; exit: if (err != CHIP_NO_ERROR) { - ChipLogError(Inet, "Failed to initialize TCP transport: %s", ErrorStr(err)); + ChipLogError(Inet, "Failed to initialize TCP transport: %" CHIP_ERROR_FORMAT, err.Format()); if (mListenSocket) { mListenSocket->Free(); @@ -124,10 +121,24 @@ void TCPBase::Close() mListenSocket->Free(); mListenSocket = nullptr; } - mState = State::kNotReady; + mState = TCPState::kNotReady; +} + +ActiveTCPConnectionState * TCPBase::AllocateConnection() +{ + for (size_t i = 0; i < mActiveConnectionsSize; i++) + { + if (!mActiveConnections[i].InUse()) + { + return &mActiveConnections[i]; + } + } + + return nullptr; } -TCPBase::ActiveConnectionState * TCPBase::FindActiveConnection(const PeerAddress & address) +// Find an ActiveTCPConnectionState corresponding to a peer address +ActiveTCPConnectionState * TCPBase::FindActiveConnection(const PeerAddress & address) { if (address.GetTransportType() != Type::kTcp) { @@ -136,7 +147,7 @@ TCPBase::ActiveConnectionState * TCPBase::FindActiveConnection(const PeerAddress for (size_t i = 0; i < mActiveConnectionsSize; i++) { - if (!mActiveConnections[i].InUse()) + if (!mActiveConnections[i].IsConnected()) { continue; } @@ -153,8 +164,26 @@ TCPBase::ActiveConnectionState * TCPBase::FindActiveConnection(const PeerAddress return nullptr; } -TCPBase::ActiveConnectionState * TCPBase::FindActiveConnection(const Inet::TCPEndPoint * endPoint) +// Find the ActiveTCPConnectionState for a given TCPEndPoint +ActiveTCPConnectionState * TCPBase::FindActiveConnection(const Inet::TCPEndPoint * endPoint) { + for (size_t i = 0; i < mActiveConnectionsSize; i++) + { + if (mActiveConnections[i].mEndPoint == endPoint && mActiveConnections[i].IsConnected()) + { + return &mActiveConnections[i]; + } + } + return nullptr; +} + +ActiveTCPConnectionState * TCPBase::FindInUseConnection(const Inet::TCPEndPoint * endPoint) +{ + if (endPoint == nullptr) + { + return nullptr; + } + for (size_t i = 0; i < mActiveConnectionsSize; i++) { if (mActiveConnections[i].mEndPoint == endPoint) @@ -172,7 +201,7 @@ CHIP_ERROR TCPBase::SendMessage(const Transport::PeerAddress & address, System:: // - actual data VerifyOrReturnError(address.GetTransportType() == Type::kTcp, CHIP_ERROR_INVALID_ARGUMENT); - VerifyOrReturnError(mState == State::kInitialized, CHIP_ERROR_INCORRECT_STATE); + VerifyOrReturnError(mState == TCPState::kInitialized, CHIP_ERROR_INCORRECT_STATE); VerifyOrReturnError(kPacketSizeBytes + msgBuf->DataLength() <= std::numeric_limits::max(), CHIP_ERROR_INVALID_ARGUMENT); @@ -186,7 +215,7 @@ CHIP_ERROR TCPBase::SendMessage(const Transport::PeerAddress & address, System:: // Reuse existing connection if one exists, otherwise a new one // will be established - ActiveConnectionState * connection = FindActiveConnection(address); + ActiveTCPConnectionState * connection = FindActiveConnection(address); if (connection != nullptr) { @@ -196,8 +225,46 @@ CHIP_ERROR TCPBase::SendMessage(const Transport::PeerAddress & address, System:: return SendAfterConnect(address, std::move(msgBuf)); } +CHIP_ERROR TCPBase::StartConnect(const PeerAddress & addr, Transport::AppTCPConnectionCallbackCtxt * appState, + Transport::ActiveTCPConnectionState ** outPeerConnState) +{ +#if INET_CONFIG_ENABLE_TCP_ENDPOINT + ActiveTCPConnectionState * activeConnection = nullptr; + Inet::TCPEndPoint * endPoint = nullptr; + *outPeerConnState = nullptr; + ReturnErrorOnFailure(mListenSocket->GetEndPointManager().NewEndPoint(&endPoint)); + + auto EndPointDeletor = [](Inet::TCPEndPoint * e) { e->Free(); }; + std::unique_ptr endPointHolder(endPoint, EndPointDeletor); + + endPoint->mAppState = reinterpret_cast(this); + endPoint->OnConnectComplete = HandleTCPEndPointConnectComplete; + endPoint->SetConnectTimeout(mConnectTimeout); + + activeConnection = AllocateConnection(); + VerifyOrReturnError(activeConnection != nullptr, CHIP_ERROR_NO_MEMORY); + activeConnection->Init(endPoint, addr); + activeConnection->mAppState = appState; + activeConnection->mConnectionState = TCPState::kConnecting; + // Set the return value of the peer connection state to the allocated + // connection. + *outPeerConnState = activeConnection; + + ReturnErrorOnFailure(endPoint->Connect(addr.GetIPAddress(), addr.GetPort(), addr.GetInterface())); + + mUsedEndPointCount++; + + endPointHolder.release(); + + return CHIP_NO_ERROR; +#else + return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; +#endif +} + CHIP_ERROR TCPBase::SendAfterConnect(const PeerAddress & addr, System::PacketBufferHandle && msg) { +#if INET_CONFIG_ENABLE_TCP_ENDPOINT // This will initiate a connection to the specified peer bool alreadyConnecting = false; @@ -224,28 +291,13 @@ CHIP_ERROR TCPBase::SendAfterConnect(const PeerAddress & addr, System::PacketBuf // Ensures sufficient active connections size exist VerifyOrReturnError(mUsedEndPointCount < mActiveConnectionsSize, CHIP_ERROR_NO_MEMORY); -#if INET_CONFIG_ENABLE_TCP_ENDPOINT - Inet::TCPEndPoint * endPoint = nullptr; - ReturnErrorOnFailure(mListenSocket->GetEndPointManager().NewEndPoint(&endPoint)); - auto EndPointDeletor = [](Inet::TCPEndPoint * e) { e->Free(); }; - std::unique_ptr endPointHolder(endPoint, EndPointDeletor); - - endPoint->mAppState = reinterpret_cast(this); - endPoint->OnDataReceived = OnTcpReceive; - endPoint->OnConnectComplete = OnConnectionComplete; - endPoint->OnConnectionClosed = OnConnectionClosed; - endPoint->OnConnectionReceived = OnConnectionReceived; - endPoint->OnAcceptError = OnAcceptError; - endPoint->OnPeerClose = OnPeerClosed; - - ReturnErrorOnFailure(endPoint->Connect(addr.GetIPAddress(), addr.GetPort(), addr.GetInterface())); + Transport::ActiveTCPConnectionState * peerConnState = nullptr; + ReturnErrorOnFailure(StartConnect(addr, nullptr, &peerConnState)); // enqueue the packet once the connection succeeds VerifyOrReturnError(mPendingPackets.CreateObject(addr, std::move(msg)) != nullptr, CHIP_ERROR_NO_MEMORY); mUsedEndPointCount++; - endPointHolder.release(); - return CHIP_NO_ERROR; #else return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; @@ -255,7 +307,7 @@ CHIP_ERROR TCPBase::SendAfterConnect(const PeerAddress & addr, System::PacketBuf CHIP_ERROR TCPBase::ProcessReceivedBuffer(Inet::TCPEndPoint * endPoint, const PeerAddress & peerAddress, System::PacketBufferHandle && buffer) { - ActiveConnectionState * state = FindActiveConnection(endPoint); + ActiveTCPConnectionState * state = FindActiveConnection(endPoint); VerifyOrReturnError(state != nullptr, CHIP_ERROR_INTERNAL); state->mReceived.AddToEnd(std::move(buffer)); @@ -275,6 +327,7 @@ CHIP_ERROR TCPBase::ProcessReceivedBuffer(Inet::TCPEndPoint * endPoint, const Pe uint16_t messageSize = LittleEndian::Get16(messageSizeBuf); if (messageSize >= kMaxMessageSize) { + // This message is too long for upper layers. return CHIP_ERROR_MESSAGE_TOO_LONG; } @@ -291,12 +344,15 @@ CHIP_ERROR TCPBase::ProcessReceivedBuffer(Inet::TCPEndPoint * endPoint, const Pe return CHIP_NO_ERROR; } -CHIP_ERROR TCPBase::ProcessSingleMessage(const PeerAddress & peerAddress, ActiveConnectionState * state, uint16_t messageSize) +CHIP_ERROR TCPBase::ProcessSingleMessage(const PeerAddress & peerAddress, ActiveTCPConnectionState * state, uint16_t messageSize) { // We enter with `state->mReceived` containing at least one full message, perhaps in a chain. // `state->mReceived->Start()` currently points to the message data. // On exit, `state->mReceived` will have had `messageSize` bytes consumed, no matter what. System::PacketBufferHandle message; + MessageTransportContext msgContext; + msgContext.conn = state; + if (state->mReceived->DataLength() == messageSize) { // In this case, the head packet buffer contains exactly the message. @@ -321,23 +377,53 @@ CHIP_ERROR TCPBase::ProcessSingleMessage(const PeerAddress & peerAddress, Active message->SetDataLength(messageSize); } - HandleMessageReceived(peerAddress, std::move(message)); + HandleMessageReceived(peerAddress, std::move(message), &msgContext); return CHIP_NO_ERROR; } -void TCPBase::ReleaseActiveConnection(Inet::TCPEndPoint * endPoint) +void TCPBase::CloseConnectionInternal(ActiveTCPConnectionState * connection, CHIP_ERROR err, SuppressCallback suppressCallback) { - for (size_t i = 0; i < mActiveConnectionsSize; i++) + TCPState prevState; + + if (connection == nullptr) { - if (mActiveConnections[i].mEndPoint == endPoint) + return; + } + + if (connection->mConnectionState != TCPState::kClosed && connection->mEndPoint) + { + if (err == CHIP_NO_ERROR) { - mActiveConnections[i].Free(); - mUsedEndPointCount--; + connection->mEndPoint->Close(); } + else + { + connection->mEndPoint->Abort(); + } + + prevState = connection->mConnectionState; + connection->mConnectionState = TCPState::kClosed; + + if (suppressCallback == SuppressCallback::No) + { + if (prevState == TCPState::kConnecting) + { + // Call upper layer connection attempt complete handler + HandleConnectionAttemptComplete(connection, err); + } + else + { + // Call upper layer connection closed handler + HandleConnectionClosed(connection, err); + } + } + + connection->Free(); + mUsedEndPointCount--; } } -CHIP_ERROR TCPBase::OnTcpReceive(Inet::TCPEndPoint * endPoint, System::PacketBufferHandle && buffer) +CHIP_ERROR TCPBase::HandleTCPEndPointDataReceived(Inet::TCPEndPoint * endPoint, System::PacketBufferHandle && buffer) { Inet::IPAddress ipAddress; uint16_t port; @@ -353,13 +439,13 @@ CHIP_ERROR TCPBase::OnTcpReceive(Inet::TCPEndPoint * endPoint, System::PacketBuf if (err != CHIP_NO_ERROR) { // Connection could need to be closed at this point - ChipLogError(Inet, "Failed to accept received TCP message: %s", ErrorStr(err)); + ChipLogError(Inet, "Failed to accept received TCP message: %" CHIP_ERROR_FORMAT, err.Format()); return CHIP_ERROR_UNEXPECTED_EVENT; } return CHIP_NO_ERROR; } -void TCPBase::OnConnectionComplete(Inet::TCPEndPoint * endPoint, CHIP_ERROR inetErr) +void TCPBase::HandleTCPEndPointConnectComplete(Inet::TCPEndPoint * endPoint, CHIP_ERROR conErr) { CHIP_ERROR err = CHIP_NO_ERROR; bool foundPendingPacket = false; @@ -367,157 +453,229 @@ void TCPBase::OnConnectionComplete(Inet::TCPEndPoint * endPoint, CHIP_ERROR inet Inet::IPAddress ipAddress; uint16_t port; Inet::InterfaceId interfaceId; + ActiveTCPConnectionState * activeConnection = nullptr; endPoint->GetPeerInfo(&ipAddress, &port); endPoint->GetInterfaceId(&interfaceId); + char addrStr[Transport::PeerAddress::kMaxToStringSize]; PeerAddress addr = PeerAddress::TCP(ipAddress, port, interfaceId); + addr.ToString(addrStr); - // Send any pending packets - tcp->mPendingPackets.ForEachActiveObject([&](PendingPacket * pending) { - if (pending->mPeerAddress == addr) + if (conErr == CHIP_NO_ERROR) + { + // Set the Data received handler when connection completes + endPoint->OnDataReceived = HandleTCPEndPointDataReceived; + endPoint->OnDataSent = nullptr; + endPoint->OnConnectionClosed = HandleTCPEndPointConnectionClosed; + + activeConnection = tcp->FindInUseConnection(endPoint); + VerifyOrDie(activeConnection != nullptr); + + // Set to Connected state + activeConnection->mConnectionState = TCPState::kConnected; + + // Disable TCP Nagle buffering by setting TCP_NODELAY socket option to true. + // This is to expedite transmission of payload data and not rely on the + // network stack's configuration of collating enough data in the TCP + // window to begin transmission. + err = endPoint->EnableNoDelay(); + if (err != CHIP_NO_ERROR) { - foundPendingPacket = true; - System::PacketBufferHandle buffer = std::move(pending->mPacketBuffer); - tcp->mPendingPackets.ReleaseObject(pending); + tcp->CloseConnectionInternal(activeConnection, err, SuppressCallback::No); + return; + } - if ((inetErr == CHIP_NO_ERROR) && (err == CHIP_NO_ERROR)) + // Send any pending packets that are queued for this connection + tcp->mPendingPackets.ForEachActiveObject([&](PendingPacket * pending) { + if (pending->mPeerAddress == addr) { - err = endPoint->Send(std::move(buffer)); + foundPendingPacket = true; + System::PacketBufferHandle buffer = std::move(pending->mPacketBuffer); + tcp->mPendingPackets.ReleaseObject(pending); + + if ((conErr == CHIP_NO_ERROR) && (err == CHIP_NO_ERROR)) + { + err = endPoint->Send(std::move(buffer)); + } } - } - return Loop::Continue; - }); + return Loop::Continue; + }); - if (err == CHIP_NO_ERROR) - { - err = inetErr; - } + // Set the TCPKeepalive configurations on the established connection + endPoint->EnableKeepAlive(activeConnection->mTCPKeepAliveIntervalSecs, activeConnection->mTCPMaxNumKeepAliveProbes); - if (!foundPendingPacket && (err == CHIP_NO_ERROR)) - { - // Force a close: new connections are only expected when a - // new buffer is being sent. - ChipLogError(Inet, "Connection accepted without pending buffers"); - err = CHIP_ERROR_CONNECTION_CLOSED_UNEXPECTEDLY; - } + ChipLogProgress(Inet, "Connection established successfully with %s.", addrStr); - // cleanup packets or mark as free - if (err != CHIP_NO_ERROR) - { - ChipLogError(Inet, "Connection complete encountered an error: %s", ErrorStr(err)); - endPoint->Free(); - tcp->mUsedEndPointCount--; + // Let higher layer/delegate know that connection is successfully + // established + tcp->HandleConnectionAttemptComplete(activeConnection, CHIP_NO_ERROR); } else { - bool connectionStored = false; - for (size_t i = 0; i < tcp->mActiveConnectionsSize; i++) - { - if (!tcp->mActiveConnections[i].InUse()) - { - tcp->mActiveConnections[i].Init(endPoint); - connectionStored = true; - break; - } - } - - // since we track end points counts, we always expect to store the - // connection. - if (!connectionStored) - { - endPoint->Free(); - ChipLogError(Inet, "Internal logic error: insufficient space to store active connection"); - } + ChipLogError(Inet, "Connection establishment with %s encountered an error: %" CHIP_ERROR_FORMAT, addrStr, err.Format()); + endPoint->Free(); + tcp->mUsedEndPointCount--; } } -void TCPBase::OnConnectionClosed(Inet::TCPEndPoint * endPoint, CHIP_ERROR err) +void TCPBase::HandleTCPEndPointConnectionClosed(Inet::TCPEndPoint * endPoint, CHIP_ERROR err) { - TCPBase * tcp = reinterpret_cast(endPoint->mAppState); + TCPBase * tcp = reinterpret_cast(endPoint->mAppState); + ActiveTCPConnectionState * activeConnection = tcp->FindInUseConnection(endPoint); - ChipLogProgress(Inet, "Connection closed."); + if (activeConnection == nullptr) + { + endPoint->Free(); + return; + } - ChipLogProgress(Inet, "Freeing closed connection."); - tcp->ReleaseActiveConnection(endPoint); + if (err == CHIP_NO_ERROR && activeConnection->IsConnected()) + { + err = CHIP_ERROR_CONNECTION_CLOSED_UNEXPECTEDLY; + } + + tcp->CloseConnectionInternal(activeConnection, err, SuppressCallback::No); } -void TCPBase::OnConnectionReceived(Inet::TCPEndPoint * listenEndPoint, Inet::TCPEndPoint * endPoint, - const Inet::IPAddress & peerAddress, uint16_t peerPort) +// Handler for incoming connection requests from peer nodes +void TCPBase::HandleIncomingConnection(Inet::TCPEndPoint * listenEndPoint, Inet::TCPEndPoint * endPoint, + const Inet::IPAddress & peerAddress, uint16_t peerPort) { - TCPBase * tcp = reinterpret_cast(listenEndPoint->mAppState); + TCPBase * tcp = reinterpret_cast(listenEndPoint->mAppState); + ActiveTCPConnectionState * activeConnection = nullptr; + Inet::InterfaceId interfaceId; + Inet::IPAddress ipAddress; + uint16_t port; + + endPoint->GetPeerInfo(&ipAddress, &port); + endPoint->GetInterfaceId(&interfaceId); + PeerAddress addr = PeerAddress::TCP(ipAddress, port, interfaceId); if (tcp->mUsedEndPointCount < tcp->mActiveConnectionsSize) { - // have space to use one more (even if considering pending connections) - for (size_t i = 0; i < tcp->mActiveConnectionsSize; i++) - { - if (!tcp->mActiveConnections[i].InUse()) - { - tcp->mActiveConnections[i].Init(endPoint); - tcp->mUsedEndPointCount++; - break; - } - } + activeConnection = tcp->AllocateConnection(); + + endPoint->mAppState = listenEndPoint->mAppState; + endPoint->OnDataReceived = HandleTCPEndPointDataReceived; + endPoint->OnDataSent = nullptr; + endPoint->OnConnectionClosed = HandleTCPEndPointConnectionClosed; + + // By default, disable TCP Nagle buffering by setting TCP_NODELAY socket option to true + endPoint->EnableNoDelay(); - endPoint->mAppState = listenEndPoint->mAppState; - endPoint->OnDataReceived = OnTcpReceive; - endPoint->OnConnectComplete = OnConnectionComplete; - endPoint->OnConnectionClosed = OnConnectionClosed; - endPoint->OnConnectionReceived = OnConnectionReceived; - endPoint->OnAcceptError = OnAcceptError; - endPoint->OnPeerClose = OnPeerClosed; + // Update state for the active connection + activeConnection->Init(endPoint, addr); + tcp->mUsedEndPointCount++; + activeConnection->mConnectionState = TCPState::kConnected; + + char addrStr[Transport::PeerAddress::kMaxToStringSize]; + peerAddress.ToString(addrStr); + ChipLogProgress(Inet, "Incoming connection established with peer at %s.", addrStr); + + // Call the upper layer handler for incoming connection received. + tcp->HandleConnectionReceived(activeConnection); } else { - ChipLogError(Inet, "Insufficient connection space to accept new connections"); + ChipLogError(Inet, "Insufficient connection space to accept new connections."); endPoint->Free(); + listenEndPoint->OnAcceptError(endPoint, CHIP_ERROR_TOO_MANY_CONNECTIONS); } } -void TCPBase::OnAcceptError(Inet::TCPEndPoint * endPoint, CHIP_ERROR err) +void TCPBase::HandleAcceptError(Inet::TCPEndPoint * endPoint, CHIP_ERROR err) +{ + endPoint->Free(); + ChipLogError(Inet, "Accept error: %" CHIP_ERROR_FORMAT, err.Format()); +} + +CHIP_ERROR TCPBase::TCPConnect(const PeerAddress & address, Transport::AppTCPConnectionCallbackCtxt * appState, + Transport::ActiveTCPConnectionState ** outPeerConnState) { - ChipLogError(Inet, "Accept error: %s", ErrorStr(err)); + VerifyOrReturnError(mState == TCPState::kInitialized, CHIP_ERROR_INCORRECT_STATE); + + // Verify that PeerAddress AddressType is TCP + VerifyOrReturnError(address.GetTransportType() == Transport::Type::kTcp, CHIP_ERROR_INVALID_ARGUMENT); + + VerifyOrReturnError(mUsedEndPointCount < mActiveConnectionsSize, CHIP_ERROR_NO_MEMORY); + + char addrStr[Transport::PeerAddress::kMaxToStringSize]; + address.ToString(addrStr); + ChipLogProgress(Inet, "Connecting to peer %s.", addrStr); + + ReturnErrorOnFailure(StartConnect(address, appState, outPeerConnState)); + + return CHIP_NO_ERROR; } -void TCPBase::Disconnect(const PeerAddress & address) +void TCPBase::TCPDisconnect(const PeerAddress & address) { + CHIP_ERROR err = CHIP_NO_ERROR; // Closes an existing connection for (size_t i = 0; i < mActiveConnectionsSize; i++) { - if (mActiveConnections[i].InUse()) + if (mActiveConnections[i].IsConnected()) { Inet::IPAddress ipAddress; uint16_t port; Inet::InterfaceId interfaceId; - mActiveConnections[i].mEndPoint->GetPeerInfo(&ipAddress, &port); - mActiveConnections[i].mEndPoint->GetInterfaceId(&interfaceId); - if (address == PeerAddress::TCP(ipAddress, port, interfaceId)) + err = mActiveConnections[i].mEndPoint->GetPeerInfo(&ipAddress, &port); + if (err != CHIP_NO_ERROR) + { + ChipLogError(Inet, "TCPDisconnect: GetPeerInfo error: %" CHIP_ERROR_FORMAT, err.Format()); + return; + } + + err = mActiveConnections[i].mEndPoint->GetInterfaceId(&interfaceId); + if (err != CHIP_NO_ERROR) + { + ChipLogError(Inet, "TCPDisconnect: GetInterfaceId error: %" CHIP_ERROR_FORMAT, err.Format()); + return; + } + // if (address == PeerAddress::TCP(ipAddress, port, interfaceId)) + if (ipAddress == address.GetIPAddress() && port == address.GetPort()) { + char addrStr[Transport::PeerAddress::kMaxToStringSize]; + address.ToString(addrStr); + ChipLogProgress(Inet, "Disconnecting with peer %s.", addrStr); + // NOTE: this leaves the socket in TIME_WAIT. // Calling Abort() would clean it since SO_LINGER would be set to 0, // however this seems not to be useful. - mActiveConnections[i].Free(); - mUsedEndPointCount--; + CloseConnectionInternal(&mActiveConnections[i], CHIP_NO_ERROR, SuppressCallback::Yes); } } } } -void TCPBase::OnPeerClosed(Inet::TCPEndPoint * endPoint) +void TCPBase::TCPDisconnect(Transport::ActiveTCPConnectionState * conn, bool shouldAbort) { - TCPBase * tcp = reinterpret_cast(endPoint->mAppState); - ChipLogProgress(Inet, "Freeing connection: connection closed by peer"); + if (conn == nullptr) + { + ChipLogError(Inet, "Failed to Disconnect. Passed in Connection is null."); + return; + } - tcp->ReleaseActiveConnection(endPoint); + // This call should be able to disconnect the connection either when it is + // already established, or when it is being set up. + if ((conn->IsConnected() && shouldAbort) || conn->IsConnecting()) + { + CloseConnectionInternal(conn, CHIP_ERROR_CONNECTION_ABORTED, SuppressCallback::Yes); + } + + if (conn->IsConnected() && !shouldAbort) + { + CloseConnectionInternal(conn, CHIP_NO_ERROR, SuppressCallback::Yes); + } } bool TCPBase::HasActiveConnections() const { for (size_t i = 0; i < mActiveConnectionsSize; i++) { - if (mActiveConnections[i].InUse()) + if (mActiveConnections[i].IsConnected()) { return true; } diff --git a/src/transport/raw/TCP.h b/src/transport/raw/TCP.h index d9f78be1771b0f..bb4671215b96c8 100644 --- a/src/transport/raw/TCP.h +++ b/src/transport/raw/TCP.h @@ -34,7 +34,9 @@ #include #include #include +#include #include +#include namespace chip { namespace Transport { @@ -96,45 +98,23 @@ struct PendingPacket /** Implements a transport using TCP. */ class DLL_EXPORT TCPBase : public Base { - /** - * The State of the TCP connection - */ - enum class State - { - kNotReady = 0, /**< State before initialization. */ - kInitialized = 1, /**< State after class is listening and ready. */ - }; protected: - /** - * State for each active connection - */ - struct ActiveConnectionState + enum class ShouldAbort : uint8_t { - void Init(Inet::TCPEndPoint * endPoint) - { - mEndPoint = endPoint; - mReceived = nullptr; - } - - void Free() - { - mEndPoint->Free(); - mEndPoint = nullptr; - mReceived = nullptr; - } - bool InUse() const { return mEndPoint != nullptr; } - - // Associated endpoint. - Inet::TCPEndPoint * mEndPoint; + Yes, + No + }; - // Buffers received but not yet consumed. - System::PacketBufferHandle mReceived; + enum class SuppressCallback : uint8_t + { + Yes, + No }; public: using PendingPacketPoolType = PoolInterface; - TCPBase(ActiveConnectionState * activeConnectionsBuffer, size_t bufferSize, PendingPacketPoolType & packetBuffers) : + TCPBase(ActiveTCPConnectionState * activeConnectionsBuffer, size_t bufferSize, PendingPacketPoolType & packetBuffers) : mActiveConnections(activeConnectionsBuffer), mActiveConnectionsSize(bufferSize), mPendingPackets(packetBuffers) { // activeConnectionsBuffer must be initialized by the caller. @@ -153,6 +133,13 @@ class DLL_EXPORT TCPBase : public Base */ CHIP_ERROR Init(TcpListenParameters & params); + /** + * Set the timeout (in milliseconds) for the node to wait for the TCP + * connection attempt to complete. + * + */ + void SetConnectTimeout(const uint32_t connTimeoutMsecs) { mConnectTimeout = connTimeoutMsecs; } + /** * Close the open endpoint without destroying the object */ @@ -160,14 +147,46 @@ class DLL_EXPORT TCPBase : public Base CHIP_ERROR SendMessage(const PeerAddress & address, System::PacketBufferHandle && msgBuf) override; - void Disconnect(const PeerAddress & address) override; + /* + * Connect to the given peerAddress over TCP. + * + * @param address The address of the peer. + * + * @param appState Context passed in by the application to be sent back + * via the connection attempt complete callback when + * connection attempt with peer completes. + * + * @param outPeerConnState Pointer to pointer to the active TCP connection state. This is + * an output parameter that is allocated by the + * transport layer and held by the caller object. + * This allows the caller object to abort the + * connection attempt if the caller object dies + * before the attempt completes. + * + */ + CHIP_ERROR TCPConnect(const PeerAddress & address, Transport::AppTCPConnectionCallbackCtxt * appState, + Transport::ActiveTCPConnectionState ** outPeerConnState) override; + + void TCPDisconnect(const PeerAddress & address) override; + + // Close an active connection (corresponding to the passed + // ActiveTCPConnectionState object) + // and release from the pool. + void TCPDisconnect(Transport::ActiveTCPConnectionState * conn, bool shouldAbort = false) override; bool CanSendToPeer(const PeerAddress & address) override { - return (mState == State::kInitialized) && (address.GetTransportType() == Type::kTcp) && + return (mState == TCPState::kInitialized) && (address.GetTransportType() == Type::kTcp) && (address.GetIPAddress().Type() == mEndpointType); } + const Optional GetConnectionPeerAddress(const Inet::TCPEndPoint * con) + { + ActiveTCPConnectionState * activeConState = FindActiveConnection(con); + + return activeConState != nullptr ? MakeOptional(activeConState->mPeerAddr) : Optional::Missing(); + } + /** * Helper method to determine if IO processing is still required for a TCP transport * before everything is cleaned up (socket closing is async, so after calling 'Close' on @@ -183,12 +202,22 @@ class DLL_EXPORT TCPBase : public Base private: friend class TCPTest; + /** + * Allocate an unused connection from the pool + * + */ + ActiveTCPConnectionState * AllocateConnection(); /** * Find an active connection to the given peer or return nullptr if * no active connection exists. */ - ActiveConnectionState * FindActiveConnection(const PeerAddress & addr); - ActiveConnectionState * FindActiveConnection(const Inet::TCPEndPoint * endPoint); + ActiveTCPConnectionState * FindActiveConnection(const PeerAddress & addr); + ActiveTCPConnectionState * FindActiveConnection(const Inet::TCPEndPoint * endPoint); + + /** + * Find an allocated connection that matches the corresponding TCPEndPoint. + */ + ActiveTCPConnectionState * FindInUseConnection(const Inet::TCPEndPoint * endPoint); /** * Sends the specified message once a connection has been established. @@ -223,46 +252,63 @@ class DLL_EXPORT TCPBase : public Base * is no other data). * @param[in] messageSize Size of the single message. */ - CHIP_ERROR ProcessSingleMessage(const PeerAddress & peerAddress, ActiveConnectionState * state, uint16_t messageSize); + CHIP_ERROR ProcessSingleMessage(const PeerAddress & peerAddress, ActiveTCPConnectionState * state, uint16_t messageSize); - // Release an active connection (corresponding to the passed TCPEndPoint) - // from the pool. - void ReleaseActiveConnection(Inet::TCPEndPoint * endPoint); + /** + * Initiate a connection to the given peer. On connection completion, + * HandleTCPConnectComplete callback would be called. + * + */ + CHIP_ERROR StartConnect(const PeerAddress & addr, AppTCPConnectionCallbackCtxt * appState, + Transport::ActiveTCPConnectionState ** outPeerConnState); + + /** + * Gracefully Close or Abort a given connection. + * + */ + void CloseConnectionInternal(ActiveTCPConnectionState * connection, CHIP_ERROR err, SuppressCallback suppressCallback); + + // Close the listening socket endpoint + void CloseListeningSocket(); // Callback handler for TCPEndPoint. TCP message receive handler. // @see TCPEndpoint::OnDataReceivedFunct - static CHIP_ERROR OnTcpReceive(Inet::TCPEndPoint * endPoint, System::PacketBufferHandle && buffer); + static CHIP_ERROR HandleTCPEndPointDataReceived(Inet::TCPEndPoint * endPoint, System::PacketBufferHandle && buffer); // Callback handler for TCPEndPoint. Called when a connection has been completed. // @see TCPEndpoint::OnConnectCompleteFunct - static void OnConnectionComplete(Inet::TCPEndPoint * endPoint, CHIP_ERROR err); + static void HandleTCPEndPointConnectComplete(Inet::TCPEndPoint * endPoint, CHIP_ERROR err); // Callback handler for TCPEndPoint. Called when a connection has been closed. // @see TCPEndpoint::OnConnectionClosedFunct - static void OnConnectionClosed(Inet::TCPEndPoint * endPoint, CHIP_ERROR err); - - // Callback handler for TCPEndPoint. Callend when a peer closes the connection. - // @see TCPEndpoint::OnPeerCloseFunct - static void OnPeerClosed(Inet::TCPEndPoint * endPoint); + static void HandleTCPEndPointConnectionClosed(Inet::TCPEndPoint * endPoint, CHIP_ERROR err); // Callback handler for TCPEndPoint. Called when a connection is received on the listening port. // @see TCPEndpoint::OnConnectionReceivedFunct - static void OnConnectionReceived(Inet::TCPEndPoint * listenEndPoint, Inet::TCPEndPoint * endPoint, - const Inet::IPAddress & peerAddress, uint16_t peerPort); + static void HandleIncomingConnection(Inet::TCPEndPoint * listenEndPoint, Inet::TCPEndPoint * endPoint, + const Inet::IPAddress & peerAddress, uint16_t peerPort); - // Called on accept error + // Callback handler for handling accept error // @see TCPEndpoint::OnAcceptErrorFunct - static void OnAcceptError(Inet::TCPEndPoint * endPoint, CHIP_ERROR err); + static void HandleAcceptError(Inet::TCPEndPoint * endPoint, CHIP_ERROR err); Inet::TCPEndPoint * mListenSocket = nullptr; ///< TCP socket used by the transport Inet::IPAddressType mEndpointType = Inet::IPAddressType::kUnknown; ///< Socket listening type - State mState = State::kNotReady; ///< State of the TCP transport + TCPState mState = TCPState::kNotReady; ///< State of the TCP transport + + // The configured timeout for the connection attempt to the peer, before + // giving up. + uint32_t mConnectTimeout = CHIP_CONFIG_TCP_CONNECT_TIMEOUT_MSECS; + + // The max payload size of data over a TCP connection that is transmissible + // at a time. + uint32_t mMaxTCPPayloadSize = CHIP_CONFIG_MAX_TCP_PAYLOAD_SIZE_BYTES; // Number of active and 'pending connection' endpoints size_t mUsedEndPointCount = 0; // Currently active connections - ActiveConnectionState * mActiveConnections; + ActiveTCPConnectionState * mActiveConnections; const size_t mActiveConnectionsSize; // Data to be sent when connections succeed @@ -277,14 +323,15 @@ class TCP : public TCPBase { for (size_t i = 0; i < kActiveConnectionsSize; ++i) { - mConnectionsBuffer[i].Init(nullptr); + mConnectionsBuffer[i].Init(nullptr, PeerAddress::Uninitialized()); } } + ~TCP() override { mPendingPackets.ReleaseAll(); } private: friend class TCPTest; - TCPBase::ActiveConnectionState mConnectionsBuffer[kActiveConnectionsSize]; + ActiveTCPConnectionState mConnectionsBuffer[kActiveConnectionsSize]; PoolImpl mPendingPackets; }; diff --git a/src/transport/raw/TCPConfig.h b/src/transport/raw/TCPConfig.h new file mode 100644 index 00000000000000..d54a9466b4d294 --- /dev/null +++ b/src/transport/raw/TCPConfig.h @@ -0,0 +1,127 @@ +/* + * + * Copyright (c) 2023 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file + * This file defines default compile-time configuration constants + * for CHIP. + * + * Package integrators that wish to override these values should + * either use preprocessor definitions or create a project- + * specific chipProjectConfig.h header and then assert + * HAVE_CHIPPROJECTCONFIG_H via the package configuration tool + * via --with-chip-project-includes=DIR where DIR is the + * directory that contains the header. + * + * + */ + +#pragma once + +#include + +namespace chip { + +/** + * @def CHIP_CONFIG_MAX_ACTIVE_TCP_CONNECTIONS + * + * @brief Maximum Number of TCP connections a device can simultaneously have + */ +#ifndef CHIP_CONFIG_MAX_ACTIVE_TCP_CONNECTIONS +#define CHIP_CONFIG_MAX_ACTIVE_TCP_CONNECTIONS 4 +#endif + +#if INET_CONFIG_ENABLE_TCP_ENDPOINT && CHIP_CONFIG_MAX_ACTIVE_TCP_CONNECTIONS < 1 +#error "If TCP is enabled, the device needs to support at least 1 TCP connection" +#endif + +#if INET_CONFIG_ENABLE_TCP_ENDPOINT && CHIP_CONFIG_MAX_ACTIVE_TCP_CONNECTIONS > INET_CONFIG_NUM_TCP_ENDPOINTS +#error "If TCP is enabled, the maximum number of connections cannot exceed the number of tcp endpoints" +#endif + +/** + * @def CHIP_CONFIG_MAX_TCP_PENDING_PACKETS + * + * @brief Maximum Number of outstanding pending packets in the queue before a TCP connection + * needs to be established + */ +#ifndef CHIP_CONFIG_MAX_TCP_PENDING_PACKETS +#define CHIP_CONFIG_MAX_TCP_PENDING_PACKETS 4 +#endif + +/** + * @def CHIP_CONFIG_MAX_TCP_PAYLOAD_SIZE_BYTES + * + * @brief Maximum payload size of a message over a TCP connection + */ +#ifndef CHIP_CONFIG_MAX_TCP_PAYLOAD_SIZE_BYTES +#define CHIP_CONFIG_MAX_TCP_PAYLOAD_SIZE_BYTES 1000000 +#endif + +/** + * @def CHIP_CONFIG_TCP_CONNECT_TIMEOUT_MSECS + * + * @brief + * This defines the default timeout for the TCP connect + * attempt to either succeed or notify the caller of an + * error. + * + */ +#ifndef CHIP_CONFIG_TCP_CONNECT_TIMEOUT_MSECS +#define CHIP_CONFIG_TCP_CONNECT_TIMEOUT_MSECS (10000) +#endif // CHIP_CONFIG_TCP_CONNECT_TIMEOUT_MSECS + +/** + * @def CHIP_CONFIG_KEEPALIVE_INTERVAL_SECS + * + * @brief + * This defines the default interval (in seconds) between + * keepalive probes for a TCP connection. + * This value also controls the time between last data + * packet sent and the transmission of the first keepalive + * probe. + * + */ +#ifndef CHIP_CONFIG_TCP_KEEPALIVE_INTERVAL_SECS +#define CHIP_CONFIG_TCP_KEEPALIVE_INTERVAL_SECS (25) +#endif // CHIP_CONFIG_TCP_KEEPALIVE_INTERVAL_SECS + +/** + * @def CHIP_CONFIG_MAX_TCP_KEEPALIVE_PROBES + * + * @brief + * This defines the default value for the maximum number of + * keepalive probes for a TCP connection. + * + */ +#ifndef CHIP_CONFIG_MAX_TCP_KEEPALIVE_PROBES +#define CHIP_CONFIG_MAX_TCP_KEEPALIVE_PROBES (5) +#endif // CHIP_CONFIG_MAX_TCP_KEEPALIVE_PROBES + +/** + * @def CHIP_CONFIG_MAX_UNACKED_DATA_TIMEOUT_SECS + * + * @brief + * This defines the default value for the maximum timeout + * of unacknowledged data for a TCP connection. + * + */ +#ifndef CHIP_CONFIG_MAX_UNACKED_DATA_TIMEOUT_SECS +#define CHIP_CONFIG_MAX_UNACKED_DATA_TIMEOUT_SECS (30) +#endif // CHIP_CONFIG_MAX_UNACKED_DATA_TIMEOUT_SECS + +} // namespace chip diff --git a/src/transport/raw/Tuple.h b/src/transport/raw/Tuple.h index 743b9b9b0e09aa..e3e52a171abcda 100644 --- a/src/transport/raw/Tuple.h +++ b/src/transport/raw/Tuple.h @@ -93,7 +93,20 @@ class Tuple : public Base bool CanSendToPeer(const PeerAddress & address) override { return CanSendToPeerImpl<0>(address); } - void Disconnect(const PeerAddress & address) override { return DisconnectImpl<0>(address); } +#if INET_CONFIG_ENABLE_TCP_ENDPOINT + CHIP_ERROR TCPConnect(const PeerAddress & address, Transport::AppTCPConnectionCallbackCtxt * appState, + Transport::ActiveTCPConnectionState ** peerConnState) override + { + return TCPConnectImpl<0>(address, appState, peerConnState); + } + + void TCPDisconnect(const PeerAddress & address) override { return TCPDisconnectImpl<0>(address); } + + void TCPDisconnect(Transport::ActiveTCPConnectionState * conn, bool shouldAbort = 0) override + { + return TCPDisconnectImpl<0>(conn, shouldAbort); + } +#endif // INET_CONFIG_ENABLE_TCP_ENDPOINT void Close() override { return CloseImpl<0>(); } @@ -138,26 +151,78 @@ class Tuple : public Base return false; } +#if INET_CONFIG_ENABLE_TCP_ENDPOINT + /** + * Recursive TCPConnect implementation iterating through transport members. + * + * @tparam N the index of the underlying transport to send disconnect to + * + * @param address what address to connect to. + */ + template ::type * = nullptr> + CHIP_ERROR TCPConnectImpl(const PeerAddress & address, Transport::AppTCPConnectionCallbackCtxt * appState, + Transport::ActiveTCPConnectionState ** peerConnState) + { + Base * base = &std::get(mTransports); + if (base->CanSendToPeer(address)) + { + return base->TCPConnect(address, appState, peerConnState); + } + return TCPConnectImpl(address, appState, peerConnState); + } + + /** + * TCPConnectImpl template for out of range N. + */ + template = sizeof...(TransportTypes))>::type * = nullptr> + CHIP_ERROR TCPConnectImpl(const PeerAddress & address, Transport::AppTCPConnectionCallbackCtxt * appState, + Transport::ActiveTCPConnectionState ** peerConnState) + { + return CHIP_ERROR_NO_MESSAGE_HANDLER; + } + /** * Recursive disconnect implementation iterating through transport members. * * @tparam N the index of the underlying transport to send disconnect to * - * @param address what address to check. + * @param address what address to disconnect from. + */ + template ::type * = nullptr> + void TCPDisconnectImpl(const PeerAddress & address) + { + std::get(mTransports).TCPDisconnect(address); + TCPDisconnectImpl(address); + } + + /** + * TCPDisconnectImpl template for out of range N. + */ + template = sizeof...(TransportTypes))>::type * = nullptr> + void TCPDisconnectImpl(const PeerAddress & address) + {} + + /** + * Recursive disconnect implementation iterating through transport members. + * + * @tparam N the index of the underlying transport to send disconnect to + * + * @param conn pointer to the connection to the peer. */ template ::type * = nullptr> - void DisconnectImpl(const PeerAddress & address) + void TCPDisconnectImpl(Transport::ActiveTCPConnectionState * conn, bool shouldAbort = 0) { - std::get(mTransports).Disconnect(address); - DisconnectImpl(address); + std::get(mTransports).TCPDisconnect(conn, shouldAbort); + TCPDisconnectImpl(conn, shouldAbort); } /** - * DisconnectImpl template for out of range N. + * TCPDisconnectImpl template for out of range N. */ template = sizeof...(TransportTypes))>::type * = nullptr> - void DisconnectImpl(const PeerAddress & address) + void TCPDisconnectImpl(Transport::ActiveTCPConnectionState * conn, bool shouldAbort = 0) {} +#endif // INET_CONFIG_ENABLE_TCP_ENDPOINT /** * Recursive disconnect implementation iterating through transport members. diff --git a/src/transport/raw/tests/BUILD.gn b/src/transport/raw/tests/BUILD.gn index c655586c5a0e35..973626af7f340b 100644 --- a/src/transport/raw/tests/BUILD.gn +++ b/src/transport/raw/tests/BUILD.gn @@ -14,7 +14,9 @@ import("//build_overrides/build.gni") import("//build_overrides/chip.gni") +import("//build_overrides/nlunit_test.gni") import("//build_overrides/pigweed.gni") +import("${chip_root}/src/inet/inet.gni") import("${chip_root}/build/chip/chip_test_suite.gni") static_library("helpers") { @@ -40,10 +42,13 @@ chip_test_suite("tests") { test_sources = [ "TestMessageHeader.cpp", "TestPeerAddress.cpp", - "TestTCP.cpp", "TestUDP.cpp", ] + if (chip_inet_config_enable_tcp_endpoint) { + test_sources += [ "TestTCP.cpp" ] + } + public_deps = [ ":helpers", "${chip_root}/src/inet/tests:helpers", diff --git a/src/transport/raw/tests/TestTCP.cpp b/src/transport/raw/tests/TestTCP.cpp index 93414e01e3d653..6a60fb330c70f7 100644 --- a/src/transport/raw/tests/TestTCP.cpp +++ b/src/transport/raw/tests/TestTCP.cpp @@ -23,6 +23,7 @@ #include "NetworkTestHelpers.h" +#include #include #include #include @@ -30,7 +31,9 @@ #include #include #include +#if INET_CONFIG_ENABLE_TCP_ENDPOINT #include +#endif // INET_CONFIG_ENABLE_TCP_ENDPOINT #include @@ -47,6 +50,9 @@ namespace { constexpr size_t kMaxTcpActiveConnectionCount = 4; constexpr size_t kMaxTcpPendingPackets = 4; constexpr uint16_t kPacketSizeBytes = static_cast(sizeof(uint16_t)); +uint16_t gChipTCPPort = static_cast(CHIP_PORT + chip::Crypto::GetRandU16() % 100); +chip::Transport::AppTCPConnectionCallbackCtxt gAppTCPConnCbCtxt; +chip::Transport::ActiveTCPConnectionState * gActiveTCPConnState = nullptr; using TCPImpl = Transport::TCP; @@ -71,7 +77,8 @@ class MockTransportMgrDelegate : public chip::TransportMgrDelegate mCallback = callback; mCallbackData = callback_data; } - void OnMessageReceived(const Transport::PeerAddress & source, System::PacketBufferHandle && msgBuf) override + void OnMessageReceived(const Transport::PeerAddress & source, System::PacketBufferHandle && msgBuf, + Transport::MessageTransportContext * transCtxt = nullptr) override { PacketHeader packetHeader; @@ -82,12 +89,54 @@ class MockTransportMgrDelegate : public chip::TransportMgrDelegate EXPECT_EQ(mCallback(msgBuf->Start(), msgBuf->DataLength(), mReceiveHandlerCallCount, mCallbackData), 0); } + ChipLogProgress(Inet, "Message Receive Handler called"); + mReceiveHandlerCallCount++; } + void HandleConnectionAttemptComplete(chip::Transport::ActiveTCPConnectionState * conn, CHIP_ERROR conErr) override + { + chip::Transport::AppTCPConnectionCallbackCtxt * appConnCbCtxt = nullptr; + VerifyOrReturn(conn != nullptr); + + mHandleConnectionCompleteCalled = true; + appConnCbCtxt = conn->mAppState; + VerifyOrReturn(appConnCbCtxt != nullptr); + + if (appConnCbCtxt->connCompleteCb != nullptr) + { + appConnCbCtxt->connCompleteCb(conn, conErr); + } + else + { + ChipLogProgress(Inet, "Connection established. App callback missing."); + } + } + + void HandleConnectionClosed(chip::Transport::ActiveTCPConnectionState * conn, CHIP_ERROR conErr) override + { + chip::Transport::AppTCPConnectionCallbackCtxt * appConnCbCtxt = nullptr; + VerifyOrReturn(conn != nullptr); + + mHandleConnectionCloseCalled = true; + appConnCbCtxt = conn->mAppState; + VerifyOrReturn(appConnCbCtxt != nullptr); + + if (appConnCbCtxt->connClosedCb != nullptr) + { + appConnCbCtxt->connClosedCb(conn, conErr); + } + else + { + ChipLogProgress(Inet, "Connection Closed. App callback missing."); + } + } + void InitializeMessageTest(TCPImpl & tcp, const IPAddress & addr) { - CHIP_ERROR err = tcp.Init(Transport::TcpListenParameters(mContext->GetTCPEndPointManager()).SetAddressType(addr.Type())); + CHIP_ERROR err = tcp.Init(Transport::TcpListenParameters(mContext->GetTCPEndPointManager()) + .SetAddressType(addr.Type()) + .SetListenPort(gChipTCPPort)); // retry a few times in case the port is somehow in use. // this is a WORKAROUND for flaky testing if we run tests very fast after each other. @@ -106,7 +155,9 @@ class MockTransportMgrDelegate : public chip::TransportMgrDelegate { ChipLogProgress(NotSpecified, "RETRYING tcp initialization"); chip::test_utils::SleepMillis(100); - err = tcp.Init(Transport::TcpListenParameters(mContext->GetTCPEndPointManager()).SetAddressType(addr.Type())); + err = tcp.Init(Transport::TcpListenParameters(mContext->GetTCPEndPointManager()) + .SetAddressType(addr.Type()) + .SetListenPort(gChipTCPPort)); } EXPECT_EQ(err, CHIP_NO_ERROR); @@ -114,7 +165,14 @@ class MockTransportMgrDelegate : public chip::TransportMgrDelegate mTransportMgrBase.SetSessionManager(this); mTransportMgrBase.Init(&tcp); - mReceiveHandlerCallCount = 0; + mReceiveHandlerCallCount = 0; + mHandleConnectionCompleteCalled = false; + mHandleConnectionCloseCalled = false; + + gAppTCPConnCbCtxt.appContext = nullptr; + gAppTCPConnCbCtxt.connReceivedCb = nullptr; + gAppTCPConnCbCtxt.connCompleteCb = nullptr; + gAppTCPConnCbCtxt.connClosedCb = nullptr; } void SingleMessageTest(TCPImpl & tcp, const IPAddress & addr) @@ -132,7 +190,7 @@ class MockTransportMgrDelegate : public chip::TransportMgrDelegate EXPECT_EQ(err, CHIP_NO_ERROR); // Should be able to send a message to itself by just calling send. - err = tcp.SendMessage(Transport::PeerAddress::TCP(addr), std::move(buffer)); + err = tcp.SendMessage(Transport::PeerAddress::TCP(addr, gChipTCPPort), std::move(buffer)); EXPECT_EQ(err, CHIP_NO_ERROR); mContext->DriveIOUntil(chip::System::Clock::Seconds16(5), [this]() { return mReceiveHandlerCallCount != 0; }); @@ -141,39 +199,114 @@ class MockTransportMgrDelegate : public chip::TransportMgrDelegate SetCallback(nullptr); } - void FinalizeMessageTest(TCPImpl & tcp, const IPAddress & addr) + void ConnectTest(TCPImpl & tcp, const IPAddress & addr) + { + // Connect and wait for seeing active connection + CHIP_ERROR err = tcp.TCPConnect(Transport::PeerAddress::TCP(addr, gChipTCPPort), &gAppTCPConnCbCtxt, &gActiveTCPConnState); + EXPECT_EQ(err, CHIP_NO_ERROR); + + mContext->DriveIOUntil(chip::System::Clock::Seconds16(5), [&tcp]() { return tcp.HasActiveConnections(); }); + EXPECT_EQ(tcp.HasActiveConnections(), true); + } + + void HandleConnectCompleteCbCalledTest(TCPImpl & tcp, const IPAddress & addr) + { + // Connect and wait for seeing active connection and connection complete + // handler being called. + CHIP_ERROR err = tcp.TCPConnect(Transport::PeerAddress::TCP(addr, gChipTCPPort), &gAppTCPConnCbCtxt, &gActiveTCPConnState); + EXPECT_EQ(err, CHIP_NO_ERROR); + + mContext->DriveIOUntil(chip::System::Clock::Seconds16(5), [this]() { return mHandleConnectionCompleteCalled; }); + EXPECT_EQ(mHandleConnectionCompleteCalled, true); + } + + void HandleConnectCloseCbCalledTest(TCPImpl & tcp, const IPAddress & addr) + { + // Connect and wait for seeing active connection and connection complete + // handler being called. + CHIP_ERROR err = tcp.TCPConnect(Transport::PeerAddress::TCP(addr, gChipTCPPort), &gAppTCPConnCbCtxt, &gActiveTCPConnState); + EXPECT_EQ(err, CHIP_NO_ERROR); + + mContext->DriveIOUntil(chip::System::Clock::Seconds16(5), [this]() { return mHandleConnectionCompleteCalled; }); + EXPECT_EQ(mHandleConnectionCompleteCalled, true); + + tcp.TCPDisconnect(Transport::PeerAddress::TCP(addr, gChipTCPPort)); + mContext->DriveIOUntil(chip::System::Clock::Seconds16(5), [&tcp]() { return !tcp.HasActiveConnections(); }); + EXPECT_EQ(mHandleConnectionCloseCalled, true); + } + + void DisconnectTest(TCPImpl & tcp, chip::Transport::ActiveTCPConnectionState * conn) { // Disconnect and wait for seeing peer close - tcp.Disconnect(Transport::PeerAddress::TCP(addr)); + tcp.TCPDisconnect(conn, true); mContext->DriveIOUntil(chip::System::Clock::Seconds16(5), [&tcp]() { return !tcp.HasActiveConnections(); }); + EXPECT_EQ(tcp.HasActiveConnections(), false); + } + + void DisconnectTest(TCPImpl & tcp, const IPAddress & addr) + { + // Disconnect and wait for seeing peer close + tcp.TCPDisconnect(Transport::PeerAddress::TCP(addr, gChipTCPPort)); + mContext->DriveIOUntil(chip::System::Clock::Seconds16(5), [&tcp]() { return !tcp.HasActiveConnections(); }); + EXPECT_EQ(tcp.HasActiveConnections(), false); + } + + CHIP_ERROR TCPConnect(const Transport::PeerAddress & peerAddress, Transport::AppTCPConnectionCallbackCtxt * appState, + Transport::ActiveTCPConnectionState ** peerConnState) + { + return mTransportMgrBase.TCPConnect(peerAddress, appState, peerConnState); + } + + using OnTCPConnectionReceivedCallback = void (*)(void * context, chip::Transport::ActiveTCPConnectionState * conn); + + using OnTCPConnectionCompleteCallback = void (*)(void * context, chip::Transport::ActiveTCPConnectionState * conn, + CHIP_ERROR conErr); + + using OnTCPConnectionClosedCallback = void (*)(void * context, chip::Transport::ActiveTCPConnectionState * conn, + CHIP_ERROR conErr); + + void SetConnectionCallbacks(OnTCPConnectionCompleteCallback connCompleteCb, OnTCPConnectionClosedCallback connClosedCb, + OnTCPConnectionReceivedCallback connReceivedCb) + { + mConnCompleteCb = connCompleteCb; + mConnClosedCb = connClosedCb; + mConnReceivedCb = connReceivedCb; } int mReceiveHandlerCallCount = 0; + bool mHandleConnectionCompleteCalled = false; + + bool mHandleConnectionCloseCalled = false; + private: TestContext * mContext; MessageReceivedCallback mCallback; void * mCallbackData; TransportMgrBase mTransportMgrBase; + OnTCPConnectionCompleteCallback mConnCompleteCb = nullptr; + OnTCPConnectionClosedCallback mConnClosedCb = nullptr; + OnTCPConnectionReceivedCallback mConnReceivedCb = nullptr; }; -/////////////////////////// Init test - class TestTCP : public ::testing::Test, public chip::Test::IOContext { protected: void SetUp() { ASSERT_EQ(Init(), CHIP_NO_ERROR); } void TearDown() { Shutdown(); } + /////////////////////////// Init test void CheckSimpleInitTest(Inet::IPAddressType type) { TCPImpl tcp; - CHIP_ERROR err = tcp.Init(Transport::TcpListenParameters(GetTCPEndPointManager()).SetAddressType(type)); + CHIP_ERROR err = + tcp.Init(Transport::TcpListenParameters(GetTCPEndPointManager()).SetAddressType(type).SetListenPort(gChipTCPPort)); EXPECT_EQ(err, CHIP_NO_ERROR); } + /////////////////////////// Messaging test void CheckMessageTest(const IPAddress & addr) { TCPImpl tcp; @@ -181,7 +314,48 @@ class TestTCP : public ::testing::Test, public chip::Test::IOContext MockTransportMgrDelegate gMockTransportMgrDelegate(this); gMockTransportMgrDelegate.InitializeMessageTest(tcp, addr); gMockTransportMgrDelegate.SingleMessageTest(tcp, addr); - gMockTransportMgrDelegate.FinalizeMessageTest(tcp, addr); + gMockTransportMgrDelegate.DisconnectTest(tcp, addr); + } + + void ConnectToSelfTest(const IPAddress & addr) + { + TCPImpl tcp; + + MockTransportMgrDelegate gMockTransportMgrDelegate(this); + gMockTransportMgrDelegate.InitializeMessageTest(tcp, addr); + gMockTransportMgrDelegate.ConnectTest(tcp, addr); + gMockTransportMgrDelegate.DisconnectTest(tcp, addr); + } + + void ConnectSendMessageThenCloseTest(const IPAddress & addr) + { + TCPImpl tcp; + + MockTransportMgrDelegate gMockTransportMgrDelegate(this); + gMockTransportMgrDelegate.InitializeMessageTest(tcp, addr); + gMockTransportMgrDelegate.ConnectTest(tcp, addr); + gMockTransportMgrDelegate.SingleMessageTest(tcp, addr); + gMockTransportMgrDelegate.DisconnectTest(tcp, addr); + } + + void HandleConnCompleteTest(const IPAddress & addr) + { + TCPImpl tcp; + + MockTransportMgrDelegate gMockTransportMgrDelegate(this); + gMockTransportMgrDelegate.InitializeMessageTest(tcp, addr); + gMockTransportMgrDelegate.HandleConnectCompleteCbCalledTest(tcp, addr); + gMockTransportMgrDelegate.DisconnectTest(tcp, addr); + } + + void HandleConnCloseTest(const IPAddress & addr) + { + TCPImpl tcp; + + MockTransportMgrDelegate gMockTransportMgrDelegate(this); + gMockTransportMgrDelegate.InitializeMessageTest(tcp, addr); + gMockTransportMgrDelegate.HandleConnectCloseCbCalledTest(tcp, addr); + gMockTransportMgrDelegate.DisconnectTest(tcp, addr); } }; @@ -211,6 +385,57 @@ TEST_F(TestTCP, CheckMessageTest6) CheckMessageTest(addr); } +#if INET_CONFIG_ENABLE_IPV4 +TEST_F(TestTCP, ConnectToSelfTest4) +{ + IPAddress addr; + IPAddress::FromString("127.0.0.1", addr); + ConnectToSelfTest(addr); +} + +TEST_F(TestTCP, ConnectSendMessageThenCloseTest4) +{ + IPAddress addr; + IPAddress::FromString("127.0.0.1", addr); + ConnectSendMessageThenCloseTest(addr); +} + +TEST_F(TestTCP, HandleConnCompleteCalledTest4) +{ + IPAddress addr; + IPAddress::FromString("127.0.0.1", addr); + HandleConnCompleteTest(addr); +} +#endif // INET_CONFIG_ENABLE_IPV4 + +TEST_F(TestTCP, ConnectToSelfTest6) +{ + IPAddress addr; + IPAddress::FromString("::1", addr); + ConnectToSelfTest(addr); +} + +TEST_F(TestTCP, ConnectSendMessageThenCloseTest6) +{ + IPAddress addr; + IPAddress::FromString("::1", addr); + ConnectSendMessageThenCloseTest(addr); +} + +TEST_F(TestTCP, HandleConnCompleteCalledTest6) +{ + IPAddress addr; + IPAddress::FromString("::1", addr); + HandleConnCompleteTest(addr); +} + +TEST_F(TestTCP, HandleConnCloseCalledTest6) +{ + IPAddress addr; + IPAddress::FromString("::1", addr); + HandleConnCloseTest(addr); +} + // Generates a packet buffer or a chain of packet buffers for a single message. struct TestData { @@ -381,8 +606,8 @@ class TCPTest // (The current TCPEndPoint implementation is not effectively mockable.) gMockTransportMgrDelegate.SingleMessageTest(tcp, addr); - Transport::PeerAddress lPeerAddress = Transport::PeerAddress::TCP(addr); - TCPBase::ActiveConnectionState * state = tcp.FindActiveConnection(lPeerAddress); + Transport::PeerAddress lPeerAddress = Transport::PeerAddress::TCP(addr, gChipTCPPort); + chip::Transport::ActiveTCPConnectionState * state = tcp.FindActiveConnection(lPeerAddress); ASSERT_NE(state, nullptr); Inet::TCPEndPoint * lEndPoint = state->mEndPoint; ASSERT_NE(lEndPoint, nullptr); @@ -433,7 +658,7 @@ class TCPTest EXPECT_EQ(err, CHIP_ERROR_MESSAGE_TOO_LONG); EXPECT_EQ(gMockTransportMgrDelegate.mReceiveHandlerCallCount, 0); - gMockTransportMgrDelegate.FinalizeMessageTest(tcp, addr); + gMockTransportMgrDelegate.DisconnectTest(tcp, addr); } }; } // namespace Transport diff --git a/src/transport/raw/tests/TestUDP.cpp b/src/transport/raw/tests/TestUDP.cpp index 70077a6fa297e9..6a22a821fdfc94 100644 --- a/src/transport/raw/tests/TestUDP.cpp +++ b/src/transport/raw/tests/TestUDP.cpp @@ -52,7 +52,8 @@ class MockTransportMgrDelegate : public TransportMgrDelegate MockTransportMgrDelegate() {} ~MockTransportMgrDelegate() override {} - void OnMessageReceived(const Transport::PeerAddress & source, System::PacketBufferHandle && msgBuf) override + void OnMessageReceived(const Transport::PeerAddress & source, System::PacketBufferHandle && msgBuf, + Transport::MessageTransportContext * transCtxt = nullptr) override { PacketHeader packetHeader; From 007e11d084abbf88d0d14816d13e15515bf26cb0 Mon Sep 17 00:00:00 2001 From: Amine Alami <43780877+Alami-Amine@users.noreply.github.com> Date: Wed, 1 May 2024 15:10:59 +0200 Subject: [PATCH 20/33] pw_unit_test migration: lib support batch 5 (#33238) * pw_unit_test migration: lib support batch 5 * pw_unit_test migration: lib support batch 4 (#33199) * pw_unit_test migration: lib support batch 4 * fix merge error BUILD.gn * pw_unit_test migration: lib support batch 5 * newline * removing commented-out code * convert TestCHIPArgParser test --- src/BUILD.gn | 1 - src/lib/support/tests/BUILD.gn | 39 +-- src/lib/support/tests/TestCHIPArgParser.cpp | 214 +++++-------- src/lib/support/tests/TestPool.cpp | 293 ++++++++---------- src/lib/support/tests/TestStateMachine.cpp | 123 +++----- .../tests/TestThreadOperationalDataset.cpp | 200 +++++------- .../unit-tests/test_components_nl.txt | 1 - 7 files changed, 342 insertions(+), 529 deletions(-) diff --git a/src/BUILD.gn b/src/BUILD.gn index 8fedfa15e43fd8..aa657786cd2469 100644 --- a/src/BUILD.gn +++ b/src/BUILD.gn @@ -99,7 +99,6 @@ if (chip_build_tests) { "${chip_root}/src/credentials/tests", "${chip_root}/src/lib/format/tests", "${chip_root}/src/lib/support/tests", - "${chip_root}/src/lib/support/tests:tests_nltest", "${chip_root}/src/protocols/secure_channel/tests", "${chip_root}/src/protocols/secure_channel/tests:tests_nltest", "${chip_root}/src/system/tests", diff --git a/src/lib/support/tests/BUILD.gn b/src/lib/support/tests/BUILD.gn index 485402003fd4dd..565eb85097d133 100644 --- a/src/lib/support/tests/BUILD.gn +++ b/src/lib/support/tests/BUILD.gn @@ -40,6 +40,7 @@ chip_test_suite("tests") { "TestJsonToTlv.cpp", "TestJsonToTlvToJson.cpp", "TestPersistedCounter.cpp", + "TestPool.cpp", "TestPrivateHeap.cpp", "TestSafeInt.cpp", "TestSafeString.cpp", @@ -47,10 +48,12 @@ chip_test_suite("tests") { "TestScopedBuffer.cpp", "TestSorting.cpp", "TestSpan.cpp", + "TestStateMachine.cpp", "TestStaticSupportSmartPtr.cpp", "TestStringBuilder.cpp", "TestStringSplitter.cpp", "TestTestPersistentStorageDelegate.cpp", + "TestThreadOperationalDataset.cpp", "TestTimeUtils.cpp", "TestTlvJson.cpp", "TestTlvToJson.cpp", @@ -58,42 +61,12 @@ chip_test_suite("tests") { "TestVariant.cpp", "TestZclString.cpp", ] - sources = [] - - cflags = [ - "-Wconversion", - - # TODO(#21255): work-around for SimpleStateMachine constructor issue. - "-Wno-uninitialized", - - # TestStringSplitter intentionally validates string overflows. - "-Wno-stringop-truncation", - ] - - public_deps = [ - "${chip_root}/src/credentials", - "${chip_root}/src/lib/core", - "${chip_root}/src/lib/support:static-support", - "${chip_root}/src/lib/support:testing", - "${chip_root}/src/lib/support/jsontlv", - "${chip_root}/src/platform", - ] -} - -chip_test_suite_using_nltest("tests_nltest") { - output_name = "libSupportTestsNL" - - test_sources = [ - "TestPool.cpp", - "TestStateMachine.cpp", - "TestThreadOperationalDataset.cpp", - ] - sources = [] - if (current_os != "mbed") { test_sources += [ "TestCHIPArgParser.cpp" ] } + sources = [] + cflags = [ "-Wconversion", @@ -109,9 +82,7 @@ chip_test_suite_using_nltest("tests_nltest") { "${chip_root}/src/lib/core", "${chip_root}/src/lib/support:static-support", "${chip_root}/src/lib/support:testing", - "${chip_root}/src/lib/support:testing_nlunit", "${chip_root}/src/lib/support/jsontlv", "${chip_root}/src/platform", - "${nlunit_test_root}:nlunit-test", ] } diff --git a/src/lib/support/tests/TestCHIPArgParser.cpp b/src/lib/support/tests/TestCHIPArgParser.cpp index c54e0223ca7e07..426758aff1e5c8 100644 --- a/src/lib/support/tests/TestCHIPArgParser.cpp +++ b/src/lib/support/tests/TestCHIPArgParser.cpp @@ -22,17 +22,16 @@ #include #include +#include + #include #include #include #include #include #include -#include #include -#if CHIP_CONFIG_ENABLE_ARG_PARSER - using namespace chip::ArgParser; static bool HandleOption(const char * progName, OptionSet * optSet, int id, const char * name, const char * arg); @@ -40,71 +39,68 @@ static bool HandleNonOptionArgs(const char * progName, int argc, char * const ar static void HandleArgError(const char * msg, ...); static void ClearCallbackRecords(); -#define DEBUG_TESTS 0 - -#define QuitWithError(MSG) \ - do \ - { \ - fprintf(stderr, "%s FAILED (line %d): ", __FUNCTION__, __LINE__); \ - fputs(MSG, stderr); \ - fputs("\n", stderr); \ - exit(EXIT_FAILURE); \ - } while (0) +class TestCHIPArgParser : public ::testing::Test +{ +public: + static void SetUpTestSuite() { ASSERT_EQ(chip::Platform::MemoryInit(), CHIP_NO_ERROR); } + static void TearDownTestSuite() + { + ClearCallbackRecords(); + chip::Platform::MemoryShutdown(); + } +}; -#define VerifyOrQuit(TST, MSG) \ - do \ - { \ - if (!(TST)) \ - { \ - QuitWithError(MSG); \ - } \ - } while (0) +#define DEBUG_TESTS 0 #define VerifyHandleOptionCallback(INDEX, EXPECT_PROG_NAME, EXPECT_OPTSET, EXPECT_ID, EXPECT_NAME, EXPECT_ARG) \ do \ { \ CallbackRecord & rec = sCallbackRecords[INDEX]; \ const char * arg = EXPECT_ARG; \ - VerifyOrQuit(rec.Type == CallbackRecord::kHandleOption, "Invalid callback type (expected HandleOption)"); \ - VerifyOrQuit(strcmp(rec.ProgName, EXPECT_PROG_NAME) == 0, "Invalid value for HandleOption argument: progName"); \ - VerifyOrQuit(rec.OptSet == EXPECT_OPTSET, "Invalid value for HandleOption argument: optSet"); \ - VerifyOrQuit(rec.Id == EXPECT_ID, "Invalid value for HandleOption argument: id"); \ - VerifyOrQuit(strcmp(rec.Name, EXPECT_NAME) == 0, "Invalid value for HandleOption argument: name"); \ + ASSERT_EQ(rec.Type, CallbackRecord::kHandleOption) << "Invalid callback type (expected HandleOption)"; \ + ASSERT_STREQ(rec.ProgName, EXPECT_PROG_NAME) << "Invalid value for HandleOption argument: progName"; \ + ASSERT_EQ(rec.OptSet, EXPECT_OPTSET) << "Invalid value for HandleOption argument: optSet"; \ + ASSERT_EQ(rec.Id, EXPECT_ID) << "Invalid value for HandleOption argument: id"; \ + ASSERT_STREQ(rec.Name, EXPECT_NAME) << "Invalid value for HandleOption argument: name"; \ if (arg != NULL) \ - VerifyOrQuit(strcmp(rec.Arg, arg) == 0, "Invalid value for HandleOption argument: arg"); \ + { \ + ASSERT_STREQ(rec.Arg, arg) << "Invalid value for HandleOption argument: arg"; \ + } \ else \ - VerifyOrQuit(rec.Arg == NULL, "Invalid value for HandleOption argument: arg"); \ + { \ + ASSERT_EQ(rec.Arg, nullptr) << "Invalid value for HandleOption argument: arg"; \ + } \ } while (0) #define VerifyHandleNonOptionArgsCallback(INDEX, EXPECT_PROG_NAME, EXPECT_ARGC) \ do \ { \ CallbackRecord & rec = sCallbackRecords[INDEX]; \ - VerifyOrQuit(rec.Type == CallbackRecord::kHandleNonOptionArgs, "Invalid callback type (expected HandleNonOptionArgs)"); \ - VerifyOrQuit(strcmp(rec.ProgName, EXPECT_PROG_NAME) == 0, "Invalid value for HandleNonOptionArgs argument: progName"); \ - VerifyOrQuit(rec.Argc == EXPECT_ARGC, "Invalid value for HandleNonOptionArgs argument: argc"); \ + ASSERT_EQ(rec.Type, CallbackRecord::kHandleNonOptionArgs) << "Invalid callback type (expected HandleNonOptionArgs)"; \ + ASSERT_STREQ(rec.ProgName, EXPECT_PROG_NAME) << "Invalid value for HandleNonOptionArgs argument: progName"; \ + ASSERT_EQ(rec.Argc, EXPECT_ARGC) << "Invalid value for HandleNonOptionArgs argument: argc"; \ } while (0) #define VerifyNonOptionArg(INDEX, EXPECT_ARG) \ do \ { \ CallbackRecord & rec = sCallbackRecords[INDEX]; \ - VerifyOrQuit(rec.Type == CallbackRecord::kNonOptionArg, "Invalid callback type (expected NonOptionArg)"); \ - VerifyOrQuit(strcmp(rec.Arg, EXPECT_ARG) == 0, "Invalid value for NonOptionArg"); \ + ASSERT_EQ(rec.Type, CallbackRecord::kNonOptionArg) << "Invalid callback type (expected NonOptionArg)"; \ + ASSERT_STREQ(rec.Arg, EXPECT_ARG) << "Invalid value for NonOptionArg"; \ } while (0) #define VerifyPrintArgErrorCallback(INDEX) \ do \ { \ CallbackRecord & rec = sCallbackRecords[INDEX]; \ - VerifyOrQuit(rec.Type == CallbackRecord::kArgError, "Invalid callback type (expected ArgError)"); \ + ASSERT_EQ(rec.Type, CallbackRecord::kArgError) << "Invalid callback type (expected ArgError)"; \ } while (0) #define VerifyArgErrorContains(INDEX, EXPECT_TEXT) \ do \ { \ CallbackRecord & rec = sCallbackRecords[INDEX]; \ - VerifyOrQuit(strstr(rec.Error, EXPECT_TEXT) != NULL, "Expected text not found in error output"); \ + ASSERT_NE(strstr(rec.Error, EXPECT_TEXT), nullptr) << "Expected text not found in error output"; \ } while (0) struct CallbackRecord @@ -212,7 +208,7 @@ TestArgv DupeArgs(const char * argv[], int argc_as_int) } // namespace -static void SimpleParseTest_SingleLongOption() +TEST_F(TestCHIPArgParser, SimpleParseTest_SingleLongOption) { bool res; @@ -232,13 +228,13 @@ static void SimpleParseTest_SingleLongOption() TestArgv argsDup = DupeArgs(argv, argc); res = ParseArgs(__FUNCTION__, argc, argsDup.argv.Get(), optionSets, HandleNonOptionArgs); - VerifyOrQuit(res == true, "ParseArgs() returned false"); - VerifyOrQuit(sCallbackRecordCount == 2, "Invalid value returned for sCallbackRecordCount"); + ASSERT_TRUE(res) << "ParseArgs() returned false"; + ASSERT_EQ(sCallbackRecordCount, 2u) << "Invalid value returned for sCallbackRecordCount"; VerifyHandleOptionCallback(0, __FUNCTION__, &sOptionSetA, '1', "--foo", nullptr); VerifyHandleNonOptionArgsCallback(1, __FUNCTION__, 0); } -static void SimpleParseTest_SingleShortOption() +TEST_F(TestCHIPArgParser, SimpleParseTest_SingleShortOption) { bool res; @@ -258,13 +254,13 @@ static void SimpleParseTest_SingleShortOption() TestArgv argsDup = DupeArgs(argv, argc); res = ParseArgs(__FUNCTION__, argc, argsDup.argv.Get(), optionSets, HandleNonOptionArgs); - VerifyOrQuit(res == true, "ParseArgs() returned false"); - VerifyOrQuit(sCallbackRecordCount == 2, "Invalid value returned for sCallbackRecordCount"); + ASSERT_TRUE(res) << "ParseArgs() returned false"; + ASSERT_EQ(sCallbackRecordCount, 2u) << "Invalid value returned for sCallbackRecordCount"; VerifyHandleOptionCallback(0, __FUNCTION__, &sOptionSetB, 's', "-s", nullptr); VerifyHandleNonOptionArgsCallback(1, __FUNCTION__, 0); } -static void SimpleParseTest_SingleLongOptionWithValue() +TEST_F(TestCHIPArgParser, SimpleParseTest_SingleLongOptionWithValue) { bool res; @@ -284,13 +280,13 @@ static void SimpleParseTest_SingleLongOptionWithValue() TestArgv argsDup = DupeArgs(argv, argc); res = ParseArgs(__FUNCTION__, argc, argsDup.argv.Get(), optionSets, HandleNonOptionArgs); - VerifyOrQuit(res == true, "ParseArgs() returned false"); - VerifyOrQuit(sCallbackRecordCount == 2, "Invalid value returned for sCallbackRecordCount"); + ASSERT_TRUE(res) << "ParseArgs() returned false"; + ASSERT_EQ(sCallbackRecordCount, 2u) << "Invalid value returned for sCallbackRecordCount"; VerifyHandleOptionCallback(0, __FUNCTION__, &sOptionSetB, 1000, "--run", "run-value"); VerifyHandleNonOptionArgsCallback(1, __FUNCTION__, 0); } -static void SimpleParseTest_SingleShortOptionWithValue() +TEST_F(TestCHIPArgParser, SimpleParseTest_SingleShortOptionWithValue) { bool res; @@ -310,13 +306,13 @@ static void SimpleParseTest_SingleShortOptionWithValue() TestArgv argsDup = DupeArgs(argv, argc); res = ParseArgs(__FUNCTION__, argc, argsDup.argv.Get(), optionSets, HandleNonOptionArgs); - VerifyOrQuit(res == true, "ParseArgs() returned false"); - VerifyOrQuit(sCallbackRecordCount == 2, "Invalid value returned for sCallbackRecordCount"); + ASSERT_TRUE(res) << "ParseArgs() returned false"; + ASSERT_EQ(sCallbackRecordCount, 2u) << "Invalid value returned for sCallbackRecordCount"; VerifyHandleOptionCallback(0, __FUNCTION__, &sOptionSetA, 'Z', "-Z", "baz-value"); VerifyHandleNonOptionArgsCallback(1, __FUNCTION__, 0); } -static void SimpleParseTest_VariousShortAndLongWithArgs() +TEST_F(TestCHIPArgParser, SimpleParseTest_VariousShortAndLongWithArgs) { bool res; @@ -345,8 +341,8 @@ static void SimpleParseTest_VariousShortAndLongWithArgs() TestArgv argsDup = DupeArgs(argv, argc); res = ParseArgs(__FUNCTION__, argc, argsDup.argv.Get(), optionSets, HandleNonOptionArgs); - VerifyOrQuit(res == true, "ParseArgs() returned false"); - VerifyOrQuit(sCallbackRecordCount == 12, "Invalid value returned for sCallbackRecordCount"); + ASSERT_TRUE(res) << "ParseArgs() returned false"; + ASSERT_EQ(sCallbackRecordCount, 12u) << "Invalid value returned for sCallbackRecordCount"; VerifyHandleOptionCallback(0, __FUNCTION__, &sOptionSetA, '1', "--foo", nullptr); VerifyHandleOptionCallback(1, __FUNCTION__, &sOptionSetB, 1000, "--run", "run-value"); VerifyHandleOptionCallback(2, __FUNCTION__, &sOptionSetB, 's', "-s", nullptr); @@ -361,7 +357,7 @@ static void SimpleParseTest_VariousShortAndLongWithArgs() VerifyNonOptionArg(11, "non-opt-arg-4"); } -static void UnknownOptionTest_UnknownShortOption() +TEST_F(TestCHIPArgParser, UnknownOptionTest_UnknownShortOption) { bool res; @@ -385,8 +381,8 @@ static void UnknownOptionTest_UnknownShortOption() TestArgv argsDup = DupeArgs(argv, argc); res = ParseArgs(__FUNCTION__, argc, argsDup.argv.Get(), optionSets, HandleNonOptionArgs); - VerifyOrQuit(res == false, "ParseArgs() returned true"); - VerifyOrQuit(sCallbackRecordCount == 3, "Invalid value returned for sCallbackRecordCount"); + ASSERT_FALSE(res) << "ParseArgs() returned true"; + ASSERT_EQ(sCallbackRecordCount, 3u) << "Invalid value returned for sCallbackRecordCount"; VerifyHandleOptionCallback(0, __FUNCTION__, &sOptionSetA, '1', "--foo", nullptr); VerifyHandleOptionCallback(1, __FUNCTION__, &sOptionSetB, 1000, "--run", "run-value"); VerifyPrintArgErrorCallback(2); @@ -394,7 +390,7 @@ static void UnknownOptionTest_UnknownShortOption() VerifyArgErrorContains(2, "-q"); } -static void UnknownOptionTest_UnknownLongOption() +TEST_F(TestCHIPArgParser, UnknownOptionTest_UnknownLongOption) { bool res; @@ -418,8 +414,8 @@ static void UnknownOptionTest_UnknownLongOption() TestArgv argsDup = DupeArgs(argv, argc); res = ParseArgs(__FUNCTION__, argc, argsDup.argv.Get(), optionSets, HandleNonOptionArgs); - VerifyOrQuit(res == false, "ParseArgs() returned true"); - VerifyOrQuit(sCallbackRecordCount == 3, "Invalid value returned for sCallbackRecordCount"); + ASSERT_FALSE(res) << "ParseArgs() returned true"; + ASSERT_EQ(sCallbackRecordCount, 3u) << "Invalid value returned for sCallbackRecordCount"; VerifyHandleOptionCallback(0, __FUNCTION__, &sOptionSetA, '1', "--foo", nullptr); VerifyHandleOptionCallback(1, __FUNCTION__, &sOptionSetB, 1000, "--run", "run-value"); VerifyPrintArgErrorCallback(2); @@ -427,7 +423,7 @@ static void UnknownOptionTest_UnknownLongOption() VerifyArgErrorContains(2, "--bad"); } -static void UnknownOptionTest_UnknownShortOptionAfterKnown() +TEST_F(TestCHIPArgParser, UnknownOptionTest_UnknownShortOptionAfterKnown) { bool res; @@ -451,8 +447,8 @@ static void UnknownOptionTest_UnknownShortOptionAfterKnown() TestArgv argsDup = DupeArgs(argv, argc); res = ParseArgs(__FUNCTION__, argc, argsDup.argv.Get(), optionSets, HandleNonOptionArgs); - VerifyOrQuit(res == false, "ParseArgs() returned true"); - VerifyOrQuit(sCallbackRecordCount == 4, "Invalid value returned for sCallbackRecordCount"); + ASSERT_FALSE(res) << "ParseArgs() returned true"; + ASSERT_EQ(sCallbackRecordCount, 4u) << "Invalid value returned for sCallbackRecordCount"; VerifyHandleOptionCallback(0, __FUNCTION__, &sOptionSetA, '1', "--foo", nullptr); VerifyHandleOptionCallback(1, __FUNCTION__, &sOptionSetB, 1000, "--run", "run-value"); VerifyHandleOptionCallback(2, __FUNCTION__, &sOptionSetA, '1', "-1", nullptr); @@ -461,7 +457,7 @@ static void UnknownOptionTest_UnknownShortOptionAfterKnown() VerifyArgErrorContains(3, "-Q"); } -static void UnknownOptionTest_UnknownShortOptionBeforeKnown() +TEST_F(TestCHIPArgParser, UnknownOptionTest_UnknownShortOptionBeforeKnown) { bool res; @@ -481,14 +477,14 @@ static void UnknownOptionTest_UnknownShortOptionBeforeKnown() TestArgv argsDup = DupeArgs(argv, argc); res = ParseArgs(__FUNCTION__, argc, argsDup.argv.Get(), optionSets, HandleNonOptionArgs); - VerifyOrQuit(res == false, "ParseArgs() returned true"); - VerifyOrQuit(sCallbackRecordCount == 1, "Invalid value returned for sCallbackRecordCount"); + ASSERT_FALSE(res) << "ParseArgs() returned true"; + ASSERT_EQ(sCallbackRecordCount, 1u) << "Invalid value returned for sCallbackRecordCount"; VerifyPrintArgErrorCallback(0); VerifyArgErrorContains(0, "Unknown"); VerifyArgErrorContains(0, "-Q"); } -static void UnknownOptionTest_UnknownShortOptionAfterArgs() +TEST_F(TestCHIPArgParser, UnknownOptionTest_UnknownShortOptionAfterArgs) { bool res; @@ -510,14 +506,14 @@ static void UnknownOptionTest_UnknownShortOptionAfterArgs() TestArgv argsDup = DupeArgs(argv, argc); res = ParseArgs(__FUNCTION__, argc, argsDup.argv.Get(), optionSets, HandleNonOptionArgs); - VerifyOrQuit(res == false, "ParseArgs() returned true"); - VerifyOrQuit(sCallbackRecordCount == 1, "Invalid value returned for sCallbackRecordCount"); + ASSERT_FALSE(res) << "ParseArgs() returned true"; + ASSERT_EQ(sCallbackRecordCount, 1u) << "Invalid value returned for sCallbackRecordCount"; VerifyPrintArgErrorCallback(0); VerifyArgErrorContains(0, "Unknown"); VerifyArgErrorContains(0, "-Q"); } -static void UnknownOptionTest_UnknownLongOptionAfterArgs() +TEST_F(TestCHIPArgParser, UnknownOptionTest_UnknownLongOptionAfterArgs) { bool res; @@ -539,15 +535,14 @@ static void UnknownOptionTest_UnknownLongOptionAfterArgs() TestArgv argsDup = DupeArgs(argv, argc); res = ParseArgs(__FUNCTION__, argc, argsDup.argv.Get(), optionSets, HandleNonOptionArgs); - VerifyOrQuit(res == false, "ParseArgs() returned true"); - VerifyOrQuit(sCallbackRecordCount == 1, "Invalid value returned for sCallbackRecordCount"); + ASSERT_FALSE(res) << "ParseArgs() returned true"; + ASSERT_EQ(sCallbackRecordCount, 1u) << "Invalid value returned for sCallbackRecordCount"; VerifyPrintArgErrorCallback(0); VerifyArgErrorContains(0, "Unknown"); VerifyArgErrorContains(0, "--barf"); } -#ifndef CHIP_CONFIG_NON_POSIX_LONG_OPT -static void UnknownOptionTest_IgnoreUnknownLongOption() +TEST_F(TestCHIPArgParser, UnknownOptionTest_IgnoreUnknownLongOption) { bool res; @@ -570,18 +565,17 @@ static void UnknownOptionTest_IgnoreUnknownLongOption() TestArgv argsDup = DupeArgs(argv, argc); res = ParseArgs(__FUNCTION__, argc, argsDup.argv.Get(), optionSets, HandleNonOptionArgs, true); - VerifyOrQuit(res == true, "ParseArgs() returned false"); + ASSERT_TRUE(res) << "ParseArgs() returned false"; - VerifyOrQuit(sCallbackRecordCount == 4, "Invalid value returned for sCallbackRecordCount"); + ASSERT_EQ(sCallbackRecordCount, 4u) << "Invalid value returned for sCallbackRecordCount"; VerifyHandleOptionCallback(0, __FUNCTION__, &sOptionSetA, 'Z', "-Z", "baz-value"); VerifyHandleNonOptionArgsCallback(1, __FUNCTION__, 2); VerifyNonOptionArg(2, "non-opt-arg-1"); VerifyNonOptionArg(3, "non-opt-arg-2"); } -#endif // !CHIP_CONFIG_NON_POSIX_LONG_OPT -static void UnknownOptionTest_IgnoreUnknownShortOption() +TEST_F(TestCHIPArgParser, UnknownOptionTest_IgnoreUnknownShortOption) { bool res; @@ -604,9 +598,9 @@ static void UnknownOptionTest_IgnoreUnknownShortOption() TestArgv argsDup = DupeArgs(argv, argc); res = ParseArgs(__FUNCTION__, argc, argsDup.argv.Get(), optionSets, HandleNonOptionArgs, true); - VerifyOrQuit(res == true, "ParseArgs() returned false"); + ASSERT_TRUE(res) << "ParseArgs() returned false"; - VerifyOrQuit(sCallbackRecordCount == 5, "Invalid value returned for sCallbackRecordCount"); + ASSERT_EQ(sCallbackRecordCount, 5u) << "Invalid value returned for sCallbackRecordCount"; VerifyHandleOptionCallback(0, __FUNCTION__, &sOptionSetA, '1', "-1", nullptr); VerifyHandleOptionCallback(1, __FUNCTION__, &sOptionSetA, 'Z', "-Z", "baz-value"); @@ -615,7 +609,7 @@ static void UnknownOptionTest_IgnoreUnknownShortOption() VerifyNonOptionArg(4, "non-opt-arg-2"); } -static void MissingValueTest_MissingShortOptionValue() +TEST_F(TestCHIPArgParser, MissingValueTest_MissingShortOptionValue) { bool res; @@ -635,14 +629,14 @@ static void MissingValueTest_MissingShortOptionValue() TestArgv argsDup = DupeArgs(argv, argc); res = ParseArgs(__FUNCTION__, argc, argsDup.argv.Get(), optionSets, HandleNonOptionArgs, true); - VerifyOrQuit(res == false, "ParseArgs() returned true"); - VerifyOrQuit(sCallbackRecordCount == 1, "Invalid value returned for sCallbackRecordCount"); + ASSERT_FALSE(res) << "ParseArgs() returned true"; + ASSERT_EQ(sCallbackRecordCount, 1u) << "Invalid value returned for sCallbackRecordCount"; VerifyPrintArgErrorCallback(0); VerifyArgErrorContains(0, "Missing"); VerifyArgErrorContains(0, "-Z"); } -static void MissingValueTest_MissingLongOptionValue() +TEST_F(TestCHIPArgParser, MissingValueTest_MissingLongOptionValue) { bool res; @@ -662,8 +656,8 @@ static void MissingValueTest_MissingLongOptionValue() TestArgv argsDup = DupeArgs(argv, argc); res = ParseArgs(__FUNCTION__, argc, argsDup.argv.Get(), optionSets, HandleNonOptionArgs, true); - VerifyOrQuit(res == false, "ParseArgs() returned true"); - VerifyOrQuit(sCallbackRecordCount == 1, "Invalid value returned for sCallbackRecordCount"); + ASSERT_FALSE(res) << "ParseArgs() returned true"; + ASSERT_EQ(sCallbackRecordCount, 1u) << "Invalid value returned for sCallbackRecordCount"; VerifyPrintArgErrorCallback(0); VerifyArgErrorContains(0, "Missing"); VerifyArgErrorContains(0, "--run"); @@ -692,7 +686,7 @@ static bool HandleOption(const char * progName, OptionSet * optSet, int id, cons printf("HandleOption called: progName:%s optSet:%08lX id:%d name:%s arg:%s\n", progName, (intptr_t) optSet, id, name, arg); #endif - VerifyOrQuit(sCallbackRecordCount < kMaxCallbackRecords, "Out of callback records"); + EXPECT_LT(sCallbackRecordCount, kMaxCallbackRecords) << "Out of callback records"; sCallbackRecords[sCallbackRecordCount].Type = CallbackRecord::kHandleOption; sCallbackRecords[sCallbackRecordCount].ProgName = chip::Platform::MemoryAllocString(progName, strlen(progName)); sCallbackRecords[sCallbackRecordCount].OptSet = optSet; @@ -717,7 +711,7 @@ static bool HandleNonOptionArgs(const char * progName, int argc, char * const ar // clang-format on #endif - VerifyOrQuit(sCallbackRecordCount < kMaxCallbackRecords, "Out of callback records"); + EXPECT_LT(sCallbackRecordCount, kMaxCallbackRecords) << "Out of callback records"; sCallbackRecords[sCallbackRecordCount].Type = CallbackRecord::kHandleNonOptionArgs; sCallbackRecords[sCallbackRecordCount].ProgName = chip::Platform::MemoryAllocString(progName, strlen(progName)); sCallbackRecords[sCallbackRecordCount].Argc = argc; @@ -725,7 +719,7 @@ static bool HandleNonOptionArgs(const char * progName, int argc, char * const ar for (int i = 0; i < argc; i++) { - VerifyOrQuit(sCallbackRecordCount < kMaxCallbackRecords, "Out of callback records"); + EXPECT_LT(sCallbackRecordCount, kMaxCallbackRecords) << "Out of callback records"; sCallbackRecords[sCallbackRecordCount].Type = CallbackRecord::kNonOptionArg; sCallbackRecords[sCallbackRecordCount].Arg = chip::Platform::MemoryAllocString(argv[i], strlen(argv[i])); sCallbackRecordCount++; @@ -740,7 +734,7 @@ static void ENFORCE_FORMAT(1, 2) HandleArgError(const char * msg, ...) int status; va_list ap; - VerifyOrQuit(sCallbackRecordCount < kMaxCallbackRecords, "Out of callback records"); + ASSERT_LT(sCallbackRecordCount, kMaxCallbackRecords) << "Out of callback records"; sCallbackRecords[sCallbackRecordCount].Type = CallbackRecord::kArgError; @@ -760,51 +754,3 @@ static void ENFORCE_FORMAT(1, 2) HandleArgError(const char * msg, ...) sCallbackRecordCount++; } - -int TestCHIPArgParser() -{ - if (chip::Platform::MemoryInit() != CHIP_NO_ERROR) - { - return EXIT_FAILURE; - } - - SimpleParseTest_SingleLongOption(); - SimpleParseTest_SingleShortOption(); - SimpleParseTest_SingleLongOptionWithValue(); - SimpleParseTest_SingleShortOptionWithValue(); - SimpleParseTest_VariousShortAndLongWithArgs(); - - UnknownOptionTest_UnknownShortOption(); - UnknownOptionTest_UnknownLongOption(); - UnknownOptionTest_UnknownShortOptionAfterArgs(); - UnknownOptionTest_UnknownShortOptionAfterKnown(); - UnknownOptionTest_UnknownShortOptionBeforeKnown(); - UnknownOptionTest_UnknownLongOptionAfterArgs(); - UnknownOptionTest_IgnoreUnknownShortOption(); - - /* Skip this test because the parser successfully captures all the options - but the error reporting is incorrect in this case due to long_opt limitations */ -#ifndef CHIP_CONFIG_NON_POSIX_LONG_OPT - UnknownOptionTest_IgnoreUnknownLongOption(); -#endif // !CHIP_CONFIG_NON_POSIX_LONG_OPT - - MissingValueTest_MissingShortOptionValue(); - MissingValueTest_MissingLongOptionValue(); - - ClearCallbackRecords(); - - printf("All tests succeeded\n"); - - chip::Platform::MemoryShutdown(); - - return (EXIT_SUCCESS); -} -#else // CHIP_CONFIG_ENABLE_ARG_PARSER -int TestCHIPArgParser(void) -{ - printf("No tests were run\n"); - return (EXIT_SUCCESS); -} -#endif // CHIP_CONFIG_ENABLE_ARG_PARSER - -CHIP_REGISTER_TEST_SUITE(TestCHIPArgParser); diff --git a/src/lib/support/tests/TestPool.cpp b/src/lib/support/tests/TestPool.cpp index 963a7b3c52f7ea..da76d7ebb70d7b 100644 --- a/src/lib/support/tests/TestPool.cpp +++ b/src/lib/support/tests/TestPool.cpp @@ -25,13 +25,11 @@ #include +#include + #include #include -#include #include - -#include - namespace chip { template @@ -51,60 +49,67 @@ namespace { using namespace chip; +class TestPool : public ::testing::Test +{ +public: + static void SetUpTestSuite() { ASSERT_EQ(chip::Platform::MemoryInit(), CHIP_NO_ERROR); } + static void TearDownTestSuite() { chip::Platform::MemoryShutdown(); } +}; + template -void TestReleaseNull(nlTestSuite * inSuite, void * inContext) +void TestReleaseNull() { ObjectPool pool; pool.ReleaseObject(nullptr); - NL_TEST_ASSERT(inSuite, GetNumObjectsInUse(pool) == 0); - NL_TEST_ASSERT(inSuite, pool.Allocated() == 0); + EXPECT_EQ(GetNumObjectsInUse(pool), 0u); + EXPECT_EQ(pool.Allocated(), 0u); } -void TestReleaseNullStatic(nlTestSuite * inSuite, void * inContext) +TEST_F(TestPool, TestReleaseNullStatic) { - TestReleaseNull(inSuite, inContext); + TestReleaseNull(); } #if CHIP_SYSTEM_CONFIG_POOL_USE_HEAP -void TestReleaseNullDynamic(nlTestSuite * inSuite, void * inContext) +TEST_F(TestPool, TestReleaseNullDynamic) { - TestReleaseNull(inSuite, inContext); + TestReleaseNull(); } #endif // CHIP_SYSTEM_CONFIG_POOL_USE_HEAP template -void TestCreateReleaseObject(nlTestSuite * inSuite, void * inContext) +void TestCreateReleaseObject() { ObjectPool pool; uint32_t * obj[N]; - NL_TEST_ASSERT(inSuite, pool.Allocated() == 0); + EXPECT_EQ(pool.Allocated(), 0u); for (int t = 0; t < 2; ++t) { pool.ReleaseAll(); - NL_TEST_ASSERT(inSuite, pool.Allocated() == 0); + EXPECT_EQ(pool.Allocated(), 0u); for (size_t i = 0; i < N; ++i) { obj[i] = pool.CreateObject(); - NL_TEST_ASSERT(inSuite, obj[i] != nullptr); - NL_TEST_ASSERT(inSuite, GetNumObjectsInUse(pool) == i + 1); - NL_TEST_ASSERT(inSuite, pool.Allocated() == i + 1); + ASSERT_NE(obj[i], nullptr); + EXPECT_EQ(GetNumObjectsInUse(pool), i + 1); + EXPECT_EQ(pool.Allocated(), i + 1); } } for (size_t i = 0; i < N; ++i) { pool.ReleaseObject(obj[i]); - NL_TEST_ASSERT(inSuite, GetNumObjectsInUse(pool) == N - i - 1); - NL_TEST_ASSERT(inSuite, pool.Allocated() == N - i - 1); + EXPECT_EQ(GetNumObjectsInUse(pool), N - i - 1); + EXPECT_EQ(pool.Allocated(), N - i - 1); } } -void TestCreateReleaseObjectStatic(nlTestSuite * inSuite, void * inContext) +TEST_F(TestPool, TestCreateReleaseObjectStatic) { constexpr const size_t kSize = 100; - TestCreateReleaseObject(inSuite, inContext); + TestCreateReleaseObject(); ObjectPool pool; uint32_t * obj[kSize]; @@ -112,44 +117,44 @@ void TestCreateReleaseObjectStatic(nlTestSuite * inSuite, void * inContext) for (size_t i = 0; i < kSize; ++i) { obj[i] = pool.CreateObject(); - NL_TEST_ASSERT(inSuite, obj[i] != nullptr); - NL_TEST_ASSERT(inSuite, GetNumObjectsInUse(pool) == i + 1); - NL_TEST_ASSERT(inSuite, pool.Allocated() == i + 1); + ASSERT_NE(obj[i], nullptr); + EXPECT_EQ(GetNumObjectsInUse(pool), i + 1); + EXPECT_EQ(pool.Allocated(), i + 1); } uint32_t * fail = pool.CreateObject(); - NL_TEST_ASSERT(inSuite, fail == nullptr); - NL_TEST_ASSERT(inSuite, GetNumObjectsInUse(pool) == kSize); - NL_TEST_ASSERT(inSuite, pool.Allocated() == kSize); - NL_TEST_ASSERT(inSuite, pool.Exhausted()); + EXPECT_EQ(fail, nullptr); + EXPECT_EQ(GetNumObjectsInUse(pool), kSize); + EXPECT_EQ(pool.Allocated(), kSize); + EXPECT_TRUE(pool.Exhausted()); pool.ReleaseObject(obj[55]); - NL_TEST_ASSERT(inSuite, GetNumObjectsInUse(pool) == kSize - 1); - NL_TEST_ASSERT(inSuite, pool.Allocated() == kSize - 1); - NL_TEST_ASSERT(inSuite, !pool.Exhausted()); - NL_TEST_ASSERT(inSuite, obj[55] == pool.CreateObject()); - NL_TEST_ASSERT(inSuite, GetNumObjectsInUse(pool) == kSize); - NL_TEST_ASSERT(inSuite, pool.Allocated() == kSize); - NL_TEST_ASSERT(inSuite, pool.Exhausted()); + EXPECT_EQ(GetNumObjectsInUse(pool), kSize - 1); + EXPECT_EQ(pool.Allocated(), kSize - 1); + EXPECT_FALSE(pool.Exhausted()); + EXPECT_EQ(obj[55], pool.CreateObject()); + EXPECT_EQ(GetNumObjectsInUse(pool), kSize); + EXPECT_EQ(pool.Allocated(), kSize); + EXPECT_TRUE(pool.Exhausted()); fail = pool.CreateObject(); - NL_TEST_ASSERT(inSuite, fail == nullptr); - NL_TEST_ASSERT(inSuite, GetNumObjectsInUse(pool) == kSize); - NL_TEST_ASSERT(inSuite, pool.Allocated() == kSize); - NL_TEST_ASSERT(inSuite, pool.Exhausted()); + ASSERT_EQ(fail, nullptr); + EXPECT_EQ(GetNumObjectsInUse(pool), kSize); + EXPECT_EQ(pool.Allocated(), kSize); + EXPECT_TRUE(pool.Exhausted()); pool.ReleaseAll(); } #if CHIP_SYSTEM_CONFIG_POOL_USE_HEAP -void TestCreateReleaseObjectDynamic(nlTestSuite * inSuite, void * inContext) +TEST_F(TestPool, TestCreateReleaseObjectDynamic) { - TestCreateReleaseObject(inSuite, inContext); + TestCreateReleaseObject(); } #endif // CHIP_SYSTEM_CONFIG_POOL_USE_HEAP template -void TestCreateReleaseStruct(nlTestSuite * inSuite, void * inContext) +void TestCreateReleaseStruct() { struct S { @@ -166,17 +171,17 @@ void TestCreateReleaseStruct(nlTestSuite * inSuite, void * inContext) for (size_t i = 0; i < kSize; ++i) { objs2[i] = pool.CreateObject(objs1); - NL_TEST_ASSERT(inSuite, objs2[i] != nullptr); - NL_TEST_ASSERT(inSuite, pool.Allocated() == i + 1); - NL_TEST_ASSERT(inSuite, GetNumObjectsInUse(pool) == i + 1); - NL_TEST_ASSERT(inSuite, GetNumObjectsInUse(pool) == objs1.size()); + ASSERT_NE(objs2[i], nullptr); + EXPECT_EQ(pool.Allocated(), i + 1); + EXPECT_EQ(GetNumObjectsInUse(pool), i + 1); + EXPECT_EQ(GetNumObjectsInUse(pool), objs1.size()); } for (size_t i = 0; i < kSize; ++i) { pool.ReleaseObject(objs2[i]); - NL_TEST_ASSERT(inSuite, pool.Allocated() == kSize - i - 1); - NL_TEST_ASSERT(inSuite, GetNumObjectsInUse(pool) == kSize - i - 1); - NL_TEST_ASSERT(inSuite, GetNumObjectsInUse(pool) == objs1.size()); + EXPECT_EQ(pool.Allocated(), kSize - i - 1); + EXPECT_EQ(GetNumObjectsInUse(pool), kSize - i - 1); + EXPECT_EQ(GetNumObjectsInUse(pool), objs1.size()); } // Verify that ReleaseAll() calls the destructors. @@ -184,35 +189,35 @@ void TestCreateReleaseStruct(nlTestSuite * inSuite, void * inContext) { obj = pool.CreateObject(objs1); } - NL_TEST_ASSERT(inSuite, objs1.size() == kSize); - NL_TEST_ASSERT(inSuite, pool.Allocated() == kSize); - NL_TEST_ASSERT(inSuite, GetNumObjectsInUse(pool) == kSize); + EXPECT_EQ(objs1.size(), kSize); + EXPECT_EQ(pool.Allocated(), kSize); + EXPECT_EQ(GetNumObjectsInUse(pool), kSize); printf("allocated = %u\n", static_cast(pool.Allocated())); printf("highwater = %u\n", static_cast(pool.HighWaterMark())); pool.ReleaseAll(); printf("allocated = %u\n", static_cast(pool.Allocated())); printf("highwater = %u\n", static_cast(pool.HighWaterMark())); - NL_TEST_ASSERT(inSuite, objs1.size() == 0); - NL_TEST_ASSERT(inSuite, GetNumObjectsInUse(pool) == 0); - NL_TEST_ASSERT(inSuite, pool.Allocated() == 0); - NL_TEST_ASSERT(inSuite, pool.HighWaterMark() == kSize); + EXPECT_EQ(objs1.size(), 0u); + EXPECT_EQ(GetNumObjectsInUse(pool), 0u); + EXPECT_EQ(pool.Allocated(), 0u); + EXPECT_EQ(pool.HighWaterMark(), kSize); } -void TestCreateReleaseStructStatic(nlTestSuite * inSuite, void * inContext) +TEST_F(TestPool, TestCreateReleaseStructStatic) { - TestCreateReleaseStruct(inSuite, inContext); + TestCreateReleaseStruct(); } #if CHIP_SYSTEM_CONFIG_POOL_USE_HEAP -void TestCreateReleaseStructDynamic(nlTestSuite * inSuite, void * inContext) +TEST_F(TestPool, TestCreateReleaseStructDynamic) { - TestCreateReleaseStruct(inSuite, inContext); + TestCreateReleaseStruct(); } #endif // CHIP_SYSTEM_CONFIG_POOL_USE_HEAP template -void TestForEachActiveObject(nlTestSuite * inSuite, void * inContext) +void TestForEachActiveObject() { struct S { @@ -229,37 +234,37 @@ void TestForEachActiveObject(nlTestSuite * inSuite, void * inContext) for (size_t i = 0; i < kSize; ++i) { objArray[i] = pool.CreateObject(i); - NL_TEST_ASSERT(inSuite, objArray[i] != nullptr); - NL_TEST_ASSERT(inSuite, objArray[i]->mId == i); + ASSERT_NE(objArray[i], nullptr); + EXPECT_EQ(objArray[i]->mId, i); objIds.insert(i); } // Default constructor of an iterator should be pointing to the pool end. { typename ObjectPoolIterator::Type defaultIterator; - NL_TEST_ASSERT(inSuite, defaultIterator == pool.end()); + EXPECT_EQ(defaultIterator, pool.end()); } // Verify that iteration visits all objects. size_t count = 0; { size_t sum = 0; - pool.ForEachActiveObject([&](S * object) { - NL_TEST_ASSERT(inSuite, object != nullptr); + pool.ForEachActiveObject([&](S * object) -> Loop { + EXPECT_NE(object, nullptr); if (object == nullptr) { - // NL_TEST_ASSERT doesn't stop running the test and we want to avoid nullptr dereference. + // Using EXPECT_NE instead of ASSERT_NE due to compilation errors when using ASSERT_NE return Loop::Continue; } - NL_TEST_ASSERT(inSuite, objIds.count(object->mId) == 1); + EXPECT_EQ(objIds.count(object->mId), 1u); objIds.erase(object->mId); ++count; sum += object->mId; return Loop::Continue; }); - NL_TEST_ASSERT(inSuite, count == kSize); - NL_TEST_ASSERT(inSuite, sum == kSize * (kSize - 1) / 2); - NL_TEST_ASSERT(inSuite, objIds.size() == 0); + EXPECT_EQ(count, kSize); + EXPECT_EQ(sum, kSize * (kSize - 1) / 2); + EXPECT_EQ(objIds.size(), 0u); } // Test begin/end iteration @@ -273,14 +278,14 @@ void TestForEachActiveObject(nlTestSuite * inSuite, void * inContext) size_t sum = 0; for (auto v = pool.begin(); v != pool.end(); ++v) { - NL_TEST_ASSERT(inSuite, objIds.count((*v)->mId) == 1); + EXPECT_EQ(objIds.count((*v)->mId), 1u); objIds.erase((*v)->mId); ++count; sum += (*v)->mId; } - NL_TEST_ASSERT(inSuite, count == kSize); - NL_TEST_ASSERT(inSuite, sum == kSize * (kSize - 1) / 2); - NL_TEST_ASSERT(inSuite, objIds.size() == 0); + EXPECT_EQ(count, kSize); + EXPECT_EQ(sum, kSize * (kSize - 1) / 2); + EXPECT_EQ(objIds.size(), 0u); } // Verify that returning Loop::Break stops iterating. @@ -289,8 +294,8 @@ void TestForEachActiveObject(nlTestSuite * inSuite, void * inContext) objIds.insert(object->mId); return ++count != kSize / 2 ? Loop::Continue : Loop::Break; }); - NL_TEST_ASSERT(inSuite, count == kSize / 2); - NL_TEST_ASSERT(inSuite, objIds.size() == kSize / 2); + EXPECT_EQ(count, kSize / 2); + EXPECT_EQ(objIds.size(), kSize / 2); // Verify that iteration can be nested. count = 0; @@ -311,8 +316,8 @@ void TestForEachActiveObject(nlTestSuite * inSuite, void * inContext) } return Loop::Continue; }); - NL_TEST_ASSERT(inSuite, count == (kSize - 1) * kSize / 2); - NL_TEST_ASSERT(inSuite, objIds.size() == 0); + EXPECT_EQ(count, (kSize - 1) * kSize / 2); + EXPECT_EQ(objIds.size(), 0u); // Verify that iteration can be nested for iterator types { @@ -346,8 +351,8 @@ void TestForEachActiveObject(nlTestSuite * inSuite, void * inContext) } } } - NL_TEST_ASSERT(inSuite, count == (kSize - 1) * kSize / 2); - NL_TEST_ASSERT(inSuite, objIds.size() == 0); + EXPECT_EQ(count, (kSize - 1) * kSize / 2); + EXPECT_EQ(objIds.size(), 0u); } count = 0; @@ -364,18 +369,18 @@ void TestForEachActiveObject(nlTestSuite * inSuite, void * inContext) } return Loop::Continue; }); - NL_TEST_ASSERT(inSuite, count == kSize); - NL_TEST_ASSERT(inSuite, objIds.size() == kSize / 2); + EXPECT_EQ(count, kSize); + EXPECT_EQ(objIds.size(), kSize / 2); for (size_t i = 0; i < kSize; ++i) { if ((i % 2) == 0) { - NL_TEST_ASSERT(inSuite, objArray[i] == nullptr); + EXPECT_EQ(objArray[i], nullptr); } else { - NL_TEST_ASSERT(inSuite, objArray[i] != nullptr); - NL_TEST_ASSERT(inSuite, objArray[i]->mId == i); + ASSERT_NE(objArray[i], nullptr); + EXPECT_EQ(objArray[i]->mId, i); } } @@ -385,19 +390,19 @@ void TestForEachActiveObject(nlTestSuite * inSuite, void * inContext) if ((object->mId % 2) == 1) { size_t id = object->mId - 1; - NL_TEST_ASSERT(inSuite, objArray[id] == nullptr); + EXPECT_EQ(objArray[id], nullptr); objArray[id] = pool.CreateObject(id); - NL_TEST_ASSERT(inSuite, objArray[id] != nullptr); + EXPECT_NE(objArray[id], nullptr); } return Loop::Continue; }); for (size_t i = 0; i < kSize; ++i) { - NL_TEST_ASSERT(inSuite, objArray[i] != nullptr); - NL_TEST_ASSERT(inSuite, objArray[i]->mId == i); + ASSERT_NE(objArray[i], nullptr); + EXPECT_EQ(objArray[i]->mId, i); } - NL_TEST_ASSERT(inSuite, count >= kSize / 2); - NL_TEST_ASSERT(inSuite, count <= kSize); + EXPECT_GE(count, kSize / 2); + EXPECT_LE(count, kSize); // Test begin/end iteration { @@ -417,25 +422,25 @@ void TestForEachActiveObject(nlTestSuite * inSuite, void * inContext) objIds.insert(object->mId); } } - NL_TEST_ASSERT(inSuite, count == kSize); - NL_TEST_ASSERT(inSuite, objIds.size() == kSize / 2); + EXPECT_EQ(count, kSize); + EXPECT_EQ(objIds.size(), kSize / 2); // validate we iterate only over active objects for (auto object : pool) { - NL_TEST_ASSERT(inSuite, (object->mId % 2) == 1); + EXPECT_EQ((object->mId % 2), 1u); } for (size_t i = 0; i < kSize; ++i) { if ((i % 2) == 0) { - NL_TEST_ASSERT(inSuite, objArray[i] == nullptr); + EXPECT_EQ(objArray[i], nullptr); } else { - NL_TEST_ASSERT(inSuite, objArray[i] != nullptr); - NL_TEST_ASSERT(inSuite, objArray[i]->mId == i); + ASSERT_NE(objArray[i], nullptr); + EXPECT_EQ(objArray[i]->mId, i); } } @@ -448,36 +453,36 @@ void TestForEachActiveObject(nlTestSuite * inSuite, void * inContext) continue; } size_t id = object->mId - 1; - NL_TEST_ASSERT(inSuite, objArray[id] == nullptr); + EXPECT_EQ(objArray[id], nullptr); objArray[id] = pool.CreateObject(id); - NL_TEST_ASSERT(inSuite, objArray[id] != nullptr); + EXPECT_NE(objArray[id], nullptr); } for (size_t i = 0; i < kSize; ++i) { - NL_TEST_ASSERT(inSuite, objArray[i] != nullptr); - NL_TEST_ASSERT(inSuite, objArray[i]->mId == i); + ASSERT_NE(objArray[i], nullptr); + EXPECT_EQ(objArray[i]->mId, i); } - NL_TEST_ASSERT(inSuite, count >= kSize / 2); - NL_TEST_ASSERT(inSuite, count <= kSize); + EXPECT_GE(count, kSize / 2); + EXPECT_LE(count, kSize); } pool.ReleaseAll(); } -void TestForEachActiveObjectStatic(nlTestSuite * inSuite, void * inContext) +TEST_F(TestPool, TestForEachActiveObjectStatic) { - TestForEachActiveObject(inSuite, inContext); + TestForEachActiveObject(); } #if CHIP_SYSTEM_CONFIG_POOL_USE_HEAP -void TestForEachActiveObjectDynamic(nlTestSuite * inSuite, void * inContext) +TEST_F(TestPool, TestForEachActiveObjectDynamic) { - TestForEachActiveObject(inSuite, inContext); + TestForEachActiveObject(); } #endif // CHIP_SYSTEM_CONFIG_POOL_USE_HEAP template -void TestPoolInterface(nlTestSuite * inSuite, void * inContext) +void TestPoolInterface() { struct TestObject { @@ -503,84 +508,40 @@ void TestPoolInterface(nlTestSuite * inSuite, void * inContext) for (size_t i = 0; i < kSize; ++i) { objs2[i] = poolHolder.mTestObjectPoolInterface.CreateObject(&bits, i); - NL_TEST_ASSERT(inSuite, objs2[i] != nullptr); - NL_TEST_ASSERT(inSuite, GetNumObjectsInUse(poolHolder.mTestObjectPoolInterface) == i + 1); - NL_TEST_ASSERT(inSuite, bits == (1ul << (i + 1)) - 1); + ASSERT_NE(objs2[i], nullptr); + EXPECT_EQ(GetNumObjectsInUse(poolHolder.mTestObjectPoolInterface), i + 1); + EXPECT_EQ(bits, (1ul << (i + 1)) - 1); } for (size_t i = 0; i < kSize; ++i) { poolHolder.mTestObjectPoolInterface.ReleaseObject(objs2[i]); - NL_TEST_ASSERT(inSuite, GetNumObjectsInUse(poolHolder.mTestObjectPoolInterface) == kSize - i - 1); + EXPECT_EQ(GetNumObjectsInUse(poolHolder.mTestObjectPoolInterface), kSize - i - 1); } - NL_TEST_ASSERT(inSuite, bits == 0); + EXPECT_EQ(bits, 0u); // Verify that ReleaseAll() calls the destructors. for (size_t i = 0; i < kSize; ++i) { objs2[i] = poolHolder.mTestObjectPoolInterface.CreateObject(&bits, i); } - NL_TEST_ASSERT(inSuite, bits == (1ul << kSize) - 1); - NL_TEST_ASSERT(inSuite, GetNumObjectsInUse(poolHolder.mTestObjectPoolInterface) == kSize); + EXPECT_EQ(bits, (1ul << kSize) - 1); + EXPECT_EQ(GetNumObjectsInUse(poolHolder.mTestObjectPoolInterface), kSize); poolHolder.mTestObjectPoolInterface.ReleaseAll(); - NL_TEST_ASSERT(inSuite, bits == 0); - NL_TEST_ASSERT(inSuite, GetNumObjectsInUse(poolHolder.mTestObjectPoolInterface) == 0); + EXPECT_EQ(bits, 0u); + EXPECT_EQ(GetNumObjectsInUse(poolHolder.mTestObjectPoolInterface), 0u); } -void TestPoolInterfaceStatic(nlTestSuite * inSuite, void * inContext) +TEST_F(TestPool, TestPoolInterfaceStatic) { - TestPoolInterface(inSuite, inContext); + TestPoolInterface(); } #if CHIP_SYSTEM_CONFIG_POOL_USE_HEAP -void TestPoolInterfaceDynamic(nlTestSuite * inSuite, void * inContext) +TEST_F(TestPool, TestPoolInterfaceDynamic) { - TestPoolInterface(inSuite, inContext); + TestPoolInterface(); } #endif // CHIP_SYSTEM_CONFIG_POOL_USE_HEAP -int Setup(void * inContext) -{ - return ::chip::Platform::MemoryInit() == CHIP_NO_ERROR ? SUCCESS : FAILURE; -} - -int Teardown(void * inContext) -{ - ::chip::Platform::MemoryShutdown(); - return SUCCESS; -} - } // namespace - -#define NL_TEST_DEF_FN(fn) NL_TEST_DEF("Test " #fn, fn) -/** - * Test Suite. It lists all the test functions. - */ -static const nlTest sTests[] = { - // clang-format off - NL_TEST_DEF_FN(TestReleaseNullStatic), - NL_TEST_DEF_FN(TestCreateReleaseObjectStatic), - NL_TEST_DEF_FN(TestCreateReleaseStructStatic), - NL_TEST_DEF_FN(TestForEachActiveObjectStatic), - NL_TEST_DEF_FN(TestPoolInterfaceStatic), -#if CHIP_SYSTEM_CONFIG_POOL_USE_HEAP - NL_TEST_DEF_FN(TestReleaseNullDynamic), - NL_TEST_DEF_FN(TestCreateReleaseObjectDynamic), - NL_TEST_DEF_FN(TestCreateReleaseStructDynamic), - NL_TEST_DEF_FN(TestForEachActiveObjectDynamic), - NL_TEST_DEF_FN(TestPoolInterfaceDynamic), -#endif // CHIP_SYSTEM_CONFIG_POOL_USE_HEAP - NL_TEST_SENTINEL() - // clang-format on -}; - -int TestPool() -{ - nlTestSuite theSuite = { "CHIP Pool tests", &sTests[0], Setup, Teardown }; - - // Run test suite against one context. - nlTestRunner(&theSuite, nullptr); - return nlTestRunnerStats(&theSuite); -} - -CHIP_REGISTER_TEST_SUITE(TestPool); diff --git a/src/lib/support/tests/TestStateMachine.cpp b/src/lib/support/tests/TestStateMachine.cpp index cef020e019ff74..4b6af3a73d85cf 100644 --- a/src/lib/support/tests/TestStateMachine.cpp +++ b/src/lib/support/tests/TestStateMachine.cpp @@ -16,10 +16,10 @@ * limitations under the License. */ +#include + #include -#include #include -#include namespace { @@ -166,67 +166,67 @@ class SimpleStateMachine ~SimpleStateMachine() {} }; -void TestInit(nlTestSuite * inSuite, void * inContext) +TEST(TestStateMachine, TestInit) { // state machine initializes to State1 SimpleStateMachine fsm; - NL_TEST_ASSERT(inSuite, fsm.mStateMachine.GetState().Is()); + EXPECT_TRUE(fsm.mStateMachine.GetState().Is()); } -void TestIgnoredEvents(nlTestSuite * inSuite, void * inContext) +TEST(TestStateMachine, TestIgnoredEvents) { // in State1 - ignore Event1 and Event3 SimpleStateMachine fsm; fsm.mStateMachine.Dispatch(Event::Create()); - NL_TEST_ASSERT(inSuite, fsm.mStateMachine.GetState().Is()); + EXPECT_TRUE(fsm.mStateMachine.GetState().Is()); fsm.mStateMachine.Dispatch(Event::Create()); - NL_TEST_ASSERT(inSuite, fsm.mStateMachine.GetState().Is()); + EXPECT_TRUE(fsm.mStateMachine.GetState().Is()); // transition to State2 fsm.mStateMachine.Dispatch(Event::Create()); - NL_TEST_ASSERT(inSuite, fsm.mStateMachine.GetState().Is()); + EXPECT_TRUE(fsm.mStateMachine.GetState().Is()); // in State2 - ignore Event2 and Event3 fsm.mStateMachine.Dispatch(Event::Create()); - NL_TEST_ASSERT(inSuite, fsm.mStateMachine.GetState().Is()); + EXPECT_TRUE(fsm.mStateMachine.GetState().Is()); fsm.mStateMachine.Dispatch(Event::Create()); - NL_TEST_ASSERT(inSuite, fsm.mStateMachine.GetState().Is()); + EXPECT_TRUE(fsm.mStateMachine.GetState().Is()); } -void TestTransitions(nlTestSuite * inSuite, void * inContext) +TEST(TestStateMachine, TestTransitions) { // in State1 SimpleStateMachine fsm; // dispatch Event2 to transition to State2 fsm.mStateMachine.Dispatch(Event::Create()); - NL_TEST_ASSERT(inSuite, fsm.mStateMachine.GetState().Is()); + EXPECT_TRUE(fsm.mStateMachine.GetState().Is()); // dispatch Event1 to transition back to State1 fsm.mStateMachine.Dispatch(Event::Create()); - NL_TEST_ASSERT(inSuite, fsm.mStateMachine.GetState().Is()); + EXPECT_TRUE(fsm.mStateMachine.GetState().Is()); // dispatch Event2 to transition to State2 fsm.mStateMachine.Dispatch(Event::Create()); - NL_TEST_ASSERT(inSuite, fsm.mStateMachine.GetState().Is()); + EXPECT_TRUE(fsm.mStateMachine.GetState().Is()); // dispatch Event4 to transitions to State1. fsm.mStateMachine.Dispatch(Event::Create()); - NL_TEST_ASSERT(inSuite, fsm.mStateMachine.GetState().Is()); + EXPECT_TRUE(fsm.mStateMachine.GetState().Is()); } -void TestTransitionsDispatch(nlTestSuite * inSuite, void * inContext) +TEST(TestStateMachine, TestTransitionsDispatch) { // in State1 SimpleStateMachine fsm; // Dispatch Event4, which in turn dispatches Event2 from the transitions // table and ultimately places us in State2. fsm.mStateMachine.Dispatch(Event::Create()); - NL_TEST_ASSERT(inSuite, fsm.mStateMachine.GetState().Is()); + EXPECT_TRUE(fsm.mStateMachine.GetState().Is()); } -void TestNestedDispatch(nlTestSuite * inSuite, void * inContext) +TEST(TestStateMachine, TestNestedDispatch) { // in State1 SimpleStateMachine fsm; // Dispatch Event5, which places us into State3, which will dispatch // Event5 again from its Enter method to place us into State2. fsm.mStateMachine.Dispatch(Event::Create()); - NL_TEST_ASSERT(inSuite, fsm.mStateMachine.GetState().Is()); + EXPECT_TRUE(fsm.mStateMachine.GetState().Is()); // Make sure that Enter methods execute the correct number of times. // This helps verify that pattern matching is working correctly. // Specifically, we need to verify this case: State3 creates State2 @@ -238,74 +238,45 @@ void TestNestedDispatch(nlTestSuite * inSuite, void * inContext) // been constructed when the State3 Enter method executes a second // time. The state machine pattern matching has code to explicitly // prevent this double-execution. This is testing that. - NL_TEST_ASSERT(inSuite, fsm.mTransitions.mFactory.ms1.mEntered == 0); - NL_TEST_ASSERT(inSuite, fsm.mTransitions.mFactory.ms1.mExited == 1); - NL_TEST_ASSERT(inSuite, fsm.mTransitions.mFactory.ms1.mLogged == 0); - NL_TEST_ASSERT(inSuite, fsm.mTransitions.mFactory.ms2.mEntered == 1); - NL_TEST_ASSERT(inSuite, fsm.mTransitions.mFactory.ms2.mExited == 0); - NL_TEST_ASSERT(inSuite, fsm.mTransitions.mFactory.ms2.mLogged == 1); - NL_TEST_ASSERT(inSuite, fsm.mTransitions.mFactory.ms3.mEntered == 1); - NL_TEST_ASSERT(inSuite, fsm.mTransitions.mFactory.ms3.mExited == 1); - NL_TEST_ASSERT(inSuite, fsm.mTransitions.mFactory.ms3.mLogged == 1); + EXPECT_EQ(fsm.mTransitions.mFactory.ms1.mEntered, 0u); + EXPECT_EQ(fsm.mTransitions.mFactory.ms1.mExited, 1u); + EXPECT_EQ(fsm.mTransitions.mFactory.ms1.mLogged, 0u); + EXPECT_EQ(fsm.mTransitions.mFactory.ms2.mEntered, 1u); + EXPECT_EQ(fsm.mTransitions.mFactory.ms2.mExited, 0u); + EXPECT_EQ(fsm.mTransitions.mFactory.ms2.mLogged, 1u); + EXPECT_EQ(fsm.mTransitions.mFactory.ms3.mEntered, 1u); + EXPECT_EQ(fsm.mTransitions.mFactory.ms3.mExited, 1u); + EXPECT_EQ(fsm.mTransitions.mFactory.ms3.mLogged, 1u); } -void TestMethodExec(nlTestSuite * inSuite, void * inContext) +TEST(TestStateMachine, TestMethodExec) { // in State1 SimpleStateMachine fsm; // transition to State2 fsm.mStateMachine.Dispatch(Event::Create()); - NL_TEST_ASSERT(inSuite, fsm.mStateMachine.GetState().Is()); + EXPECT_TRUE(fsm.mStateMachine.GetState().Is()); // verify expected method calls - NL_TEST_ASSERT(inSuite, fsm.mTransitions.mFactory.ms1.mEntered == 0); - NL_TEST_ASSERT(inSuite, fsm.mTransitions.mFactory.ms1.mExited == 1); - NL_TEST_ASSERT(inSuite, fsm.mTransitions.mFactory.ms1.mLogged == 0); - NL_TEST_ASSERT(inSuite, fsm.mTransitions.mFactory.ms1.mPrevious == nullptr); - NL_TEST_ASSERT(inSuite, fsm.mTransitions.mFactory.ms2.mEntered == 1); - NL_TEST_ASSERT(inSuite, fsm.mTransitions.mFactory.ms2.mExited == 0); - NL_TEST_ASSERT(inSuite, fsm.mTransitions.mFactory.ms2.mLogged == 1); - NL_TEST_ASSERT(inSuite, strcmp(fsm.mTransitions.mFactory.ms2.mPrevious, "State1") == 0); + EXPECT_EQ(fsm.mTransitions.mFactory.ms1.mEntered, 0u); + EXPECT_EQ(fsm.mTransitions.mFactory.ms1.mExited, 1u); + EXPECT_EQ(fsm.mTransitions.mFactory.ms1.mLogged, 0u); + EXPECT_EQ(fsm.mTransitions.mFactory.ms1.mPrevious, nullptr); + EXPECT_EQ(fsm.mTransitions.mFactory.ms2.mEntered, 1u); + EXPECT_EQ(fsm.mTransitions.mFactory.ms2.mExited, 0u); + EXPECT_EQ(fsm.mTransitions.mFactory.ms2.mLogged, 1u); + EXPECT_STREQ(fsm.mTransitions.mFactory.ms2.mPrevious, "State1"); // transition back to State1 fsm.mStateMachine.Dispatch(Event::Create()); - NL_TEST_ASSERT(inSuite, fsm.mStateMachine.GetState().Is()); + EXPECT_TRUE(fsm.mStateMachine.GetState().Is()); // verify expected method calls - NL_TEST_ASSERT(inSuite, fsm.mTransitions.mFactory.ms1.mEntered == 1); - NL_TEST_ASSERT(inSuite, fsm.mTransitions.mFactory.ms1.mExited == 1); - NL_TEST_ASSERT(inSuite, fsm.mTransitions.mFactory.ms1.mLogged == 1); - NL_TEST_ASSERT(inSuite, strcmp(fsm.mTransitions.mFactory.ms1.mPrevious, "State2") == 0); - NL_TEST_ASSERT(inSuite, fsm.mTransitions.mFactory.ms2.mEntered == 1); - NL_TEST_ASSERT(inSuite, fsm.mTransitions.mFactory.ms2.mExited == 1); - NL_TEST_ASSERT(inSuite, fsm.mTransitions.mFactory.ms2.mLogged == 1); - NL_TEST_ASSERT(inSuite, strcmp(fsm.mTransitions.mFactory.ms2.mPrevious, "State1") == 0); -} - -int Setup(void * inContext) -{ - return SUCCESS; -} - -int Teardown(void * inContext) -{ - return SUCCESS; + EXPECT_EQ(fsm.mTransitions.mFactory.ms1.mEntered, 1u); + EXPECT_EQ(fsm.mTransitions.mFactory.ms1.mExited, 1u); + EXPECT_EQ(fsm.mTransitions.mFactory.ms1.mLogged, 1u); + EXPECT_STREQ(fsm.mTransitions.mFactory.ms1.mPrevious, "State2"); + EXPECT_EQ(fsm.mTransitions.mFactory.ms2.mEntered, 1u); + EXPECT_EQ(fsm.mTransitions.mFactory.ms2.mExited, 1u); + EXPECT_EQ(fsm.mTransitions.mFactory.ms2.mLogged, 1u); + EXPECT_STREQ(fsm.mTransitions.mFactory.ms2.mPrevious, "State1"); } } // namespace - -static const nlTest sTests[] = { - NL_TEST_DEF("TestInit", TestInit), - NL_TEST_DEF("TestIgnoredEvents", TestIgnoredEvents), - NL_TEST_DEF("TestTransitions", TestTransitions), - NL_TEST_DEF("TestTransitionsDispatch", TestTransitionsDispatch), - NL_TEST_DEF("TestNestedDispatch", TestNestedDispatch), - NL_TEST_DEF("TestMethodExec", TestMethodExec), - NL_TEST_SENTINEL(), -}; - -int StateMachineTestSuite() -{ - nlTestSuite suite = { "CHIP State Machine tests", &sTests[0], Setup, Teardown }; - nlTestRunner(&suite, nullptr); - return nlTestRunnerStats(&suite); -} - -CHIP_REGISTER_TEST_SUITE(StateMachineTestSuite); diff --git a/src/lib/support/tests/TestThreadOperationalDataset.cpp b/src/lib/support/tests/TestThreadOperationalDataset.cpp index 27e18eac87e23e..d9e13c8c25705f 100644 --- a/src/lib/support/tests/TestThreadOperationalDataset.cpp +++ b/src/lib/support/tests/TestThreadOperationalDataset.cpp @@ -14,286 +14,252 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#include -#include -#include -#include +#include + +#include +#include namespace { using namespace chip; -void TestInit(nlTestSuite * inSuite, void * inContext) +class TestThreadOperationalDataset : public ::testing::Test +{ +public: + static void SetUpTestSuite() { ASSERT_EQ(chip::Platform::MemoryInit(), CHIP_NO_ERROR); } + static void TearDownTestSuite() { chip::Platform::MemoryShutdown(); } + + static Thread::OperationalDataset dataset; +}; + +Thread::OperationalDataset TestThreadOperationalDataset::dataset; + +TEST_F(TestThreadOperationalDataset, TestInit) { - Thread::OperationalDataset & dataset = *static_cast(inContext); uint8_t longerThanOperationalDatasetSize[255]{}; - NL_TEST_ASSERT(inSuite, dataset.Init(ByteSpan(longerThanOperationalDatasetSize)) == CHIP_ERROR_INVALID_ARGUMENT); - NL_TEST_ASSERT(inSuite, dataset.Init(ByteSpan()) == CHIP_NO_ERROR); + EXPECT_EQ(dataset.Init(ByteSpan(longerThanOperationalDatasetSize)), CHIP_ERROR_INVALID_ARGUMENT); + EXPECT_EQ(dataset.Init(ByteSpan()), CHIP_NO_ERROR); { uint8_t data[] = { 0x01, 0x02, 0x03 }; - NL_TEST_ASSERT(inSuite, dataset.Init(ByteSpan(data)) == CHIP_ERROR_INVALID_ARGUMENT); + EXPECT_EQ(dataset.Init(ByteSpan(data)), CHIP_ERROR_INVALID_ARGUMENT); } { uint8_t data[] = { 0x01 }; - NL_TEST_ASSERT(inSuite, dataset.Init(ByteSpan(data)) == CHIP_ERROR_INVALID_ARGUMENT); + EXPECT_EQ(dataset.Init(ByteSpan(data)), CHIP_ERROR_INVALID_ARGUMENT); } } -void TestActiveTimestamp(nlTestSuite * inSuite, void * inContext) +TEST_F(TestThreadOperationalDataset, TestActiveTimestamp) { static constexpr uint64_t kActiveTimestampValue = 1; - Thread::OperationalDataset & dataset = *static_cast(inContext); - uint64_t activeTimestamp = 0; - NL_TEST_ASSERT(inSuite, dataset.SetActiveTimestamp(kActiveTimestampValue) == CHIP_NO_ERROR); - NL_TEST_ASSERT(inSuite, dataset.GetActiveTimestamp(activeTimestamp) == CHIP_NO_ERROR); - NL_TEST_ASSERT(inSuite, activeTimestamp == kActiveTimestampValue); + EXPECT_EQ(dataset.SetActiveTimestamp(kActiveTimestampValue), CHIP_NO_ERROR); + EXPECT_EQ(dataset.GetActiveTimestamp(activeTimestamp), CHIP_NO_ERROR); + EXPECT_EQ(activeTimestamp, kActiveTimestampValue); } -void TestChannel(nlTestSuite * inSuite, void * inContext) +TEST_F(TestThreadOperationalDataset, TestChannel) { static constexpr uint16_t kChannelValue = 15; - Thread::OperationalDataset & dataset = *static_cast(inContext); - uint16_t channel = 0; - NL_TEST_ASSERT(inSuite, dataset.SetChannel(kChannelValue) == CHIP_NO_ERROR); - NL_TEST_ASSERT(inSuite, dataset.GetChannel(channel) == CHIP_NO_ERROR); - NL_TEST_ASSERT(inSuite, channel == kChannelValue); + EXPECT_EQ(dataset.SetChannel(kChannelValue), CHIP_NO_ERROR); + EXPECT_EQ(dataset.GetChannel(channel), CHIP_NO_ERROR); + EXPECT_EQ(channel, kChannelValue); } -void TestExtendedPanId(nlTestSuite * inSuite, void * inContext) +TEST_F(TestThreadOperationalDataset, TestExtendedPanId) { static constexpr uint8_t kExtendedPanId[] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77 }; - Thread::OperationalDataset & dataset = *static_cast(inContext); - uint8_t extendedPanId[Thread::kSizeExtendedPanId] = { 0 }; - NL_TEST_ASSERT(inSuite, dataset.SetExtendedPanId(kExtendedPanId) == CHIP_NO_ERROR); - NL_TEST_ASSERT(inSuite, dataset.GetExtendedPanId(extendedPanId) == CHIP_NO_ERROR); - NL_TEST_ASSERT(inSuite, memcmp(extendedPanId, kExtendedPanId, sizeof(kExtendedPanId)) == 0); + EXPECT_EQ(dataset.SetExtendedPanId(kExtendedPanId), CHIP_NO_ERROR); + EXPECT_EQ(dataset.GetExtendedPanId(extendedPanId), CHIP_NO_ERROR); + EXPECT_EQ(memcmp(extendedPanId, kExtendedPanId, sizeof(kExtendedPanId)), 0); ByteSpan span; - NL_TEST_ASSERT(inSuite, dataset.GetExtendedPanIdAsByteSpan(span) == CHIP_NO_ERROR); - NL_TEST_ASSERT(inSuite, span.size() == sizeof(kExtendedPanId)); - NL_TEST_ASSERT(inSuite, memcmp(extendedPanId, span.data(), sizeof(kExtendedPanId)) == 0); + EXPECT_EQ(dataset.GetExtendedPanIdAsByteSpan(span), CHIP_NO_ERROR); + EXPECT_EQ(span.size(), sizeof(kExtendedPanId)); + EXPECT_EQ(memcmp(extendedPanId, span.data(), sizeof(kExtendedPanId)), 0); } -void TestMasterKey(nlTestSuite * inSuite, void * inContext) +TEST_F(TestThreadOperationalDataset, TestMasterKey) { static constexpr uint8_t kMasterKey[] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff }; - Thread::OperationalDataset & dataset = *static_cast(inContext); - uint8_t masterKey[Thread::kSizeMasterKey] = { 0 }; - NL_TEST_ASSERT(inSuite, dataset.SetMasterKey(kMasterKey) == CHIP_NO_ERROR); - NL_TEST_ASSERT(inSuite, dataset.GetMasterKey(masterKey) == CHIP_NO_ERROR); - NL_TEST_ASSERT(inSuite, memcmp(masterKey, kMasterKey, sizeof(kMasterKey)) == 0); + EXPECT_EQ(dataset.SetMasterKey(kMasterKey), CHIP_NO_ERROR); + EXPECT_EQ(dataset.GetMasterKey(masterKey), CHIP_NO_ERROR); + EXPECT_EQ(memcmp(masterKey, kMasterKey, sizeof(kMasterKey)), 0); } -void TestMeshLocalPrefix(nlTestSuite * inSuite, void * inContext) +TEST_F(TestThreadOperationalDataset, TestMeshLocalPrefix) { static constexpr uint8_t kMeshLocalPrefix[] = { 0xfd, 0xde, 0xad, 0x00, 0xbe, 0xef, 0x00, 0x00 }; - Thread::OperationalDataset & dataset = *static_cast(inContext); - uint8_t meshLocalPrefix[Thread::kSizeMeshLocalPrefix] = { 0 }; - NL_TEST_ASSERT(inSuite, dataset.SetMeshLocalPrefix(kMeshLocalPrefix) == CHIP_NO_ERROR); - NL_TEST_ASSERT(inSuite, dataset.GetMeshLocalPrefix(meshLocalPrefix) == CHIP_NO_ERROR); - NL_TEST_ASSERT(inSuite, memcmp(meshLocalPrefix, kMeshLocalPrefix, sizeof(kMeshLocalPrefix)) == 0); + EXPECT_EQ(dataset.SetMeshLocalPrefix(kMeshLocalPrefix), CHIP_NO_ERROR); + EXPECT_EQ(dataset.GetMeshLocalPrefix(meshLocalPrefix), CHIP_NO_ERROR); + EXPECT_EQ(memcmp(meshLocalPrefix, kMeshLocalPrefix, sizeof(kMeshLocalPrefix)), 0); } -void TestNetworkName(nlTestSuite * inSuite, void * inContext) +TEST_F(TestThreadOperationalDataset, TestNetworkName) { static constexpr char kNetworkName[] = "ThreadNetwork"; - Thread::OperationalDataset & dataset = *static_cast(inContext); - char networkName[Thread::kSizeNetworkName + 1] = { 0 }; - NL_TEST_ASSERT(inSuite, dataset.SetNetworkName(kNetworkName) == CHIP_NO_ERROR); - NL_TEST_ASSERT(inSuite, dataset.GetNetworkName(networkName) == CHIP_NO_ERROR); - NL_TEST_ASSERT(inSuite, strcmp(networkName, kNetworkName) == 0); + EXPECT_EQ(dataset.SetNetworkName(kNetworkName), CHIP_NO_ERROR); + EXPECT_EQ(dataset.GetNetworkName(networkName), CHIP_NO_ERROR); + EXPECT_STREQ(networkName, kNetworkName); - NL_TEST_ASSERT(inSuite, dataset.SetNetworkName("0123456789abcdef") == CHIP_NO_ERROR); - NL_TEST_ASSERT(inSuite, dataset.SetNetworkName("0123456789abcdefg") == CHIP_ERROR_INVALID_STRING_LENGTH); - NL_TEST_ASSERT(inSuite, dataset.SetNetworkName("") == CHIP_ERROR_INVALID_STRING_LENGTH); + EXPECT_EQ(dataset.SetNetworkName("0123456789abcdef"), CHIP_NO_ERROR); + EXPECT_EQ(dataset.SetNetworkName("0123456789abcdefg"), CHIP_ERROR_INVALID_STRING_LENGTH); + EXPECT_EQ(dataset.SetNetworkName(""), CHIP_ERROR_INVALID_STRING_LENGTH); } -void TestPanId(nlTestSuite * inSuite, void * inContext) +TEST_F(TestThreadOperationalDataset, TestPanId) { static constexpr uint16_t kPanIdValue = 0x1234; - Thread::OperationalDataset & dataset = *static_cast(inContext); - uint16_t panid = 0; - NL_TEST_ASSERT(inSuite, dataset.SetPanId(kPanIdValue) == CHIP_NO_ERROR); - NL_TEST_ASSERT(inSuite, dataset.GetPanId(panid) == CHIP_NO_ERROR); - NL_TEST_ASSERT(inSuite, panid == kPanIdValue); + EXPECT_EQ(dataset.SetPanId(kPanIdValue), CHIP_NO_ERROR); + EXPECT_EQ(dataset.GetPanId(panid), CHIP_NO_ERROR); + EXPECT_EQ(panid, kPanIdValue); } -void TestPSKc(nlTestSuite * inSuite, void * inContext) +TEST_F(TestThreadOperationalDataset, TestPSKc) { static constexpr uint8_t kPSKc[] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff }; - Thread::OperationalDataset & dataset = *static_cast(inContext); - uint8_t pskc[Thread::kSizePSKc] = { 0 }; - NL_TEST_ASSERT(inSuite, dataset.SetPSKc(kPSKc) == CHIP_NO_ERROR); - NL_TEST_ASSERT(inSuite, dataset.GetPSKc(pskc) == CHIP_NO_ERROR); - NL_TEST_ASSERT(inSuite, memcmp(pskc, kPSKc, sizeof(kPSKc)) == 0); + EXPECT_EQ(dataset.SetPSKc(kPSKc), CHIP_NO_ERROR); + EXPECT_EQ(dataset.GetPSKc(pskc), CHIP_NO_ERROR); + EXPECT_FALSE(memcmp(pskc, kPSKc, sizeof(kPSKc))); } -void TestUnsetMasterKey(nlTestSuite * inSuite, void * inContext) +TEST_F(TestThreadOperationalDataset, TestUnsetMasterKey) { - Thread::OperationalDataset & dataset = *static_cast(inContext); uint8_t masterKey[Thread::kSizeMasterKey] = { 0 }; - NL_TEST_ASSERT(inSuite, dataset.GetMasterKey(masterKey) == CHIP_NO_ERROR); + EXPECT_EQ(dataset.GetMasterKey(masterKey), CHIP_NO_ERROR); dataset.UnsetMasterKey(); - NL_TEST_ASSERT(inSuite, dataset.GetMasterKey(masterKey) == CHIP_ERROR_TLV_TAG_NOT_FOUND); - NL_TEST_ASSERT(inSuite, dataset.SetMasterKey(masterKey) == CHIP_NO_ERROR); + EXPECT_EQ(dataset.GetMasterKey(masterKey), CHIP_ERROR_TLV_TAG_NOT_FOUND); + EXPECT_EQ(dataset.SetMasterKey(masterKey), CHIP_NO_ERROR); } -void TestUnsetPSKc(nlTestSuite * inSuite, void * inContext) +TEST_F(TestThreadOperationalDataset, TestUnsetPSKc) { - Thread::OperationalDataset & dataset = *static_cast(inContext); uint8_t pskc[Thread::kSizePSKc] = { 0 }; - NL_TEST_ASSERT(inSuite, dataset.GetPSKc(pskc) == CHIP_NO_ERROR); + EXPECT_EQ(dataset.GetPSKc(pskc), CHIP_NO_ERROR); dataset.UnsetPSKc(); - NL_TEST_ASSERT(inSuite, dataset.GetPSKc(pskc) == CHIP_ERROR_TLV_TAG_NOT_FOUND); - NL_TEST_ASSERT(inSuite, dataset.SetPSKc(pskc) == CHIP_NO_ERROR); + EXPECT_EQ(dataset.GetPSKc(pskc), CHIP_ERROR_TLV_TAG_NOT_FOUND); + EXPECT_EQ(dataset.SetPSKc(pskc), CHIP_NO_ERROR); } -void TestClear(nlTestSuite * inSuite, void * inContext) +TEST_F(TestThreadOperationalDataset, TestClear) { - Thread::OperationalDataset & dataset = *static_cast(inContext); { uint64_t activeTimestamp; - NL_TEST_ASSERT(inSuite, dataset.GetActiveTimestamp(activeTimestamp) == CHIP_NO_ERROR); + EXPECT_EQ(dataset.GetActiveTimestamp(activeTimestamp), CHIP_NO_ERROR); } { uint16_t channel; - NL_TEST_ASSERT(inSuite, dataset.GetChannel(channel) == CHIP_NO_ERROR); + EXPECT_EQ(dataset.GetChannel(channel), CHIP_NO_ERROR); } { uint8_t extendedPanId[Thread::kSizeExtendedPanId] = { 0 }; - NL_TEST_ASSERT(inSuite, dataset.GetExtendedPanId(extendedPanId) == CHIP_NO_ERROR); + EXPECT_EQ(dataset.GetExtendedPanId(extendedPanId), CHIP_NO_ERROR); } { uint8_t masterKey[Thread::kSizeMasterKey] = { 0 }; - NL_TEST_ASSERT(inSuite, dataset.GetMasterKey(masterKey) == CHIP_NO_ERROR); + EXPECT_EQ(dataset.GetMasterKey(masterKey), CHIP_NO_ERROR); } { uint8_t meshLocalPrefix[Thread::kSizeMeshLocalPrefix] = { 0 }; - NL_TEST_ASSERT(inSuite, dataset.GetMeshLocalPrefix(meshLocalPrefix) == CHIP_NO_ERROR); + EXPECT_EQ(dataset.GetMeshLocalPrefix(meshLocalPrefix), CHIP_NO_ERROR); } { char networkName[Thread::kSizeNetworkName + 1] = { 0 }; - NL_TEST_ASSERT(inSuite, dataset.GetNetworkName(networkName) == CHIP_NO_ERROR); + EXPECT_EQ(dataset.GetNetworkName(networkName), CHIP_NO_ERROR); } { uint16_t panid; - NL_TEST_ASSERT(inSuite, dataset.GetPanId(panid) == CHIP_NO_ERROR); + EXPECT_EQ(dataset.GetPanId(panid), CHIP_NO_ERROR); } { uint8_t pskc[Thread::kSizePSKc] = { 0 }; - NL_TEST_ASSERT(inSuite, dataset.GetPSKc(pskc) == CHIP_NO_ERROR); + EXPECT_EQ(dataset.GetPSKc(pskc), CHIP_NO_ERROR); } dataset.Clear(); { uint64_t activeTimestamp; - NL_TEST_ASSERT(inSuite, dataset.GetActiveTimestamp(activeTimestamp) == CHIP_ERROR_TLV_TAG_NOT_FOUND); + EXPECT_EQ(dataset.GetActiveTimestamp(activeTimestamp), CHIP_ERROR_TLV_TAG_NOT_FOUND); } { uint16_t channel; - NL_TEST_ASSERT(inSuite, dataset.GetChannel(channel) == CHIP_ERROR_TLV_TAG_NOT_FOUND); + EXPECT_EQ(dataset.GetChannel(channel), CHIP_ERROR_TLV_TAG_NOT_FOUND); } { uint8_t extendedPanId[Thread::kSizeExtendedPanId] = { 0 }; - NL_TEST_ASSERT(inSuite, dataset.GetExtendedPanId(extendedPanId) == CHIP_ERROR_TLV_TAG_NOT_FOUND); + EXPECT_EQ(dataset.GetExtendedPanId(extendedPanId), CHIP_ERROR_TLV_TAG_NOT_FOUND); } { uint8_t masterKey[Thread::kSizeMasterKey] = { 0 }; - NL_TEST_ASSERT(inSuite, dataset.GetMasterKey(masterKey) == CHIP_ERROR_TLV_TAG_NOT_FOUND); + EXPECT_EQ(dataset.GetMasterKey(masterKey), CHIP_ERROR_TLV_TAG_NOT_FOUND); } { uint8_t meshLocalPrefix[Thread::kSizeMeshLocalPrefix] = { 0 }; - NL_TEST_ASSERT(inSuite, dataset.GetMeshLocalPrefix(meshLocalPrefix) == CHIP_ERROR_TLV_TAG_NOT_FOUND); + EXPECT_EQ(dataset.GetMeshLocalPrefix(meshLocalPrefix), CHIP_ERROR_TLV_TAG_NOT_FOUND); } { char networkName[Thread::kSizeNetworkName + 1] = { 0 }; - NL_TEST_ASSERT(inSuite, dataset.GetNetworkName(networkName) == CHIP_ERROR_TLV_TAG_NOT_FOUND); + EXPECT_EQ(dataset.GetNetworkName(networkName), CHIP_ERROR_TLV_TAG_NOT_FOUND); } { uint16_t panid; - NL_TEST_ASSERT(inSuite, dataset.GetPanId(panid) == CHIP_ERROR_TLV_TAG_NOT_FOUND); + EXPECT_EQ(dataset.GetPanId(panid), CHIP_ERROR_TLV_TAG_NOT_FOUND); } { uint8_t pskc[Thread::kSizePSKc] = { 0 }; - NL_TEST_ASSERT(inSuite, dataset.GetPSKc(pskc) == CHIP_ERROR_TLV_TAG_NOT_FOUND); + EXPECT_EQ(dataset.GetPSKc(pskc), CHIP_ERROR_TLV_TAG_NOT_FOUND); } } -const nlTest sTests[] = { - NL_TEST_DEF("TestInit", TestInit), // - NL_TEST_DEF("TestActiveTimestamp", TestActiveTimestamp), // - NL_TEST_DEF("TestChannel", TestChannel), // - NL_TEST_DEF("TestExtendedPanId", TestExtendedPanId), // - NL_TEST_DEF("TestMasterKey", TestMasterKey), // - NL_TEST_DEF("TestMeshLocalPrefix", TestMeshLocalPrefix), // - NL_TEST_DEF("TestNetworkName", TestNetworkName), // - NL_TEST_DEF("TestPanId", TestPanId), // - NL_TEST_DEF("TestPSKc", TestPSKc), // - NL_TEST_DEF("TestUnsetMasterKey", TestUnsetMasterKey), // - NL_TEST_DEF("TestUnsetPSKc", TestUnsetPSKc), // - NL_TEST_DEF("TestClear", TestClear), // - NL_TEST_SENTINEL() // -}; - } // namespace - -int TestThreadOperationalDatasetBuilder() -{ - nlTestSuite theSuite = { "ThreadOperationalDataset", sTests, nullptr, nullptr }; - - return ExecuteTestsWithContext(&theSuite); -} - -CHIP_REGISTER_TEST_SUITE(TestThreadOperationalDatasetBuilder) diff --git a/src/test_driver/openiotsdk/unit-tests/test_components_nl.txt b/src/test_driver/openiotsdk/unit-tests/test_components_nl.txt index e3d66b49d3f644..37f0bf2c39adbf 100644 --- a/src/test_driver/openiotsdk/unit-tests/test_components_nl.txt +++ b/src/test_driver/openiotsdk/unit-tests/test_components_nl.txt @@ -4,5 +4,4 @@ ICDServerTestsNL InetLayerTests MessagingLayerTests SecureChannelTestsNL -SupportTestsNL TransportLayerTests From 26be58444bffe8f674a08ecdc893c671c9ff7a96 Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Wed, 1 May 2024 16:18:33 +0200 Subject: [PATCH 21/33] [Python] Implement async friendly GetConnectedDevice (#32760) * [Python] Implement async friendly GetConnectedDevice Currently GetConnectedDeviceSync() is blocking e.g. when a new session needs to be created. This is not asyncio friendly as it blocks the whole event loop. Implement a asyncio friendly variant GetConnectedDevice() which is a co-routine function which can be awaited. * Drop bracket * Skip timeout only when passing None Change semantics slightly to make 0 mean don't wait at all. * Add API docs --- src/controller/python/chip/ChipDeviceCtrl.py | 84 +++++++++++++++++--- 1 file changed, 75 insertions(+), 9 deletions(-) diff --git a/src/controller/python/chip/ChipDeviceCtrl.py b/src/controller/python/chip/ChipDeviceCtrl.py index b553b2f85b641e..4e57e3d6044e67 100644 --- a/src/controller/python/chip/ChipDeviceCtrl.py +++ b/src/controller/python/chip/ChipDeviceCtrl.py @@ -787,8 +787,16 @@ def GetClusterHandler(self): return self._Cluster - def GetConnectedDeviceSync(self, nodeid, allowPASE=True, timeoutMs: int = None): - ''' Returns DeviceProxyWrapper upon success.''' + def GetConnectedDeviceSync(self, nodeid, allowPASE: bool = True, timeoutMs: int = None): + ''' Gets an OperationalDeviceProxy or CommissioneeDeviceProxy for the specified Node. + + nodeId: Target's Node ID + allowPASE: Get a device proxy of a device being commissioned. + timeoutMs: Timeout for a timed invoke request. Omit or set to 'None' to indicate a non-timed request. + + Returns: + - DeviceProxyWrapper on success + ''' self.CheckIsActive() returnDevice = c_void_p(None) @@ -824,7 +832,7 @@ def deviceAvailable(self, device, err): if returnDevice.value is None: with deviceAvailableCV: timeout = None - if (timeoutMs): + if timeoutMs is not None: timeout = float(timeoutMs) / 1000 ret = deviceAvailableCV.wait(timeout) @@ -836,6 +844,64 @@ def deviceAvailable(self, device, err): return DeviceProxyWrapper(returnDevice, self._dmLib) + async def GetConnectedDevice(self, nodeid, allowPASE: bool = True, timeoutMs: int = None): + ''' Gets an OperationalDeviceProxy or CommissioneeDeviceProxy for the specified Node. + + nodeId: Target's Node ID + allowPASE: Get a device proxy of a device being commissioned. + timeoutMs: Timeout for a timed invoke request. Omit or set to 'None' to indicate a non-timed request. + + Returns: + - DeviceProxyWrapper on success + ''' + self.CheckIsActive() + + if allowPASE: + returnDevice = c_void_p(None) + res = self._ChipStack.Call(lambda: self._dmLib.pychip_GetDeviceBeingCommissioned( + self.devCtrl, nodeid, byref(returnDevice)), timeoutMs) + if res.is_success: + logging.info('Using PASE connection') + return DeviceProxyWrapper(returnDevice) + + eventLoop = asyncio.get_running_loop() + future = eventLoop.create_future() + + class DeviceAvailableClosure(): + def __init__(self, loop, future: asyncio.Future): + self._returnDevice = c_void_p(None) + self._returnErr = None + self._event_loop = loop + self._future = future + + def _deviceAvailable(self): + if self._returnDevice.value is not None: + self._future.set_result(self._returnDevice) + else: + self._future.set_exception(self._returnErr.to_exception()) + + def deviceAvailable(self, device, err): + self._returnDevice = c_void_p(device) + self._returnErr = err + self._event_loop.call_soon_threadsafe(self._deviceAvailable) + ctypes.pythonapi.Py_DecRef(ctypes.py_object(self)) + + closure = DeviceAvailableClosure(eventLoop, future) + ctypes.pythonapi.Py_IncRef(ctypes.py_object(closure)) + self._ChipStack.Call(lambda: self._dmLib.pychip_GetConnectedDeviceByNodeId( + self.devCtrl, nodeid, ctypes.py_object(closure), _DeviceAvailableCallback), + timeoutMs).raise_on_error() + + # The callback might have been received synchronously (during self._ChipStack.Call()). + # In that case the Future has already been set it will return immediately + if timeoutMs is not None: + timeout = float(timeoutMs) / 1000 + await asyncio.wait_for(future, timeout=timeout) + else: + await future + + return DeviceProxyWrapper(future.result(), self._dmLib) + def ComputeRoundTripTimeout(self, nodeid, upperLayerProcessingTimeoutMs: int = 0): ''' Returns a computed timeout value based on the round-trip time it takes for the peer at the other end of the session to receive a message, process it and send it back. This is computed based on the session type, the type of transport, @@ -900,7 +966,7 @@ async def TestOnlySendBatchCommands(self, nodeid: int, commands: typing.List[Clu eventLoop = asyncio.get_running_loop() future = eventLoop.create_future() - device = self.GetConnectedDeviceSync(nodeid, timeoutMs=interactionTimeoutMs) + device = await self.GetConnectedDevice(nodeid, timeoutMs=interactionTimeoutMs) ClusterCommand.TestOnlySendBatchCommands( future, eventLoop, device.deviceProxy, commands, @@ -921,7 +987,7 @@ async def TestOnlySendCommandTimedRequestFlagWithNoTimedInvoke(self, nodeid: int eventLoop = asyncio.get_running_loop() future = eventLoop.create_future() - device = self.GetConnectedDeviceSync(nodeid, timeoutMs=None) + device = await self.GetConnectedDevice(nodeid, timeoutMs=None) ClusterCommand.TestOnlySendCommandTimedRequestFlagWithNoTimedInvoke( future, eventLoop, responseType, device.deviceProxy, ClusterCommand.CommandPath( EndpointId=endpoint, @@ -953,7 +1019,7 @@ async def SendCommand(self, nodeid: int, endpoint: int, payload: ClusterObjects. eventLoop = asyncio.get_running_loop() future = eventLoop.create_future() - device = self.GetConnectedDeviceSync(nodeid, timeoutMs=interactionTimeoutMs) + device = await self.GetConnectedDevice(nodeid, timeoutMs=interactionTimeoutMs) ClusterCommand.SendCommand( future, eventLoop, responseType, device.deviceProxy, ClusterCommand.CommandPath( EndpointId=endpoint, @@ -994,7 +1060,7 @@ async def SendBatchCommands(self, nodeid: int, commands: typing.List[ClusterComm eventLoop = asyncio.get_running_loop() future = eventLoop.create_future() - device = self.GetConnectedDeviceSync(nodeid, timeoutMs=interactionTimeoutMs) + device = await self.GetConnectedDevice(nodeid, timeoutMs=interactionTimeoutMs) ClusterCommand.SendBatchCommands( future, eventLoop, device.deviceProxy, commands, @@ -1044,7 +1110,7 @@ async def WriteAttribute(self, nodeid: int, eventLoop = asyncio.get_running_loop() future = eventLoop.create_future() - device = self.GetConnectedDeviceSync(nodeid, timeoutMs=interactionTimeoutMs) + device = await self.GetConnectedDevice(nodeid, timeoutMs=interactionTimeoutMs) attrs = [] for v in attributes: @@ -1272,7 +1338,7 @@ async def Read(self, nodeid: int, attributes: typing.List[typing.Union[ eventLoop = asyncio.get_running_loop() future = eventLoop.create_future() - device = self.GetConnectedDeviceSync(nodeid) + device = await self.GetConnectedDevice(nodeid) attributePaths = [self._parseAttributePathTuple( v) for v in attributes] if attributes else None clusterDataVersionFilters = [self._parseDataVersionFilterTuple( From 5570be922195347a1dee9187c59d3acf87ae1e94 Mon Sep 17 00:00:00 2001 From: Justin Wood Date: Wed, 1 May 2024 08:18:15 -0700 Subject: [PATCH 22/33] Update .pullapprove.yml --- .pullapprove.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.pullapprove.yml b/.pullapprove.yml index f7da2711417441..c18d52a36eb3b9 100644 --- a/.pullapprove.yml +++ b/.pullapprove.yml @@ -173,6 +173,14 @@ groups: teams: [reviewers-samsung] reviews: request: 10 + shared-reviewers-eve: + type: optional + conditions: + - files.include('*') + reviewers: + teams: [reviewers-eve] + reviews: + request: 10 # shared-reviewers-signify disabled for now, because the reviewers-signify # team is empty and pullapprove seems to mis-handle that badly and treats # _all_ reviewers as being in this group. From f6b3594f83bef3d850a140e8e25cf967b0dc1418 Mon Sep 17 00:00:00 2001 From: fesseha-eve <88329315+fessehaeve@users.noreply.github.com> Date: Thu, 2 May 2024 12:29:30 +0200 Subject: [PATCH 23/33] Timesync improvements - part 1 (#32848) * change cluster revision in light-switch-app * added delegate functions for better usability * - made AttemptToGetTimeFromTrustedNode() public API - free readclient memory after read is complete * added default implementation for some delegate functions * added documentation for delegate functions --- .../light-switch-app.matter | 2 +- .../light-switch-common/light-switch-app.zap | 2 +- .../DefaultTimeSyncDelegate.cpp | 22 ----------------- .../DefaultTimeSyncDelegate.h | 5 ---- .../time-synchronization-delegate.h | 24 +++++++++++++++---- .../time-synchronization-server.cpp | 3 +++ .../time-synchronization-server.h | 3 ++- 7 files changed, 26 insertions(+), 35 deletions(-) diff --git a/examples/light-switch-app/light-switch-common/light-switch-app.matter b/examples/light-switch-app/light-switch-common/light-switch-app.matter index e51a772add14e2..65e7c5198a4052 100644 --- a/examples/light-switch-app/light-switch-common/light-switch-app.matter +++ b/examples/light-switch-app/light-switch-common/light-switch-app.matter @@ -2792,7 +2792,7 @@ endpoint 0 { callback attribute acceptedCommandList; callback attribute attributeList; ram attribute featureMap default = 0x0B; - ram attribute clusterRevision default = 1; + ram attribute clusterRevision default = 2; handle command SetUTCTime; handle command SetTrustedTimeSource; diff --git a/examples/light-switch-app/light-switch-common/light-switch-app.zap b/examples/light-switch-app/light-switch-common/light-switch-app.zap index ba56db35a2669b..dcfa64d7c5e88f 100644 --- a/examples/light-switch-app/light-switch-common/light-switch-app.zap +++ b/examples/light-switch-app/light-switch-common/light-switch-app.zap @@ -3826,7 +3826,7 @@ "storageOption": "RAM", "singleton": 0, "bounded": 0, - "defaultValue": "1", + "defaultValue": "2", "reportable": 1, "minInterval": 1, "maxInterval": 65534, diff --git a/src/app/clusters/time-synchronization-server/DefaultTimeSyncDelegate.cpp b/src/app/clusters/time-synchronization-server/DefaultTimeSyncDelegate.cpp index e436d19f6d6136..59fb8b0bbee24d 100644 --- a/src/app/clusters/time-synchronization-server/DefaultTimeSyncDelegate.cpp +++ b/src/app/clusters/time-synchronization-server/DefaultTimeSyncDelegate.cpp @@ -24,17 +24,6 @@ using chip::TimeSyncDataProvider; using namespace chip::app::Clusters::TimeSynchronization; -void DefaultTimeSyncDelegate::TimeZoneListChanged(const Span timeZoneList) -{ - // placeholder implementation -} - -bool DefaultTimeSyncDelegate::HandleUpdateDSTOffset(chip::CharSpan name) -{ - // placeholder implementation - return false; -} - bool DefaultTimeSyncDelegate::IsNTPAddressValid(chip::CharSpan ntp) { // placeholder implementation @@ -67,14 +56,3 @@ CHIP_ERROR DefaultTimeSyncDelegate::UpdateTimeFromPlatformSource(chip::Callback: } return CHIP_ERROR_NOT_IMPLEMENTED; } - -CHIP_ERROR DefaultTimeSyncDelegate::UpdateTimeUsingNTPFallback(const CharSpan & fallbackNTP, - chip::Callback::Callback * callback) -{ - return CHIP_ERROR_NOT_IMPLEMENTED; -} - -void DefaultTimeSyncDelegate::UTCTimeAvailabilityChanged(uint64_t time) -{ - // placeholder implementation -} diff --git a/src/app/clusters/time-synchronization-server/DefaultTimeSyncDelegate.h b/src/app/clusters/time-synchronization-server/DefaultTimeSyncDelegate.h index 01f156e4ea2ccb..0d78ef2f0fe6e9 100644 --- a/src/app/clusters/time-synchronization-server/DefaultTimeSyncDelegate.h +++ b/src/app/clusters/time-synchronization-server/DefaultTimeSyncDelegate.h @@ -29,14 +29,9 @@ class DefaultTimeSyncDelegate : public Delegate public: DefaultTimeSyncDelegate() : Delegate(){}; - void TimeZoneListChanged(const Span timeZoneList) override; - bool HandleUpdateDSTOffset(CharSpan name) override; bool IsNTPAddressValid(CharSpan ntp) override; bool IsNTPAddressDomain(CharSpan ntp) override; CHIP_ERROR UpdateTimeFromPlatformSource(chip::Callback::Callback * callback) override; - CHIP_ERROR UpdateTimeUsingNTPFallback(const CharSpan & fallbackNTP, - chip::Callback::Callback * callback) override; - void UTCTimeAvailabilityChanged(uint64_t time) override; }; } // namespace TimeSynchronization diff --git a/src/app/clusters/time-synchronization-server/time-synchronization-delegate.h b/src/app/clusters/time-synchronization-server/time-synchronization-delegate.h index 7d5bad65ff0d2e..f38153528118fd 100644 --- a/src/app/clusters/time-synchronization-server/time-synchronization-delegate.h +++ b/src/app/clusters/time-synchronization-server/time-synchronization-delegate.h @@ -56,7 +56,7 @@ class Delegate * * @param timeZoneList new time zone list */ - virtual void TimeZoneListChanged(const Span timeZoneList) = 0; + virtual void TimeZoneListChanged(const Span timeZoneList) {} /** * @brief Give the delegate the chance to call SetDSTOffset on the TimeSynchronizationServer with a list of * DST offsets based on the provided time zone name. If the delegate does so, it should return true. @@ -64,7 +64,7 @@ class Delegate * * @param name name of active time zone */ - virtual bool HandleUpdateDSTOffset(const CharSpan name) = 0; + virtual bool HandleUpdateDSTOffset(const CharSpan name) { return false; } /** * @brief Returns true if the provided string is a valid NTP address (either domain name or IPv6 address). * @@ -104,12 +104,26 @@ class Delegate * a CHIP_ERROR. */ virtual CHIP_ERROR UpdateTimeUsingNTPFallback(const CharSpan & fallbackNTP, - chip::Callback::Callback * callback) = 0; + chip::Callback::Callback * callback) + { + return CHIP_ERROR_NOT_IMPLEMENTED; + } /** - * @brief Signals application that UTCTime has changed through the timesync cluster. + * @brief Signals application that UTCTime has changed through the timesync cluster. This gets called when + * time is available for the first time or is updated. Therefore, @param time will always have a valid value. + * The negative case of time being unavailable is handled by NotifyTimeFailure(). + */ + virtual void UTCTimeAvailabilityChanged(uint64_t time) {} + /** + * @brief Signals application that a new trusted time source is available. The application can then decide + * if it wants to attempt to query for time from this source. + */ + virtual void TrustedTimeSourceAvailabilityChanged(bool available, GranularityEnum granularity) {} + /** + * @brief Signals application that fetching time has failed. The reason is not relevant. */ - virtual void UTCTimeAvailabilityChanged(uint64_t time) = 0; + virtual void NotifyTimeFailure() {} virtual ~Delegate() = default; diff --git a/src/app/clusters/time-synchronization-server/time-synchronization-server.cpp b/src/app/clusters/time-synchronization-server/time-synchronization-server.cpp index d03d7842911d51..fda3bb50d7fda0 100644 --- a/src/app/clusters/time-synchronization-server/time-synchronization-server.cpp +++ b/src/app/clusters/time-synchronization-server/time-synchronization-server.cpp @@ -215,6 +215,7 @@ static bool emitTimeFailureEvent(EndpointId ep) // TODO: re-schedule event for after min 1hr if no time is still available // https://github.com/project-chip/connectedhomeip/issues/27200 ChipLogProgress(Zcl, "Emit TimeFailure event [ep=%d]", ep); + GetDelegate()->NotifyTimeFailure(); return true; } @@ -356,6 +357,7 @@ void TimeSynchronizationServer::OnDone(ReadClient * apReadClient) SetUTCTime(kRootEndpointId, mTimeReadInfo->utcTime.Value(), ourGranularity, TimeSourceEnum::kNodeTimeCluster); if (err == CHIP_NO_ERROR) { + mTimeReadInfo = nullptr; return; } } @@ -504,6 +506,7 @@ CHIP_ERROR TimeSynchronizationServer::SetTrustedTimeSource(const DataModel::Null { AttemptToGetTime(); } + GetDelegate()->TrustedTimeSourceAvailabilityChanged(!mTrustedTimeSource.IsNull(), mGranularity); return err; } diff --git a/src/app/clusters/time-synchronization-server/time-synchronization-server.h b/src/app/clusters/time-synchronization-server/time-synchronization-server.h index ef40eaacc790c4..2581c9712e7862 100644 --- a/src/app/clusters/time-synchronization-server/time-synchronization-server.h +++ b/src/app/clusters/time-synchronization-server/time-synchronization-server.h @@ -123,6 +123,8 @@ class TimeSynchronizationServer : public FabricTable::Delegate // ReadClient::Callback functions void OnAttributeData(const ConcreteDataAttributePath & aPath, TLV::TLVReader * apData, const StatusIB & aStatus) override; void OnDone(ReadClient * apReadClient) override; + + CHIP_ERROR AttemptToGetTimeFromTrustedNode(); #endif // Platform event handler functions @@ -166,7 +168,6 @@ class TimeSynchronizationServer : public FabricTable::Delegate // Called when the platform is set up - attempts to get time using the recommended source list in the spec. void AttemptToGetTime(); - CHIP_ERROR AttemptToGetTimeFromTrustedNode(); // Attempts to get fallback NTP from the delegate (last available source) // If successful, the function will set mGranulatiry and the time source // If unsuccessful, it will emit a TimeFailure event. From de796eb65a004435fa9eefc6f19b7155f5be1fda Mon Sep 17 00:00:00 2001 From: Thirupathi S <108743108+Thirsrin@users.noreply.github.com> Date: Thu, 2 May 2024 19:20:30 +0530 Subject: [PATCH 24/33] [Linux]DGSW_2_3 fails CurrentHeapUsed is greater than CurrentHeapHighWatermark (#33252) * changes to store max heap size * Restyled by whitespace * Restyled by clang-format * typecast changes --------- Co-authored-by: Restyled.io --- .../Linux/DiagnosticDataProviderImpl.cpp | 22 ++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/src/platform/Linux/DiagnosticDataProviderImpl.cpp b/src/platform/Linux/DiagnosticDataProviderImpl.cpp index 74f7003676c051..cc57da65e2d036 100644 --- a/src/platform/Linux/DiagnosticDataProviderImpl.cpp +++ b/src/platform/Linux/DiagnosticDataProviderImpl.cpp @@ -74,6 +74,9 @@ enum class WiFiStatsCountType kWiFiOverrunCount }; +// Static variable to store the maximum heap size +static size_t maxHeapHighWatermark = 0; + CHIP_ERROR GetEthernetStatsCount(EthernetStatsCountType type, uint64_t & count) { CHIP_ERROR err = CHIP_ERROR_READ_FAILED; @@ -244,6 +247,11 @@ CHIP_ERROR DiagnosticDataProviderImpl::GetCurrentHeapUsed(uint64_t & currentHeap // the current running program. currentHeapUsed = mallocInfo.uordblks; + // Update the maximum heap high watermark if the current heap usage exceeds it. + if (currentHeapUsed > maxHeapHighWatermark) + { + maxHeapHighWatermark = currentHeapUsed; + } return CHIP_NO_ERROR; #endif } @@ -260,9 +268,15 @@ CHIP_ERROR DiagnosticDataProviderImpl::GetCurrentHeapHighWatermark(uint64_t & cu // has been used by the Node. // On Linux, since it uses virtual memory, whereby a page of memory could be copied to // the hard disk, called swap space, and free up that page of memory. So it is impossible - // to know accurately peak physical memory it use. We just return the current heap memory - // being used by the current running program. - currentHeapHighWatermark = mallocInfo.uordblks; + // to know accurately peak physical memory it use. + // Update the maximum heap high watermark if the current heap usage exceeds it. + if (mallocInfo.uordblks > static_cast(maxHeapHighWatermark)) + { + maxHeapHighWatermark = mallocInfo.uordblks; + } + + // Set the current heap high watermark. + currentHeapHighWatermark = maxHeapHighWatermark; return CHIP_NO_ERROR; #endif @@ -275,6 +289,8 @@ CHIP_ERROR DiagnosticDataProviderImpl::ResetWatermarks() // On Linux, the write operation is non-op since we always rely on the mallinfo system // function to get the current heap memory. + struct mallinfo mallocInfo = mallinfo(); + maxHeapHighWatermark = mallocInfo.uordblks; return CHIP_NO_ERROR; } From 16b8076551471b21852611cc087a87832e3581f9 Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Thu, 2 May 2024 11:37:26 -0400 Subject: [PATCH 25/33] Fix reference cycle between controller and data store in Matter.framework. (#33263) * Fix reference cycle between controller and data store in Matter.framework. Also adds some leak detection to unit tests in CI that would have caught this. * Address review comment. * Disable the leak checks for now, because we are getting unrelated positives. --- .github/workflows/darwin.yaml | 3 + .../CHIP/MTRDeviceControllerDataStore.mm | 66 ++++++++++++++----- .../CHIPTests/MTRPerControllerStorageTests.m | 10 +-- .../CHIPTests/TestHelpers/MTRTestCase.h | 28 ++++++++ .../CHIPTests/TestHelpers/MTRTestCase.mm | 44 +++++++++++++ .../Matter.xcodeproj/project.pbxproj | 6 ++ 6 files changed, 137 insertions(+), 20 deletions(-) create mode 100644 src/darwin/Framework/CHIPTests/TestHelpers/MTRTestCase.h create mode 100644 src/darwin/Framework/CHIPTests/TestHelpers/MTRTestCase.mm diff --git a/.github/workflows/darwin.yaml b/.github/workflows/darwin.yaml index dcc025b6e2b32d..62a8d08f09ec4a 100644 --- a/.github/workflows/darwin.yaml +++ b/.github/workflows/darwin.yaml @@ -83,6 +83,9 @@ jobs: -enableUndefinedBehaviorSanitizer YES - flavor: tsan arguments: -enableThreadSanitizer YES + # "leaks" does not seem to be very compatible with asan or tsan + - flavor: leaks + defines: ENABLE_LEAK_DETECTION=1 steps: - name: Checkout uses: actions/checkout@v4 diff --git a/src/darwin/Framework/CHIP/MTRDeviceControllerDataStore.mm b/src/darwin/Framework/CHIP/MTRDeviceControllerDataStore.mm index 38f0bbccf0fa18..1f515f25565ca5 100644 --- a/src/darwin/Framework/CHIP/MTRDeviceControllerDataStore.mm +++ b/src/darwin/Framework/CHIP/MTRDeviceControllerDataStore.mm @@ -22,6 +22,7 @@ #include #include +#include #include // FIXME: Are these good key strings? https://github.com/project-chip/connectedhomeip/issues/28973 @@ -106,7 +107,8 @@ static bool IsValidCATNumber(id _Nullable value) @implementation MTRDeviceControllerDataStore { id _storageDelegate; dispatch_queue_t _storageDelegateQueue; - MTRDeviceController * _controller; + // Controller owns us, so we have to make sure to not keep it alive. + __weak MTRDeviceController * _controller; // Array of nodes with resumption info, oldest-stored first. NSMutableArray * _nodesWithResumptionInfo; } @@ -126,7 +128,9 @@ - (nullable instancetype)initWithController:(MTRDeviceController *)controller __block id resumptionNodeList; dispatch_sync(_storageDelegateQueue, ^{ @autoreleasepool { - resumptionNodeList = [_storageDelegate controller:_controller + // NOTE: controller, not our weak ref, since we know it's still + // valid under this sync dispatch. + resumptionNodeList = [_storageDelegate controller:controller valueForKey:sResumptionNodeListKey securityLevel:MTRStorageSecurityLevelSecure sharingType:MTRStorageSharingTypeNotShared]; @@ -154,9 +158,12 @@ - (nullable instancetype)initWithController:(MTRDeviceController *)controller - (void)fetchAttributeDataForAllDevices:(MTRDeviceControllerDataStoreClusterDataHandler)clusterDataHandler { __block NSDictionary * dataStoreSecureLocalValues = nil; + MTRDeviceController * controller = _controller; + VerifyOrReturn(controller != nil); // No way to call delegate without controller. + dispatch_sync(_storageDelegateQueue, ^{ if ([self->_storageDelegate respondsToSelector:@selector(valuesForController:securityLevel:sharingType:)]) { - dataStoreSecureLocalValues = [self->_storageDelegate valuesForController:self->_controller securityLevel:MTRStorageSecurityLevelSecure sharingType:MTRStorageSharingTypeNotShared]; + dataStoreSecureLocalValues = [self->_storageDelegate valuesForController:controller securityLevel:MTRStorageSecurityLevelSecure sharingType:MTRStorageSharingTypeNotShared]; } }); @@ -177,24 +184,27 @@ - (nullable MTRCASESessionResumptionInfo *)findResumptionInfoByResumptionID:(NSD - (void)storeResumptionInfo:(MTRCASESessionResumptionInfo *)resumptionInfo { + MTRDeviceController * controller = _controller; + VerifyOrReturn(controller != nil); // No way to call delegate without controller. + auto * oldInfo = [self findResumptionInfoByNodeID:resumptionInfo.nodeID]; dispatch_sync(_storageDelegateQueue, ^{ if (oldInfo != nil) { // Remove old resumption id key. No need to do that for the // node id, because we are about to overwrite it. - [_storageDelegate controller:_controller + [_storageDelegate controller:controller removeValueForKey:ResumptionByResumptionIDKey(oldInfo.resumptionID) securityLevel:MTRStorageSecurityLevelSecure sharingType:MTRStorageSharingTypeNotShared]; [_nodesWithResumptionInfo removeObject:resumptionInfo.nodeID]; } - [_storageDelegate controller:_controller + [_storageDelegate controller:controller storeValue:resumptionInfo forKey:ResumptionByNodeIDKey(resumptionInfo.nodeID) securityLevel:MTRStorageSecurityLevelSecure sharingType:MTRStorageSharingTypeNotShared]; - [_storageDelegate controller:_controller + [_storageDelegate controller:controller storeValue:resumptionInfo forKey:ResumptionByResumptionIDKey(resumptionInfo.resumptionID) securityLevel:MTRStorageSecurityLevelSecure @@ -202,7 +212,7 @@ - (void)storeResumptionInfo:(MTRCASESessionResumptionInfo *)resumptionInfo // Update our resumption info node list. [_nodesWithResumptionInfo addObject:resumptionInfo.nodeID]; - [_storageDelegate controller:_controller + [_storageDelegate controller:controller storeValue:[_nodesWithResumptionInfo copy] forKey:sResumptionNodeListKey securityLevel:MTRStorageSecurityLevelSecure @@ -212,17 +222,20 @@ - (void)storeResumptionInfo:(MTRCASESessionResumptionInfo *)resumptionInfo - (void)clearAllResumptionInfo { + MTRDeviceController * controller = _controller; + VerifyOrReturn(controller != nil); // No way to call delegate without controller. + // Can we do less dispatch? We would need to have a version of // _findResumptionInfoWithKey that assumes we are already on the right queue. for (NSNumber * nodeID in _nodesWithResumptionInfo) { auto * oldInfo = [self findResumptionInfoByNodeID:nodeID]; if (oldInfo != nil) { dispatch_sync(_storageDelegateQueue, ^{ - [_storageDelegate controller:_controller + [_storageDelegate controller:controller removeValueForKey:ResumptionByResumptionIDKey(oldInfo.resumptionID) securityLevel:MTRStorageSecurityLevelSecure sharingType:MTRStorageSharingTypeNotShared]; - [_storageDelegate controller:_controller + [_storageDelegate controller:controller removeValueForKey:ResumptionByNodeIDKey(oldInfo.nodeID) securityLevel:MTRStorageSecurityLevelSecure sharingType:MTRStorageSharingTypeNotShared]; @@ -235,9 +248,12 @@ - (void)clearAllResumptionInfo - (CHIP_ERROR)storeLastLocallyUsedNOC:(MTRCertificateTLVBytes)noc { + MTRDeviceController * controller = _controller; + VerifyOrReturnError(controller != nil, CHIP_ERROR_PERSISTED_STORAGE_FAILED); // No way to call delegate without controller. + __block BOOL ok; dispatch_sync(_storageDelegateQueue, ^{ - ok = [_storageDelegate controller:_controller + ok = [_storageDelegate controller:controller storeValue:noc forKey:sLastLocallyUsedNOCKey securityLevel:MTRStorageSecurityLevelSecure @@ -248,10 +264,13 @@ - (CHIP_ERROR)storeLastLocallyUsedNOC:(MTRCertificateTLVBytes)noc - (MTRCertificateTLVBytes _Nullable)fetchLastLocallyUsedNOC { + MTRDeviceController * controller = _controller; + VerifyOrReturnValue(controller != nil, nil); // No way to call delegate without controller. + __block id data; dispatch_sync(_storageDelegateQueue, ^{ @autoreleasepool { - data = [_storageDelegate controller:_controller + data = [_storageDelegate controller:controller valueForKey:sLastLocallyUsedNOCKey securityLevel:MTRStorageSecurityLevelSecure sharingType:MTRStorageSharingTypeNotShared]; @@ -271,6 +290,9 @@ - (MTRCertificateTLVBytes _Nullable)fetchLastLocallyUsedNOC - (nullable MTRCASESessionResumptionInfo *)_findResumptionInfoWithKey:(nullable NSString *)key { + MTRDeviceController * controller = _controller; + VerifyOrReturnValue(controller != nil, nil); // No way to call delegate without controller. + // key could be nil if [NSString stringWithFormat] returns nil for some reason. if (key == nil) { return nil; @@ -279,7 +301,7 @@ - (nullable MTRCASESessionResumptionInfo *)_findResumptionInfoWithKey:(nullable __block id resumptionInfo; dispatch_sync(_storageDelegateQueue, ^{ @autoreleasepool { - resumptionInfo = [_storageDelegate controller:_controller + resumptionInfo = [_storageDelegate controller:controller valueForKey:key securityLevel:MTRStorageSecurityLevelSecure sharingType:MTRStorageSharingTypeNotShared]; @@ -318,9 +340,12 @@ - (nullable MTRCASESessionResumptionInfo *)_findResumptionInfoWithKey:(nullable - (id)_fetchAttributeCacheValueForKey:(NSString *)key expectedClass:(Class)expectedClass; { + MTRDeviceController * controller = _controller; + VerifyOrReturnValue(controller != nil, nil); // No way to call delegate without controller. + id data; @autoreleasepool { - data = [_storageDelegate controller:_controller + data = [_storageDelegate controller:controller valueForKey:key securityLevel:MTRStorageSecurityLevelSecure sharingType:MTRStorageSharingTypeNotShared]; @@ -338,7 +363,10 @@ - (id)_fetchAttributeCacheValueForKey:(NSString *)key expectedClass:(Class)expec - (BOOL)_storeAttributeCacheValue:(id)value forKey:(NSString *)key { - return [_storageDelegate controller:_controller + MTRDeviceController * controller = _controller; + VerifyOrReturnValue(controller != nil, NO); // No way to call delegate without controller. + + return [_storageDelegate controller:controller storeValue:value forKey:key securityLevel:MTRStorageSecurityLevelSecure @@ -347,7 +375,10 @@ - (BOOL)_storeAttributeCacheValue:(id)value forKey:(NSString *)key - (BOOL)_bulkStoreAttributeCacheValues:(NSDictionary> *)values { - return [_storageDelegate controller:_controller + MTRDeviceController * controller = _controller; + VerifyOrReturnValue(controller != nil, NO); // No way to call delegate without controller. + + return [_storageDelegate controller:controller storeValues:values securityLevel:MTRStorageSecurityLevelSecure sharingType:MTRStorageSharingTypeNotShared]; @@ -355,7 +386,10 @@ - (BOOL)_bulkStoreAttributeCacheValues:(NSDictionary -// system dependencies -#import - #import "MTRDeviceControllerLocalTestStorage.h" #import "MTRDeviceTestDelegate.h" #import "MTRDevice_Internal.h" #import "MTRErrorTestUtils.h" #import "MTRFabricInfoChecker.h" +#import "MTRTestCase.h" #import "MTRTestDeclarations.h" #import "MTRTestKeys.h" #import "MTRTestPerControllerStorage.h" @@ -177,7 +175,7 @@ - (void)issueOperationalCertificateForRequest:(MTROperationalCSRInfo *)csrInfo @end -@interface MTRPerControllerStorageTests : XCTestCase +@interface MTRPerControllerStorageTests : MTRTestCase @end @implementation MTRPerControllerStorageTests { @@ -353,6 +351,8 @@ - (nullable MTRDeviceController *)startControllerWithRootKeys:(MTRTestKeys *)roo - (void)test001_BasicControllerStartup { + self.detectLeaks = YES; + __auto_type * factory = [MTRDeviceControllerFactory sharedInstance]; XCTAssertNotNil(factory); @@ -401,6 +401,8 @@ - (void)test001_BasicControllerStartup - (void)test002_TryStartingTwoControllersWithSameNodeID { + self.detectLeaks = YES; + __auto_type * rootKeys = [[MTRTestKeys alloc] init]; XCTAssertNotNil(rootKeys); diff --git a/src/darwin/Framework/CHIPTests/TestHelpers/MTRTestCase.h b/src/darwin/Framework/CHIPTests/TestHelpers/MTRTestCase.h new file mode 100644 index 00000000000000..d12ea0a1f69f84 --- /dev/null +++ b/src/darwin/Framework/CHIPTests/TestHelpers/MTRTestCase.h @@ -0,0 +1,28 @@ +/** + * Copyright (c) 2024 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface MTRTestCase : XCTestCase +// It would be nice to do the leak-detection automatically, but running "leaks" +// on every single sub-test is slow, and some of our tests seem to have leaks +// outside Matter.framework. So have it be opt-in for now, and improve later. +@property (nonatomic) BOOL detectLeaks; +@end + +NS_ASSUME_NONNULL_END diff --git a/src/darwin/Framework/CHIPTests/TestHelpers/MTRTestCase.mm b/src/darwin/Framework/CHIPTests/TestHelpers/MTRTestCase.mm new file mode 100644 index 00000000000000..b4cf92b1ee3322 --- /dev/null +++ b/src/darwin/Framework/CHIPTests/TestHelpers/MTRTestCase.mm @@ -0,0 +1,44 @@ +/** + * Copyright (c) 2024 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#import "MTRTestCase.h" + +@implementation MTRTestCase + +/** + * Unfortunately, doing this in "+ (void)tearDown" (the global suite teardown) + * does not trigger a test failure even if the XCTAssertEqual fails. + */ +- (void)tearDown +{ +#if 0 +#if defined(ENABLE_LEAK_DETECTION) && ENABLE_LEAK_DETECTION + if (_detectLeaks) { + int pid = getpid(); + __auto_type * cmd = [NSString stringWithFormat:@"leaks %d", pid]; + int ret = system(cmd.UTF8String); + XCTAssertEqual(ret, 0, "LEAKS DETECTED"); + } +#endif +#endif + + [super tearDown]; +} + +@end diff --git a/src/darwin/Framework/Matter.xcodeproj/project.pbxproj b/src/darwin/Framework/Matter.xcodeproj/project.pbxproj index 03b0b105f30feb..be1712972895fb 100644 --- a/src/darwin/Framework/Matter.xcodeproj/project.pbxproj +++ b/src/darwin/Framework/Matter.xcodeproj/project.pbxproj @@ -139,6 +139,7 @@ 512431282BA0C8BF000BC136 /* SetMRPParametersCommand.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5124311C2BA0C09A000BC136 /* SetMRPParametersCommand.mm */; }; 512431292BA0C8BF000BC136 /* ResetMRPParametersCommand.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5124311A2BA0C09A000BC136 /* ResetMRPParametersCommand.mm */; }; 5129BCFD26A9EE3300122DDF /* MTRError.h in Headers */ = {isa = PBXBuildFile; fileRef = 5129BCFC26A9EE3300122DDF /* MTRError.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 5131BF662BE2E1B000D5D6BC /* MTRTestCase.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5131BF642BE2E1B000D5D6BC /* MTRTestCase.mm */; }; 51339B1F2A0DA64D00C798C1 /* MTRCertificateValidityTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 51339B1E2A0DA64D00C798C1 /* MTRCertificateValidityTests.m */; }; 5136661328067D550025EDAE /* MTRDeviceController_Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = 5136660F28067D540025EDAE /* MTRDeviceController_Internal.h */; }; 5136661428067D550025EDAE /* MTRDeviceControllerFactory.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5136661028067D540025EDAE /* MTRDeviceControllerFactory.mm */; }; @@ -549,6 +550,8 @@ 5124311B2BA0C09A000BC136 /* SetMRPParametersCommand.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SetMRPParametersCommand.h; sourceTree = ""; }; 5124311C2BA0C09A000BC136 /* SetMRPParametersCommand.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = SetMRPParametersCommand.mm; sourceTree = ""; }; 5129BCFC26A9EE3300122DDF /* MTRError.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MTRError.h; sourceTree = ""; }; + 5131BF642BE2E1B000D5D6BC /* MTRTestCase.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MTRTestCase.mm; sourceTree = ""; }; + 5131BF652BE2E1B000D5D6BC /* MTRTestCase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MTRTestCase.h; sourceTree = ""; }; 51339B1E2A0DA64D00C798C1 /* MTRCertificateValidityTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MTRCertificateValidityTests.m; sourceTree = ""; }; 5136660F28067D540025EDAE /* MTRDeviceController_Internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MTRDeviceController_Internal.h; sourceTree = ""; }; 5136661028067D540025EDAE /* MTRDeviceControllerFactory.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MTRDeviceControllerFactory.mm; sourceTree = ""; }; @@ -1119,6 +1122,8 @@ 51189FC72A33ACE900184508 /* TestHelpers */ = { isa = PBXGroup; children = ( + 5131BF652BE2E1B000D5D6BC /* MTRTestCase.h */, + 5131BF642BE2E1B000D5D6BC /* MTRTestCase.mm */, D437613F285BDC0D0051FEA2 /* MTRTestKeys.h */, 51C8E3F72825CDB600D47D00 /* MTRTestKeys.m */, D4376140285BDC0D0051FEA2 /* MTRTestStorage.h */, @@ -1974,6 +1979,7 @@ buildActionMask = 2147483647; files = ( 51742B4E29CB6B88009974FE /* MTRPairingTests.m in Sources */, + 5131BF662BE2E1B000D5D6BC /* MTRTestCase.mm in Sources */, 51669AF02913204400F4AA36 /* MTRBackwardsCompatTests.m in Sources */, 51D10D2E2808E2CA00E8CA3D /* MTRTestStorage.m in Sources */, 51D0B12A2B61766F006E3511 /* MTRServerEndpointTests.m in Sources */, From 3fa70cff7b016c24b7875102bc94ae5798c94cef Mon Sep 17 00:00:00 2001 From: Andrei Litvin Date: Thu, 2 May 2024 11:47:47 -0400 Subject: [PATCH 26/33] Replace `DispatchSessionEvent` with `NotifySessionHang` on sessions. (#33259) * Replace `Dispatch event` with `NotifySessionHang` on sessions. Only a single event was ever dispatched and the pattern of passing in pointers to member methods was not used anywhere else and resulted in fairly unique code. Spelling out the `NotifySessionHang` explicitly seems to simplify maintainability. * Update src/transport/Session.h Co-authored-by: mkardous-silabs <84793247+mkardous-silabs@users.noreply.github.com> --------- Co-authored-by: mkardous-silabs <84793247+mkardous-silabs@users.noreply.github.com> --- src/messaging/ExchangeContext.cpp | 2 +- src/messaging/ReliableMessageMgr.cpp | 2 +- src/transport/Session.h | 10 +++++----- src/transport/SessionDelegate.h | 2 -- 4 files changed, 7 insertions(+), 9 deletions(-) diff --git a/src/messaging/ExchangeContext.cpp b/src/messaging/ExchangeContext.cpp index bca044d91f230d..554e5fbce9482d 100644 --- a/src/messaging/ExchangeContext.cpp +++ b/src/messaging/ExchangeContext.cpp @@ -485,7 +485,7 @@ void ExchangeContext::NotifyResponseTimeout(bool aCloseIfNeeded) { mSession->AsSecureSession()->MarkAsDefunct(); } - mSession->DispatchSessionEvent(&SessionDelegate::OnSessionHang); + mSession->NotifySessionHang(); } } diff --git a/src/messaging/ReliableMessageMgr.cpp b/src/messaging/ReliableMessageMgr.cpp index 3827fd096d5072..17049069b71430 100644 --- a/src/messaging/ReliableMessageMgr.cpp +++ b/src/messaging/ReliableMessageMgr.cpp @@ -158,7 +158,7 @@ void ReliableMessageMgr::ExecuteActions() { session->AsSecureSession()->MarkAsDefunct(); } - session->DispatchSessionEvent(&SessionDelegate::OnSessionHang); + session->NotifySessionHang(); } // Do not StartTimer, we will schedule the timer at the end of the timer handler. diff --git a/src/transport/Session.h b/src/transport/Session.h index d9840ec3ee33f1..87937eef521110 100644 --- a/src/transport/Session.h +++ b/src/transport/Session.h @@ -114,8 +114,8 @@ class SessionHolder : public IntrusiveListNodeBase<> Transport::Session * operator->() const { return &mSession.Value().Get(); } - // There is not delegate, nothing to do here - virtual void DispatchSessionEvent(SessionDelegate::Event event) {} + // There is no delegate, nothing to do here + virtual void OnSessionHang() {} protected: // Helper for use by the Grab methods. @@ -147,7 +147,7 @@ class SessionHolderWithDelegate : public SessionHolder SessionHolder::ShiftToSession(session); } - void DispatchSessionEvent(SessionDelegate::Event event) override { (mDelegate.*event)(); } + void OnSessionHang() override { mDelegate.OnSessionHang(); } private: SessionDelegate & mDelegate; @@ -237,7 +237,7 @@ class Session void SetTCPConnection(ActiveTCPConnectionState * conn) { mTCPConnection = conn; } #endif // INET_CONFIG_ENABLE_TCP_ENDPOINT - void DispatchSessionEvent(SessionDelegate::Event event) + void NotifySessionHang() { // Holders might remove themselves when notified. auto holder = mHolders.begin(); @@ -245,7 +245,7 @@ class Session { auto cur = holder; ++holder; - cur->DispatchSessionEvent(event); + cur->OnSessionHang(); } } diff --git a/src/transport/SessionDelegate.h b/src/transport/SessionDelegate.h index 503aaa2b0c4f5c..8de535a265796c 100644 --- a/src/transport/SessionDelegate.h +++ b/src/transport/SessionDelegate.h @@ -51,8 +51,6 @@ class DLL_EXPORT SessionDelegate */ virtual NewSessionHandlingPolicy GetNewSessionHandlingPolicy() { return NewSessionHandlingPolicy::kShiftToNewSession; } - using Event = void (SessionDelegate::*)(); - /** * @brief * Called when a session is releasing. Callees SHALL NOT make synchronous calls into SessionManager to allocate a new session. From 74c95db031b0bbd44ff12de6d844dc6d3621d128 Mon Sep 17 00:00:00 2001 From: Noah Pendleton <2538614+noahp@users.noreply.github.com> Date: Thu, 2 May 2024 14:47:39 -0400 Subject: [PATCH 27/33] Support building chip-tool with python3.12 (#33242) This updates 2 python packages to versions compatible with python3.12, fixing the following errors when running `./scripts/examples/gn_build_example.sh examples/chip-tool BUILDFOLDER`: 1. `pyyaml` 6.0 build error: `AttributeError: cython_sources`, fixed [here](https://github.com/yaml/pyyaml/pull/702) 2. `construct` import error: ``` File "/tmp/pip-install-ifgk4tul/construct_6d60304f85e249759f6c184ea89f1317/construct/core.py", line 3, in import struct, io, binascii, itertools, collections, pickle, sys, os, tempfile, hashlib, importlib, imp ModuleNotFoundError: No module named 'imp' ``` this was fixed [here](https://github.com/construct/construct/commit/91cc0c65f5f8ceace2ee59da5068da92519a99c9), in version `v2.10.57` of `construct`. I'm just updating to latest though. Now running `./scripts/examples/gn_build_example.sh examples/chip-tool BUILDFOLDER` succeeds when the host python is python3.12. --- scripts/setup/constraints.txt | 5 ++--- scripts/setup/requirements.esp32.txt | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/scripts/setup/constraints.txt b/scripts/setup/constraints.txt index 5d0ca805416433..ab4bea6e965a9c 100644 --- a/scripts/setup/constraints.txt +++ b/scripts/setup/constraints.txt @@ -49,7 +49,7 @@ colorama==0.4.6 # west coloredlogs==15.0.1 # via -r requirements.all.txt -construct==2.10.54 +construct==2.10.70 # via # -r requirements.esp32.txt # esp-coredump @@ -208,7 +208,7 @@ python-socketio==4.6.1 # via -r requirements.esp32.txt pytz==2022.7.1 # via pandas -pyyaml==6.0 +pyyaml==6.0.1 # via # esptool # idf-component-manager @@ -296,4 +296,3 @@ setuptools==68.0.0 # Higher versions depend on proto-plus, which break # nanopb code generation (due to name conflict of the 'proto' module) google-api-core==2.17.0 - diff --git a/scripts/setup/requirements.esp32.txt b/scripts/setup/requirements.esp32.txt index c9043a3f0418c1..b2584bbac08803 100644 --- a/scripts/setup/requirements.esp32.txt +++ b/scripts/setup/requirements.esp32.txt @@ -9,7 +9,7 @@ reedsolo>=1.5.3,<=1.5.4 bitarray==2.6.0 bitstring>=3.1.6,<4 ecdsa>=0.16.0 -construct==2.10.54 +construct>=2.10.70 python-socketio<5 itsdangerous<2.1 ; python_version < "3.11" esp_idf_monitor==1.1.1 From e0f9ede83a282e2f8f02c81124b8f4ae800492c4 Mon Sep 17 00:00:00 2001 From: Andrei Litvin Date: Thu, 2 May 2024 15:06:07 -0400 Subject: [PATCH 28/33] Fix off-by-one in look checks for QName iterators. (#33273) Unit test sizes for the string `test` were off by one which masked a off-by-one comparison in QName handling. Update unit test and comparisons. This will disallow backward references to "self" for qnames. Co-authored-by: Andrei Litvin --- src/lib/dnssd/minimal_mdns/core/QName.cpp | 2 +- src/lib/dnssd/minimal_mdns/core/tests/TestQName.cpp | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/lib/dnssd/minimal_mdns/core/QName.cpp b/src/lib/dnssd/minimal_mdns/core/QName.cpp index 2cc6488cfb1503..880c9ead298ca3 100644 --- a/src/lib/dnssd/minimal_mdns/core/QName.cpp +++ b/src/lib/dnssd/minimal_mdns/core/QName.cpp @@ -61,7 +61,7 @@ bool SerializedQNameIterator::Next(bool followIndirectPointers) } size_t offset = static_cast(((*mCurrentPosition & 0x3F) << 8) | *(mCurrentPosition + 1)); - if (offset > mLookBehindMax) + if (offset >= mLookBehindMax) { // Potential infinite recursion. mIsValid = false; diff --git a/src/lib/dnssd/minimal_mdns/core/tests/TestQName.cpp b/src/lib/dnssd/minimal_mdns/core/tests/TestQName.cpp index 5f430bd3c76a7a..46c0b517162133 100644 --- a/src/lib/dnssd/minimal_mdns/core/tests/TestQName.cpp +++ b/src/lib/dnssd/minimal_mdns/core/tests/TestQName.cpp @@ -135,7 +135,7 @@ TEST(TestQName, InvalidReferencing) { // Infinite recursion - static const uint8_t kData[] = "\03test\xc0\x00"; + static const uint8_t kData[] = "\04test\xc0\x00"; SerializedQNameIterator it = AsSerializedQName(kData); EXPECT_TRUE(it.Next()); @@ -145,7 +145,7 @@ TEST(TestQName, InvalidReferencing) { // Infinite recursion by referencing own element (inside the stream) - static const uint8_t kData[] = "\03test\xc0\x05"; + static const uint8_t kData[] = "\04test\xc0\x05"; SerializedQNameIterator it = AsSerializedQName(kData); EXPECT_TRUE(it.Next()); @@ -164,7 +164,7 @@ TEST(TestQName, InvalidReferencing) { // Reference that goes forwad instead of backward - static const uint8_t kData[] = "\03test\xc0\x07"; + static const uint8_t kData[] = "\04test\xc0\x07"; SerializedQNameIterator it = AsSerializedQName(kData); EXPECT_TRUE(it.Next()); From baf136e3014bc9c4fad7f411372adb37c3a7f9ad Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Thu, 2 May 2024 16:30:52 -0400 Subject: [PATCH 29/33] Fix leaks of keys in Matter.framework unit tests. (#33276) * Fix leaks of keys in Matter.framework unit tests. We need to CFRelease the return from SecKeyCreateWithData, and we were not doing that. * Address review comment. --- src/darwin/Framework/CHIPTests/MTRCertificateValidityTests.m | 2 ++ src/darwin/Framework/CHIPTests/MTRPerControllerStorageTests.m | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/darwin/Framework/CHIPTests/MTRCertificateValidityTests.m b/src/darwin/Framework/CHIPTests/MTRCertificateValidityTests.m index 7a66d299e19e71..65313e92789990 100644 --- a/src/darwin/Framework/CHIPTests/MTRCertificateValidityTests.m +++ b/src/darwin/Framework/CHIPTests/MTRCertificateValidityTests.m @@ -163,6 +163,8 @@ - (void)issueOperationalCertificateForRequest:(MTROperationalCSRInfo *)csrInfo __auto_type * operationalCertificate = [self issueOperationalCertificateForNode:@(kDeviceId) operationalPublicKey:operationalPublicKey]; + // Release no-longer-needed key before we do anything else. + CFRelease(operationalPublicKey); XCTAssertNotNil(operationalCertificate); __auto_type * certChain = [[MTROperationalCertificateChain alloc] initWithOperationalCertificate:operationalCertificate diff --git a/src/darwin/Framework/CHIPTests/MTRPerControllerStorageTests.m b/src/darwin/Framework/CHIPTests/MTRPerControllerStorageTests.m index 3c6ebfd3b5dc2f..19f114f7877d23 100644 --- a/src/darwin/Framework/CHIPTests/MTRPerControllerStorageTests.m +++ b/src/darwin/Framework/CHIPTests/MTRPerControllerStorageTests.m @@ -158,6 +158,8 @@ - (void)issueOperationalCertificateForRequest:(MTROperationalCSRInfo *)csrInfo nodeID:self.nextNodeID caseAuthenticatedTags:nil error:&error]; + // Release no-longer-needed key before we do anything else. + CFRelease(publicKey); XCTAssertNil(error); XCTAssertNotNil(operationalCert); From e29eef4356cad0de4161439fbcc69fdfd8440d0a Mon Sep 17 00:00:00 2001 From: Nivi Sarkar <55898241+nivi-apple@users.noreply.github.com> Date: Thu, 2 May 2024 13:33:24 -0700 Subject: [PATCH 30/33] =?UTF-8?q?Remove=20the=20kDNSServiceFlagsTimeout=20?= =?UTF-8?q?flag=20when=20calling=20DNSServiceGetAdd=E2=80=A6=20(#33266)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Remove the kDNSServiceFlagsTimeout flag when calling DNSServiceGetAddrInfo - We should not be terminating the queries if we do not get anything back quickly The queries should be running until we get something back * Remove the constants for the DNSServiceFlags - Either use the DNSServiceFlags value directly in the DNS SD API calls or define a local scoped variable * Make the registerFlags const * Restyled by clang-format * Address review comment * Restyled by clang-format --------- Co-authored-by: Restyled.io --- src/platform/Darwin/DnssdImpl.cpp | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/src/platform/Darwin/DnssdImpl.cpp b/src/platform/Darwin/DnssdImpl.cpp index b80e5958310e68..37406009cf0247 100644 --- a/src/platform/Darwin/DnssdImpl.cpp +++ b/src/platform/Darwin/DnssdImpl.cpp @@ -41,12 +41,6 @@ constexpr char kSRPDot[] = "default.service.arpa."; // The extra time in milliseconds that we will wait for the resolution on the SRP domain to complete. constexpr uint16_t kSRPTimeoutInMsec = 250; -constexpr DNSServiceFlags kRegisterFlags = kDNSServiceFlagsNoAutoRename; -constexpr DNSServiceFlags kBrowseFlags = kDNSServiceFlagsShareConnection; -constexpr DNSServiceFlags kGetAddrInfoFlags = kDNSServiceFlagsTimeout | kDNSServiceFlagsShareConnection; -constexpr DNSServiceFlags kResolveFlags = kDNSServiceFlagsShareConnection; -constexpr DNSServiceFlags kReconfirmRecordFlags = 0; - bool IsSupportedProtocol(DnssdServiceProtocol protocol) { return (protocol == DnssdServiceProtocol::kDnssdProtocolUdp) || (protocol == DnssdServiceProtocol::kDnssdProtocolTcp); @@ -179,10 +173,11 @@ CHIP_ERROR Register(void * context, DnssdPublishCallback callback, uint32_t inte ChipLogProgress(Discovery, "Registering service %s on host %s with port %u and type: %s on interface id: %" PRIu32, StringOrNullMarker(name), StringOrNullMarker(hostname), port, StringOrNullMarker(type), interfaceId); - RegisterContext * sdCtx = nullptr; + constexpr DNSServiceFlags registerFlags = kDNSServiceFlagsNoAutoRename; + RegisterContext * sdCtx = nullptr; if (CHIP_NO_ERROR == MdnsContexts::GetInstance().GetRegisterContextOfTypeAndName(type, name, &sdCtx)) { - auto err = DNSServiceUpdateRecord(sdCtx->serviceRef, nullptr, kRegisterFlags, record.size(), record.data(), 0 /* ttl */); + auto err = DNSServiceUpdateRecord(sdCtx->serviceRef, nullptr, registerFlags, record.size(), record.data(), 0 /* ttl */); VerifyOrReturnError(kDNSServiceErr_NoError == err, sdCtx->Finalize(err)); return CHIP_NO_ERROR; } @@ -194,7 +189,7 @@ CHIP_ERROR Register(void * context, DnssdPublishCallback callback, uint32_t inte VerifyOrReturnError(kDNSServiceErr_NoError == err, sdCtx->Finalize(err)); DNSServiceRef sdRef; - err = DNSServiceRegister(&sdRef, kRegisterFlags, interfaceId, name, type, kLocalDot, hostname, htons(port), record.size(), + err = DNSServiceRegister(&sdRef, registerFlags, interfaceId, name, type, kLocalDot, hostname, htons(port), record.size(), record.data(), OnRegister, sdCtx); VerifyOrReturnError(kDNSServiceErr_NoError == err, sdCtx->Finalize(err)); @@ -213,7 +208,7 @@ CHIP_ERROR BrowseOnDomain(BrowseHandler * sdCtx, uint32_t interfaceId, const cha { auto sdRef = sdCtx->serviceRef; // Mandatory copy because of kDNSServiceFlagsShareConnection - auto err = DNSServiceBrowse(&sdRef, kBrowseFlags, interfaceId, type, domain, OnBrowse, sdCtx); + auto err = DNSServiceBrowse(&sdRef, kDNSServiceFlagsShareConnection, interfaceId, type, domain, OnBrowse, sdCtx); VerifyOrReturnError(kDNSServiceErr_NoError == err, sdCtx->Finalize(err)); return CHIP_NO_ERROR; } @@ -334,8 +329,8 @@ static void GetAddrInfo(ResolveContext * sdCtx) ResolveContextWithType * contextWithType = (interface.first.isSRPResult) ? &sdCtx->resolveContextWithSRPType : &sdCtx->resolveContextWithNonSRPType; - auto err = - DNSServiceGetAddrInfo(&sdRefCopy, kGetAddrInfoFlags, interfaceId, protocol, hostname, OnGetAddrInfo, contextWithType); + auto err = DNSServiceGetAddrInfo(&sdRefCopy, kDNSServiceFlagsShareConnection, interfaceId, protocol, hostname, + OnGetAddrInfo, contextWithType); VerifyOrReturn(kDNSServiceErr_NoError == err, sdCtx->Finalize(err)); interface.second.isDNSLookUpRequested = true; } @@ -372,7 +367,8 @@ static CHIP_ERROR ResolveWithContext(ResolveContext * sdCtx, uint32_t interfaceI { auto sdRef = sdCtx->serviceRef; // Mandatory copy because of kDNSServiceFlagsShareConnection - auto err = DNSServiceResolve(&sdRef, kResolveFlags, interfaceId, name, type, domain, OnResolve, contextWithType); + auto err = + DNSServiceResolve(&sdRef, kDNSServiceFlagsShareConnection, interfaceId, name, type, domain, OnResolve, contextWithType); VerifyOrReturnError(kDNSServiceErr_NoError == err, sdCtx->Finalize(err)); return CHIP_NO_ERROR; } @@ -655,7 +651,7 @@ CHIP_ERROR ChipDnssdReconfirmRecord(const char * hostname, chip::Inet::IPAddress return CHIP_ERROR_INVALID_ARGUMENT; } - auto error = DNSServiceReconfirmRecord(kReconfirmRecordFlags, interfaceId, fullname.c_str(), rrtype, rrclass, rdlen, rdata); + auto error = DNSServiceReconfirmRecord(0 /* DNSServiceFlags */, interfaceId, fullname.c_str(), rrtype, rrclass, rdlen, rdata); LogOnFailure(__func__, error); return Error::ToChipError(error); From 997ccd0b389aa7b1f00b66d85d5bd1fcf89f35d4 Mon Sep 17 00:00:00 2001 From: pankore <86098180+pankore@users.noreply.github.com> Date: Fri, 3 May 2024 04:38:19 +0800 Subject: [PATCH 31/33] [Ameba] Add Ameba crypto implementation (#33208) * [Ameba] Add Ameba crypto implementation * Add Ameba cryto implementation for security purposes * Inject only customized operational key storage * Remove the use of chip_crypto = platform, instead keep it as mbedtls, and only inject customized operaional key storage --- .../ameba/main/chipinterface.cpp | 9 + .../ameba/main/chipinterface.cpp | 10 + .../ameba/main/chipinterface.cpp | 9 + .../lighting-app/ameba/main/chipinterface.cpp | 12 +- src/platform/Ameba/BUILD.gn | 2 + src/platform/Ameba/FactoryDataDecoder.cpp | 11 + src/platform/Ameba/FactoryDataDecoder.h | 4 + src/platform/Ameba/FactoryDataProvider.cpp | 23 +- ...baPersistentStorageOperationalKeystore.cpp | 446 ++++++++++++++++++ ...mebaPersistentStorageOperationalKeystore.h | 146 ++++++ 10 files changed, 667 insertions(+), 5 deletions(-) mode change 100644 => 100755 src/platform/Ameba/FactoryDataDecoder.cpp mode change 100644 => 100755 src/platform/Ameba/FactoryDataDecoder.h create mode 100644 src/platform/Ameba/crypto/AmebaPersistentStorageOperationalKeystore.cpp create mode 100644 src/platform/Ameba/crypto/AmebaPersistentStorageOperationalKeystore.h diff --git a/examples/air-purifier-app/ameba/main/chipinterface.cpp b/examples/air-purifier-app/ameba/main/chipinterface.cpp index fd1c568afbf44f..0829bb041e4882 100644 --- a/examples/air-purifier-app/ameba/main/chipinterface.cpp +++ b/examples/air-purifier-app/ameba/main/chipinterface.cpp @@ -37,6 +37,9 @@ #include #include #include +#if CONFIG_ENABLE_AMEBA_CRYPTO +#include +#endif #include @@ -130,6 +133,12 @@ static void InitServer(intptr_t context) // Init ZCL Data Model and CHIP App Server static chip::CommonCaseDeviceServerInitParams initParams; (void) initParams.InitializeStaticResourcesBeforeServerInit(); +#if CONFIG_ENABLE_AMEBA_CRYPTO + ChipLogProgress(DeviceLayer, "platform crypto enabled!"); + static chip::AmebaPersistentStorageOperationalKeystore sAmebaPersistentStorageOpKeystore; + VerifyOrDie((sAmebaPersistentStorageOpKeystore.Init(initParams.persistentStorageDelegate)) == CHIP_NO_ERROR); + initParams.operationalKeystore = &sAmebaPersistentStorageOpKeystore; +#endif chip::Server::GetInstance().Init(initParams); gExampleDeviceInfoProvider.SetStorageDelegate(&Server::GetInstance().GetPersistentStorage()); chip::DeviceLayer::SetDeviceInfoProvider(&gExampleDeviceInfoProvider); diff --git a/examples/all-clusters-app/ameba/main/chipinterface.cpp b/examples/all-clusters-app/ameba/main/chipinterface.cpp index aa7cc4afe75047..2a35d86eadc3a2 100644 --- a/examples/all-clusters-app/ameba/main/chipinterface.cpp +++ b/examples/all-clusters-app/ameba/main/chipinterface.cpp @@ -41,6 +41,9 @@ #include #include #include +#if CONFIG_ENABLE_AMEBA_CRYPTO +#include +#endif #include #include #include @@ -153,6 +156,13 @@ static void InitServer(intptr_t context) initParams.InitializeStaticResourcesBeforeServerInit(); +#if CONFIG_ENABLE_AMEBA_CRYPTO + ChipLogProgress(DeviceLayer, "platform crypto enabled!"); + static chip::AmebaPersistentStorageOperationalKeystore sAmebaPersistentStorageOpKeystore; + VerifyOrDie((sAmebaPersistentStorageOpKeystore.Init(initParams.persistentStorageDelegate)) == CHIP_NO_ERROR); + initParams.operationalKeystore = &sAmebaPersistentStorageOpKeystore; +#endif + chip::Server::GetInstance().Init(initParams); gExampleDeviceInfoProvider.SetStorageDelegate(&Server::GetInstance().GetPersistentStorage()); // TODO: Use our own DeviceInfoProvider diff --git a/examples/light-switch-app/ameba/main/chipinterface.cpp b/examples/light-switch-app/ameba/main/chipinterface.cpp index c141769ba7d483..35d11da6342ba5 100644 --- a/examples/light-switch-app/ameba/main/chipinterface.cpp +++ b/examples/light-switch-app/ameba/main/chipinterface.cpp @@ -34,6 +34,9 @@ #include #include #include +#if CONFIG_ENABLE_AMEBA_CRYPTO +#include +#endif #include #include #include @@ -100,6 +103,12 @@ static void InitServer(intptr_t context) // Init ZCL Data Model and CHIP App Server static chip::CommonCaseDeviceServerInitParams initParams; initParams.InitializeStaticResourcesBeforeServerInit(); +#if CONFIG_ENABLE_AMEBA_CRYPTO + ChipLogProgress(DeviceLayer, "platform crypto enabled!"); + static chip::AmebaPersistentStorageOperationalKeystore sAmebaPersistentStorageOpKeystore; + VerifyOrDie((sAmebaPersistentStorageOpKeystore.Init(initParams.persistentStorageDelegate)) == CHIP_NO_ERROR); + initParams.operationalKeystore = &sAmebaPersistentStorageOpKeystore; +#endif chip::Server::GetInstance().Init(initParams); gExampleDeviceInfoProvider.SetStorageDelegate(&Server::GetInstance().GetPersistentStorage()); chip::DeviceLayer::SetDeviceInfoProvider(&gExampleDeviceInfoProvider); diff --git a/examples/lighting-app/ameba/main/chipinterface.cpp b/examples/lighting-app/ameba/main/chipinterface.cpp index 461b8bea6143f6..76459b728a545b 100644 --- a/examples/lighting-app/ameba/main/chipinterface.cpp +++ b/examples/lighting-app/ameba/main/chipinterface.cpp @@ -35,12 +35,14 @@ #include #include #include +#if CONFIG_ENABLE_AMEBA_CRYPTO +#include +#endif +#include #include #include #include -#include - #if CONFIG_ENABLE_PW_RPC #include "Rpc.h" #endif @@ -121,6 +123,12 @@ static void InitServer(intptr_t context) // Init ZCL Data Model and CHIP App Server static chip::CommonCaseDeviceServerInitParams initParams; (void) initParams.InitializeStaticResourcesBeforeServerInit(); +#if CONFIG_ENABLE_AMEBA_CRYPTO + ChipLogProgress(DeviceLayer, "platform crypto enabled!"); + static chip::AmebaPersistentStorageOperationalKeystore sAmebaPersistentStorageOpKeystore; + VerifyOrDie((sAmebaPersistentStorageOpKeystore.Init(initParams.persistentStorageDelegate)) == CHIP_NO_ERROR); + initParams.operationalKeystore = &sAmebaPersistentStorageOpKeystore; +#endif chip::Server::GetInstance().Init(initParams); gExampleDeviceInfoProvider.SetStorageDelegate(&Server::GetInstance().GetPersistentStorage()); chip::DeviceLayer::SetDeviceInfoProvider(&gExampleDeviceInfoProvider); diff --git a/src/platform/Ameba/BUILD.gn b/src/platform/Ameba/BUILD.gn index ff05b1fdeb165a..9e06191ae667ca 100755 --- a/src/platform/Ameba/BUILD.gn +++ b/src/platform/Ameba/BUILD.gn @@ -50,6 +50,8 @@ static_library("Ameba") { "SoftwareUpdateManagerImpl.h", "SystemTimeSupport.cpp", "SystemTimeSupport.h", + "crypto/AmebaPersistentStorageOperationalKeystore.cpp", + "crypto/AmebaPersistentStorageOperationalKeystore.h", ] deps = [ diff --git a/src/platform/Ameba/FactoryDataDecoder.cpp b/src/platform/Ameba/FactoryDataDecoder.cpp old mode 100644 new mode 100755 index 4e3536e3de1455..250487342bf0d9 --- a/src/platform/Ameba/FactoryDataDecoder.cpp +++ b/src/platform/Ameba/FactoryDataDecoder.cpp @@ -41,5 +41,16 @@ CHIP_ERROR FactoryDataDecoder::DecodeFactoryData(uint8_t * buffer, FactoryData * return err; } +#if CONFIG_ENABLE_AMEBA_CRYPTO +CHIP_ERROR FactoryDataDecoder::GetSign(uint8_t * PublicKeyData, size_t PublicKeySize, const unsigned char * MessageData, + size_t MessageSize, unsigned char * Signature) +{ + int32_t error = matter_get_signature(PublicKeyData, PublicKeySize, MessageData, MessageSize, Signature); + CHIP_ERROR err = CHIP_NO_ERROR; + + return err; +} +#endif + } // namespace DeviceLayer } // namespace chip diff --git a/src/platform/Ameba/FactoryDataDecoder.h b/src/platform/Ameba/FactoryDataDecoder.h old mode 100644 new mode 100755 index 623eb8e102d093..1aa295d6a4c5e8 --- a/src/platform/Ameba/FactoryDataDecoder.h +++ b/src/platform/Ameba/FactoryDataDecoder.h @@ -27,6 +27,10 @@ class FactoryDataDecoder public: CHIP_ERROR ReadFactoryData(uint8_t * buffer, uint16_t * pfactorydata_len); CHIP_ERROR DecodeFactoryData(uint8_t * buffer, FactoryData * fdata, uint16_t factorydata_len); +#if CONFIG_ENABLE_AMEBA_CRYPTO + CHIP_ERROR GetSign(uint8_t * PublicKeyData, size_t PublicKeySize, const unsigned char * MessageData, size_t MessageSize, + unsigned char * Signature); +#endif static FactoryDataDecoder & GetInstance() { static FactoryDataDecoder instance; diff --git a/src/platform/Ameba/FactoryDataProvider.cpp b/src/platform/Ameba/FactoryDataProvider.cpp index 71243a1b7cfe84..d41f85669014b8 100644 --- a/src/platform/Ameba/FactoryDataProvider.cpp +++ b/src/platform/Ameba/FactoryDataProvider.cpp @@ -16,7 +16,6 @@ */ #include "FactoryDataProvider.h" - #include "FactoryDataDecoder.h" #include #include @@ -254,6 +253,19 @@ CHIP_ERROR FactoryDataProvider::SignWithDeviceAttestationKey(const ByteSpan & me if (kReadFromFlash) { +#if CONFIG_ENABLE_AMEBA_CRYPTO + ReturnErrorCodeIf(!mFactoryData.dac.dac_cert.value, CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND); + // Extract public key from DAC cert. + ByteSpan dacCertSpan{ reinterpret_cast(mFactoryData.dac.dac_cert.value), mFactoryData.dac.dac_cert.len }; + chip::Crypto::P256PublicKey dacPublicKey; + + ReturnErrorOnFailure(chip::Crypto::ExtractPubkeyFromX509Cert(dacCertSpan, dacPublicKey)); + + CHIP_ERROR err = CHIP_NO_ERROR; + FactoryDataDecoder decoder = FactoryDataDecoder::GetInstance(); + err = decoder.GetSign(dacPublicKey.Bytes(), dacPublicKey.Length(), messageToSign.data(), messageToSign.size(), + signature.Bytes()); +#else ReturnErrorCodeIf(!mFactoryData.dac.dac_cert.value, CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND); ReturnErrorCodeIf(!mFactoryData.dac.dac_key.value, CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND); // Extract public key from DAC cert. @@ -261,18 +273,23 @@ CHIP_ERROR FactoryDataProvider::SignWithDeviceAttestationKey(const ByteSpan & me chip::Crypto::P256PublicKey dacPublicKey; ReturnErrorOnFailure(chip::Crypto::ExtractPubkeyFromX509Cert(dacCertSpan, dacPublicKey)); + ReturnErrorOnFailure( LoadKeypairFromRaw(ByteSpan(reinterpret_cast(mFactoryData.dac.dac_key.value), mFactoryData.dac.dac_key.len), ByteSpan(dacPublicKey.Bytes(), dacPublicKey.Length()), keypair)); +#endif } else { ReturnErrorOnFailure(LoadKeypairFromRaw(ByteSpan(kDacPrivateKey), ByteSpan(kDacPublicKey), keypair)); } - +#if CONFIG_ENABLE_AMEBA_CRYPTO + VerifyOrReturnError(signature.SetLength(chip::Crypto::kP256_ECDSA_Signature_Length_Raw) == CHIP_NO_ERROR, CHIP_ERROR_INTERNAL); + return CopySpanToMutableSpan(ByteSpan{ signature.ConstBytes(), signature.Length() }, outSignBuffer); +#else ReturnErrorOnFailure(keypair.ECDSA_sign_msg(messageToSign.data(), messageToSign.size(), signature)); - return CopySpanToMutableSpan(ByteSpan{ signature.ConstBytes(), signature.Length() }, outSignBuffer); +#endif } CHIP_ERROR FactoryDataProvider::GetSetupDiscriminator(uint16_t & setupDiscriminator) diff --git a/src/platform/Ameba/crypto/AmebaPersistentStorageOperationalKeystore.cpp b/src/platform/Ameba/crypto/AmebaPersistentStorageOperationalKeystore.cpp new file mode 100644 index 00000000000000..73358f77ea4af0 --- /dev/null +++ b/src/platform/Ameba/crypto/AmebaPersistentStorageOperationalKeystore.cpp @@ -0,0 +1,446 @@ +/* + * Copyright (c) 2022 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#if CONFIG_ENABLE_AMEBA_CRYPTO +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include + +namespace chip { + +using namespace chip::Crypto; + +static inline mbedtls_ecp_keypair * to_keypair(P256KeypairContext * context) +{ + return SafePointerCast(context); +} + +static int CryptoRNG(void * ctxt, uint8_t * out_buffer, size_t out_length) +{ + return (chip::Crypto::DRBG_get_bytes(out_buffer, out_length) == CHIP_NO_ERROR) ? 0 : 1; +} + +CHIP_ERROR AmebaP256Keypair::Initialize(Crypto::ECPKeyTarget key_target) +{ + CHIP_ERROR error = CHIP_NO_ERROR; + int result = 0; + + Clear(); + + mbedtls_ecp_keypair * keypair = to_keypair(&mKeypair); + + VerifyOrExit(matter_get_publickey(Uint8::to_uchar(mPublicKey), mPublicKey.Length()) != 0, + error = CHIP_ERROR_INVALID_PUBLIC_KEY); + + keypair = nullptr; + mInitialized = true; + +exit: + if (keypair != nullptr) + { + keypair = nullptr; + } + + _log_mbedTLS_error(result); + return error; +} + +void AmebaP256Keypair::Clear() +{ + if (mInitialized) + { + mbedtls_ecp_keypair * keypair = to_keypair(&mKeypair); + mbedtls_ecp_keypair_free(keypair); + mInitialized = false; + } +} + +AmebaP256Keypair::~AmebaP256Keypair() +{ + Clear(); +} + +namespace { + +// Tags for our operational keypair storage. +constexpr TLV::Tag kOpKeyVersionTag = TLV::ContextTag(0); +constexpr TLV::Tag kOpKeyDataTag = TLV::ContextTag(1); + +// If this version grows beyond UINT16_MAX, adjust OpKeypairTLVMaxSize +// accordingly. +constexpr uint16_t kOpKeyVersion = 1; + +constexpr size_t OpKeyTLVMaxSize() +{ + // Version and serialized key + return TLV::EstimateStructOverhead(sizeof(uint16_t), Crypto::P256SerializedKeypair::Capacity()); +} + +/** WARNING: This can leave the operational key on the stack somewhere, since many of the platform + * APIs use stack buffers and do not sanitize! This implementation is for example purposes + * only of the API and it is recommended to avoid directly accessing raw private key bits + * in storage. + */ +CHIP_ERROR StoreOperationalKey(FabricIndex fabricIndex, PersistentStorageDelegate * storage, P256Keypair * keypair) +{ + VerifyOrReturnError(IsValidFabricIndex(fabricIndex) && (storage != nullptr) && (keypair != nullptr), + CHIP_ERROR_INVALID_ARGUMENT); + + // Use a SensitiveDataBuffer to get RAII secret data clearing on scope exit. + Crypto::SensitiveDataBuffer buf; + TLV::TLVWriter writer; + + writer.Init(buf.Bytes(), buf.Capacity()); + + TLV::TLVType outerType; + ReturnErrorOnFailure(writer.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, outerType)); + + ReturnErrorOnFailure(writer.Put(kOpKeyVersionTag, kOpKeyVersion)); + + { + // P256SerializedKeypair has RAII secret clearing + Crypto::P256SerializedKeypair serializedOpKey; + size_t len = serializedOpKey.Length() == 0 ? serializedOpKey.Capacity() : serializedOpKey.Length(); + + int result = matter_serialize(serializedOpKey.Bytes(), len); + if (result != 0) + { + return CHIP_ERROR_INTERNAL; + } + ReturnErrorOnFailure(writer.Put(kOpKeyDataTag, ByteSpan(serializedOpKey.Bytes(), len))); + } + + ReturnErrorOnFailure(writer.EndContainer(outerType)); + + const auto opKeyLength = writer.GetLengthWritten(); + VerifyOrReturnError(CanCastTo(opKeyLength), CHIP_ERROR_BUFFER_TOO_SMALL); + ReturnErrorOnFailure(storage->SyncSetKeyValue(DefaultStorageKeyAllocator::FabricOpKey(fabricIndex).KeyName(), buf.ConstBytes(), + static_cast(opKeyLength))); + + return CHIP_NO_ERROR; +} + +CHIP_ERROR ExportStoredOpKey(FabricIndex fabricIndex, PersistentStorageDelegate * storage, + Crypto::P256SerializedKeypair & serializedOpKey) +{ + VerifyOrReturnError(storage != nullptr, CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrReturnError(IsValidFabricIndex(fabricIndex), CHIP_ERROR_INVALID_FABRIC_INDEX); + + // Use a SensitiveDataBuffer to get RAII secret data clearing on scope exit. + Crypto::SensitiveDataBuffer buf; + + // Load up the operational key structure from storage + uint16_t size = static_cast(buf.Capacity()); + ReturnErrorOnFailure( + storage->SyncGetKeyValue(DefaultStorageKeyAllocator::FabricOpKey(fabricIndex).KeyName(), buf.Bytes(), size)); + + buf.SetLength(static_cast(size)); + + // Read-out the operational key TLV entry. + TLV::ContiguousBufferTLVReader reader; + reader.Init(buf.Bytes(), buf.Length()); + + ReturnErrorOnFailure(reader.Next(TLV::kTLVType_Structure, TLV::AnonymousTag())); + TLV::TLVType containerType; + ReturnErrorOnFailure(reader.EnterContainer(containerType)); + + ReturnErrorOnFailure(reader.Next(kOpKeyVersionTag)); + uint16_t opKeyVersion; + ReturnErrorOnFailure(reader.Get(opKeyVersion)); + VerifyOrReturnError(opKeyVersion == kOpKeyVersion, CHIP_ERROR_VERSION_MISMATCH); + + ReturnErrorOnFailure(reader.Next(kOpKeyDataTag)); + { + ByteSpan keyData; + ReturnErrorOnFailure(reader.GetByteView(keyData)); + + // Unfortunately, we have to copy the data into a P256SerializedKeypair. + VerifyOrReturnError(keyData.size() <= serializedOpKey.Capacity(), CHIP_ERROR_BUFFER_TOO_SMALL); + + ReturnErrorOnFailure(reader.ExitContainer(containerType)); + + memcpy(serializedOpKey.Bytes(), keyData.data(), keyData.size()); + serializedOpKey.SetLength(keyData.size()); + } + + return CHIP_NO_ERROR; +} + +/** WARNING: This can leave the operational key on the stack somewhere, since many of the platform + * APIs use stack buffers and do not sanitize! This implementation is for example purposes + * only of the API and it is recommended to avoid directly accessing raw private key bits + * in storage. + */ +CHIP_ERROR SignWithStoredOpKey(FabricIndex fabricIndex, PersistentStorageDelegate * storage, const ByteSpan & message, + P256ECDSASignature & outSignature) +{ + VerifyOrReturnError(IsValidFabricIndex(fabricIndex) && (storage != nullptr), CHIP_ERROR_INVALID_ARGUMENT); + + // Use RAII scoping for the transient keypair, to make sure it doesn't get leaked on any error paths. + // Key is put in heap since signature is a costly stack operation and P256Keypair is + // a costly class depending on the backend. + auto transientOperationalKeypair = Platform::MakeUnique(); + if (!transientOperationalKeypair) + { + return CHIP_ERROR_NO_MEMORY; + } + + // Scope 1: Load up the keypair data from storage + P256SerializedKeypair serializedOpKey; + CHIP_ERROR err = ExportStoredOpKey(fabricIndex, storage, serializedOpKey); + if (CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND == err) + { + return CHIP_ERROR_INVALID_FABRIC_INDEX; + } + + // Load-up key material + // WARNING: This makes use of the raw key bits + int result = matter_deserialize(serializedOpKey.Bytes(), serializedOpKey.Length()); + if (result != 0) + { + return CHIP_ERROR_INTERNAL; + } + + // Scope 2: Sign message with the keypair + result = matter_ecdsa_sign_msg(message.data(), message.size(), outSignature.Bytes()); + if (result != 0) + { + return CHIP_ERROR_INTERNAL; + } + + VerifyOrReturnError(outSignature.SetLength(kP256_ECDSA_Signature_Length_Raw) == CHIP_NO_ERROR, err = CHIP_ERROR_INTERNAL); + return err; +} + +} // namespace + +bool AmebaPersistentStorageOperationalKeystore::HasOpKeypairForFabric(FabricIndex fabricIndex) const +{ + VerifyOrReturnError(mStorage != nullptr, false); + VerifyOrReturnError(IsValidFabricIndex(fabricIndex), false); + + // If there was a pending keypair, then there's really a usable key + if (mIsPendingKeypairActive && (fabricIndex == mPendingFabricIndex) && (mPendingKeypair != nullptr)) + { + return true; + } + + // TODO(#16958): need to actually read the key to know if it's there due to platforms not + // properly enforcing CHIP_ERROR_BUFFER_TOO_SMALL behavior needed by + // PersistentStorageDelegate. Very unfortunate, needs fixing ASAP. + + // Use a SensitiveDataBuffer to get RAII secret data clearing on scope exit. + Crypto::SensitiveDataBuffer buf; + + uint16_t keySize = static_cast(buf.Capacity()); + CHIP_ERROR err = + mStorage->SyncGetKeyValue(DefaultStorageKeyAllocator::FabricOpKey(fabricIndex).KeyName(), buf.Bytes(), keySize); + + return (err == CHIP_NO_ERROR); +} + +CHIP_ERROR AmebaPersistentStorageOperationalKeystore::NewOpKeypairForFabric(FabricIndex fabricIndex, + MutableByteSpan & outCertificateSigningRequest) +{ + VerifyOrReturnError(mStorage != nullptr, CHIP_ERROR_INCORRECT_STATE); + VerifyOrReturnError(IsValidFabricIndex(fabricIndex), CHIP_ERROR_INVALID_FABRIC_INDEX); + // If a key is pending, we cannot generate for a different fabric index until we commit or revert. + if ((mPendingFabricIndex != kUndefinedFabricIndex) && (fabricIndex != mPendingFabricIndex)) + { + return CHIP_ERROR_INVALID_FABRIC_INDEX; + } + VerifyOrReturnError(outCertificateSigningRequest.size() >= Crypto::kMIN_CSR_Buffer_Size, CHIP_ERROR_BUFFER_TOO_SMALL); + + // Replace previous pending keypair, if any was previously allocated + ResetPendingKey(); + + mPendingKeypair = Platform::New(); + VerifyOrReturnError(mPendingKeypair != nullptr, CHIP_ERROR_NO_MEMORY); + + size_t TempLength = outCertificateSigningRequest.size(); + size_t csrLength = matter_gen_new_csr(outCertificateSigningRequest.data(), TempLength); + + if (csrLength <= 0) + { + ResetPendingKey(); + return CHIP_ERROR_INTERNAL; + } + + outCertificateSigningRequest.reduce_size(csrLength); + mPendingFabricIndex = fabricIndex; + + return CHIP_NO_ERROR; +} + +CHIP_ERROR AmebaPersistentStorageOperationalKeystore::ActivateOpKeypairForFabric(FabricIndex fabricIndex, + const Crypto::P256PublicKey & nocPublicKey) +{ + VerifyOrReturnError(mStorage != nullptr, CHIP_ERROR_INCORRECT_STATE); + VerifyOrReturnError(mPendingKeypair != nullptr, CHIP_ERROR_INVALID_FABRIC_INDEX); + VerifyOrReturnError(IsValidFabricIndex(fabricIndex) && (fabricIndex == mPendingFabricIndex), CHIP_ERROR_INVALID_FABRIC_INDEX); + + // Validate public key being activated matches last generated pending keypair + mPendingKeypair = Platform::New(); + VerifyOrReturnError(mPendingKeypair != nullptr, CHIP_ERROR_NO_MEMORY); + mPendingKeypair->Initialize(Crypto::ECPKeyTarget::ECDSA); + VerifyOrReturnError(mPendingKeypair->Pubkey().Matches(nocPublicKey), CHIP_ERROR_INVALID_PUBLIC_KEY); + + mIsPendingKeypairActive = true; + + return CHIP_NO_ERROR; +} + +CHIP_ERROR AmebaPersistentStorageOperationalKeystore::CommitOpKeypairForFabric(FabricIndex fabricIndex) +{ + VerifyOrReturnError(mStorage != nullptr, CHIP_ERROR_INCORRECT_STATE); + VerifyOrReturnError(mPendingKeypair != nullptr, CHIP_ERROR_INVALID_FABRIC_INDEX); + VerifyOrReturnError(IsValidFabricIndex(fabricIndex) && (fabricIndex == mPendingFabricIndex), CHIP_ERROR_INVALID_FABRIC_INDEX); + VerifyOrReturnError(mIsPendingKeypairActive == true, CHIP_ERROR_INCORRECT_STATE); + + // Try to store persistent key. On failure, leave everything pending as-is + CHIP_ERROR err = StoreOperationalKey(fabricIndex, mStorage, mPendingKeypair); + ReturnErrorOnFailure(err); + + // If we got here, we succeeded and can reset the pending key: next `SignWithOpKeypair` will use the stored key. + ResetPendingKey(); + return CHIP_NO_ERROR; +} + +CHIP_ERROR AmebaPersistentStorageOperationalKeystore::ExportOpKeypairForFabric(FabricIndex fabricIndex, + Crypto::P256SerializedKeypair & outKeypair) +{ + VerifyOrReturnError(mStorage != nullptr, CHIP_ERROR_INCORRECT_STATE); + return ExportStoredOpKey(fabricIndex, mStorage, outKeypair); +} + +CHIP_ERROR AmebaPersistentStorageOperationalKeystore::RemoveOpKeypairForFabric(FabricIndex fabricIndex) +{ + VerifyOrReturnError(mStorage != nullptr, CHIP_ERROR_INCORRECT_STATE); + VerifyOrReturnError(IsValidFabricIndex(fabricIndex), CHIP_ERROR_INVALID_FABRIC_INDEX); + + // Remove pending state if matching + if ((mPendingKeypair != nullptr) && (fabricIndex == mPendingFabricIndex)) + { + RevertPendingKeypair(); + } + + CHIP_ERROR err = mStorage->SyncDeleteKeyValue(DefaultStorageKeyAllocator::FabricOpKey(fabricIndex).KeyName()); + if (err == CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND) + { + err = CHIP_ERROR_INVALID_FABRIC_INDEX; + } + + return err; +} + +void AmebaPersistentStorageOperationalKeystore::RevertPendingKeypair() +{ + VerifyOrReturn(mStorage != nullptr); + + // Just reset the pending key, we never stored anything + ResetPendingKey(); +} + +CHIP_ERROR AmebaPersistentStorageOperationalKeystore::SignWithOpKeypair(FabricIndex fabricIndex, const ByteSpan & message, + Crypto::P256ECDSASignature & outSignature) const +{ + VerifyOrReturnError(mStorage != nullptr, CHIP_ERROR_INCORRECT_STATE); + VerifyOrReturnError(IsValidFabricIndex(fabricIndex), CHIP_ERROR_INVALID_FABRIC_INDEX); + + if (mIsPendingKeypairActive && (fabricIndex == mPendingFabricIndex)) + { + VerifyOrReturnError(mPendingKeypair != nullptr, CHIP_ERROR_INTERNAL); + // We have an override key: sign with it! + CHIP_ERROR err = CHIP_NO_ERROR; + if (matter_ecdsa_sign_msg(message.data(), message.size(), outSignature.Bytes()) != 0) + { + return CHIP_ERROR_INTERNAL; + } + VerifyOrReturnError(outSignature.SetLength(kP256_ECDSA_Signature_Length_Raw) == CHIP_NO_ERROR, err = CHIP_ERROR_INTERNAL); + return err; + } + + return SignWithStoredOpKey(fabricIndex, mStorage, message, outSignature); +} + +Crypto::P256Keypair * AmebaPersistentStorageOperationalKeystore::AllocateEphemeralKeypairForCASE() +{ + // DO NOT CUT AND PASTE without considering the ReleaseEphemeralKeypair(). + // If allocating a derived class, then `ReleaseEphemeralKeypair` MUST + // de-allocate the derived class after up-casting the base class pointer. + return Platform::New(); +} + +void AmebaPersistentStorageOperationalKeystore::ReleaseEphemeralKeypair(Crypto::P256Keypair * keypair) +{ + // DO NOT CUT AND PASTE without considering the AllocateEphemeralKeypairForCASE(). + // This must delete the same concrete class as allocated in `AllocateEphemeralKeypairForCASE` + Platform::Delete(keypair); +} + +CHIP_ERROR AmebaPersistentStorageOperationalKeystore::MigrateOpKeypairForFabric(FabricIndex fabricIndex, + OperationalKeystore & operationalKeystore) const +{ + VerifyOrReturnError(mStorage != nullptr, CHIP_ERROR_INCORRECT_STATE); + VerifyOrReturnError(IsValidFabricIndex(fabricIndex), CHIP_ERROR_INVALID_FABRIC_INDEX); + + P256SerializedKeypair serializedKeypair; + + // Do not allow overwriting the existing key and just remove it from the previous Operational Keystore if needed. + if (!HasOpKeypairForFabric(fabricIndex)) + { + ReturnErrorOnFailure(operationalKeystore.ExportOpKeypairForFabric(fabricIndex, serializedKeypair)); + + auto operationalKeypair = Platform::MakeUnique(); + if (!operationalKeypair) + { + return CHIP_ERROR_NO_MEMORY; + } + + ReturnErrorOnFailure(operationalKeypair->Deserialize(serializedKeypair)); + ReturnErrorOnFailure(StoreOperationalKey(fabricIndex, mStorage, operationalKeypair.get())); + + ReturnErrorOnFailure(operationalKeystore.RemoveOpKeypairForFabric(fabricIndex)); + } + else if (operationalKeystore.HasOpKeypairForFabric(fabricIndex)) + { + ReturnErrorOnFailure(operationalKeystore.RemoveOpKeypairForFabric(fabricIndex)); + } + + return CHIP_NO_ERROR; +} + +} // namespace chip + +#endif /* CONFIG_ENABLE_AMEBA_CRYPTO */ diff --git a/src/platform/Ameba/crypto/AmebaPersistentStorageOperationalKeystore.h b/src/platform/Ameba/crypto/AmebaPersistentStorageOperationalKeystore.h new file mode 100644 index 00000000000000..4969e0677764c9 --- /dev/null +++ b/src/platform/Ameba/crypto/AmebaPersistentStorageOperationalKeystore.h @@ -0,0 +1,146 @@ +/* + * Copyright (c) 2022 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#if CONFIG_ENABLE_AMEBA_CRYPTO +#include +#include +#include +#include +#include +#include +#include + +namespace chip { + +class AmebaP256Keypair : public Crypto::P256Keypair +{ +public: + AmebaP256Keypair() {} + ~AmebaP256Keypair() override; + + /** + * @brief Initialize the keypair. + * @return Returns a CHIP_ERROR on error, CHIP_NO_ERROR otherwise + **/ + CHIP_ERROR Initialize(Crypto::ECPKeyTarget key_target) override; + + /** @brief Return public key for the keypair. + **/ + const Crypto::P256PublicKey & Pubkey() const override { return mPublicKey; } + + /** Release resources associated with this key pair */ + void Clear(); + +protected: + Crypto::P256PublicKey mPublicKey; + mutable Crypto::P256KeypairContext mKeypair; + bool mInitialized = false; +}; + +/** + * @brief OperationalKeystore implementation making use of PersistentStorageDelegate + * to load/store keypairs. This is the legacy behavior of `FabricTable` prior + * to refactors to use `OperationalKeystore` and exists as a baseline example + * of how to use the interface. + * + * WARNING: Ensure that any implementation that uses this one as a starting point + * DOES NOT have the raw key material (in usable form) passed up/down to + * direct storage APIs that may make copies on heap/stack without sanitization. + */ +class AmebaPersistentStorageOperationalKeystore : public Crypto::OperationalKeystore +{ +public: + AmebaPersistentStorageOperationalKeystore() = default; + virtual ~AmebaPersistentStorageOperationalKeystore() { Finish(); } + + // Non-copyable + AmebaPersistentStorageOperationalKeystore(AmebaPersistentStorageOperationalKeystore const &) = delete; + void operator=(AmebaPersistentStorageOperationalKeystore const &) = delete; + + /** + * @brief Initialize the Operational Keystore to map to a given storage delegate. + * + * @param storage Pointer to persistent storage delegate to use. Must outlive this instance. + * @retval CHIP_NO_ERROR on success + * @retval CHIP_ERROR_INCORRECT_STATE if already initialized + */ + CHIP_ERROR Init(PersistentStorageDelegate * storage) + { + VerifyOrReturnError(mStorage == nullptr, CHIP_ERROR_INCORRECT_STATE); + mPendingFabricIndex = kUndefinedFabricIndex; + mIsExternallyOwnedKeypair = false; + mStorage = storage; + mPendingKeypair = nullptr; + mIsPendingKeypairActive = false; + return CHIP_NO_ERROR; + } + + /** + * @brief Finalize the keystore, so that subsequent operations fail + */ + void Finish() + { + VerifyOrReturn(mStorage != nullptr); + + ResetPendingKey(); + mStorage = nullptr; + } + + bool HasPendingOpKeypair() const override { return (mPendingKeypair != nullptr); } + + bool HasOpKeypairForFabric(FabricIndex fabricIndex) const override; + CHIP_ERROR NewOpKeypairForFabric(FabricIndex fabricIndex, MutableByteSpan & outCertificateSigningRequest) override; + CHIP_ERROR ActivateOpKeypairForFabric(FabricIndex fabricIndex, const Crypto::P256PublicKey & nocPublicKey) override; + CHIP_ERROR CommitOpKeypairForFabric(FabricIndex fabricIndex) override; + CHIP_ERROR ExportOpKeypairForFabric(FabricIndex fabricIndex, Crypto::P256SerializedKeypair & outKeypair) override; + CHIP_ERROR RemoveOpKeypairForFabric(FabricIndex fabricIndex) override; + void RevertPendingKeypair() override; + CHIP_ERROR SignWithOpKeypair(FabricIndex fabricIndex, const ByteSpan & message, + Crypto::P256ECDSASignature & outSignature) const override; + Crypto::P256Keypair * AllocateEphemeralKeypairForCASE() override; + void ReleaseEphemeralKeypair(Crypto::P256Keypair * keypair) override; + CHIP_ERROR MigrateOpKeypairForFabric(FabricIndex fabricIndex, OperationalKeystore & operationalKeystore) const override; + +protected: + void ResetPendingKey() + { + if (!mIsExternallyOwnedKeypair && (mPendingKeypair != nullptr)) + { + Platform::Delete(mPendingKeypair); + } + mPendingKeypair = nullptr; + mIsExternallyOwnedKeypair = false; + mIsPendingKeypairActive = false; + mPendingFabricIndex = kUndefinedFabricIndex; + } + + PersistentStorageDelegate * mStorage = nullptr; + + // This pending fabric index is `kUndefinedFabricIndex` if there isn't a pending keypair override for a given fabric. + FabricIndex mPendingFabricIndex = kUndefinedFabricIndex; + Crypto::P256Keypair * mPendingKeypair = nullptr; + bool mIsPendingKeypairActive = false; + + // If overridding NewOpKeypairForFabric method in a subclass, set this to true in + // `NewOpKeypairForFabric` if the mPendingKeypair should not be deleted when no longer in use. + bool mIsExternallyOwnedKeypair = false; +}; + +} // namespace chip +#endif /* CONFIG_ENABLE_AMEBA_CRYPTO */ From ddc06d45295eacc0ee43dcae49b21bd94b7f11d3 Mon Sep 17 00:00:00 2001 From: Junior Martinez <67972863+jmartinez-silabs@users.noreply.github.com> Date: Thu, 2 May 2024 18:02:23 -0400 Subject: [PATCH 32/33] [Silabs]Migration memMonitoring to cmsisos with some cleanup due to api changes (#33270) * Migration memMonitoring to cmsisos with some cleanup due to api changes change namespace and method names * fixup * Apply suggestion to use new/delete instead of longer MemoryMalloc/MemoryFree api --- examples/platform/silabs/MatterConfig.cpp | 2 +- examples/platform/silabs/MemMonitoring.cpp | 110 ++++++++++----------- examples/platform/silabs/MemMonitoring.h | 13 ++- 3 files changed, 64 insertions(+), 61 deletions(-) diff --git a/examples/platform/silabs/MatterConfig.cpp b/examples/platform/silabs/MatterConfig.cpp index 9cc030557ab0f3..0789c12f37aaac 100644 --- a/examples/platform/silabs/MatterConfig.cpp +++ b/examples/platform/silabs/MatterConfig.cpp @@ -240,7 +240,7 @@ CHIP_ERROR SilabsMatterConfig::InitMatter(const char * appName) #endif #ifdef HEAP_MONITORING - MemMonitoring::startHeapMonitoring(); + MemMonitoring::StartMonitor(); #endif //============================================== diff --git a/examples/platform/silabs/MemMonitoring.cpp b/examples/platform/silabs/MemMonitoring.cpp index 9da075e4e79d42..7ea61e4c8fe265 100644 --- a/examples/platform/silabs/MemMonitoring.cpp +++ b/examples/platform/silabs/MemMonitoring.cpp @@ -19,93 +19,91 @@ #include "MemMonitoring.h" #include "AppConfig.h" -#include "FreeRTOS.h" +#include #include +#include -#define BLE_STACK_TASK_NAME "Bluetooth stack" -#define BLE_LINK_TASK_NAME "Bluetooth linklayer" +namespace chip { +namespace DeviceLayer { +namespace Silabs { -static StackType_t monitoringStack[MONITORING_STACK_SIZE_byte / sizeof(StackType_t)]; -static StaticTask_t monitoringTaskStruct; +static osThreadId_t sMonitorThreadHandle; +constexpr uint32_t kMonitorTaskSize = 1024; +static uint8_t monitorStack[kMonitorTaskSize]; +static osThread_t sMonitorTaskControlBlock; +constexpr osThreadAttr_t kMonitorTaskAttr = { .name = "MemMonitor", + .attr_bits = osThreadDetached, + .cb_mem = &sMonitorTaskControlBlock, + .cb_size = osThreadCbSize, + .stack_mem = monitorStack, + .stack_size = kMonitorTaskSize, + .priority = osPriorityLow }; size_t nbAllocSuccess = 0; size_t nbFreeSuccess = 0; size_t largestBlockAllocated = 0; -void MemMonitoring::startHeapMonitoring() +void MemMonitoring::StartMonitor() { - xTaskCreateStatic(HeapMonitoring, "Monitoring", MONITORING_STACK_SIZE_byte / sizeof(StackType_t), NULL, 1, monitoringStack, - &monitoringTaskStruct); + sMonitorThreadHandle = osThreadNew(MonitorTask, nullptr, &kMonitorTaskAttr); } -void MemMonitoring::HeapMonitoring(void * pvParameter) +void MemMonitoring::MonitorTask(void * pvParameter) { + uint32_t threadCount = osThreadGetCount(); - UBaseType_t appTaskValue; - UBaseType_t bleEventTaskValue; - UBaseType_t bleTaskValue; - UBaseType_t linkLayerTaskValue; - UBaseType_t openThreadTaskValue; - UBaseType_t eventLoopTaskValue; - - TaskHandle_t eventLoopHandleStruct = xTaskGetHandle(CHIP_DEVICE_CONFIG_CHIP_TASK_NAME); - TaskHandle_t otTaskHandle = xTaskGetHandle(CHIP_DEVICE_CONFIG_THREAD_TASK_NAME); - TaskHandle_t appTaskHandle = xTaskGetHandle(APP_TASK_NAME); - TaskHandle_t bleStackTaskHandle = xTaskGetHandle(BLE_STACK_TASK_NAME); - TaskHandle_t bleLinkTaskHandle = xTaskGetHandle(BLE_LINK_TASK_NAME); - TaskHandle_t bleEventTaskHandle = xTaskGetHandle(CHIP_DEVICE_CONFIG_BLE_APP_TASK_NAME); - -#if CHIP_SYSTEM_CONFIG_USE_LWIP - UBaseType_t lwipTaskValue; - TaskHandle_t lwipHandle = xTaskGetHandle(TCPIP_THREAD_NAME); -#endif // CHIP_SYSTEM_CONFIG_USE_LWIP + osThreadId_t * threadIdTable = new osThreadId_t[threadCount]; + // Forms a table of the active thread ids + osThreadEnumerate(threadIdTable, threadCount); while (true) { - appTaskValue = uxTaskGetStackHighWaterMark(appTaskHandle); - bleEventTaskValue = uxTaskGetStackHighWaterMark(bleEventTaskHandle); - bleTaskValue = uxTaskGetStackHighWaterMark(bleStackTaskHandle); - linkLayerTaskValue = uxTaskGetStackHighWaterMark(bleLinkTaskHandle); - openThreadTaskValue = uxTaskGetStackHighWaterMark(otTaskHandle); - eventLoopTaskValue = uxTaskGetStackHighWaterMark(eventLoopHandleStruct); -#if CHIP_SYSTEM_CONFIG_USE_LWIP - lwipTaskValue = uxTaskGetStackHighWaterMark(lwipHandle); -#endif // CHIP_SYSTEM_CONFIG_USE_LWIP SILABS_LOG("============================="); - SILABS_LOG(" "); - SILABS_LOG("Largest Block allocated 0x%x", largestBlockAllocated); - SILABS_LOG("Number Of Successful Alloc 0x%x", nbAllocSuccess); - SILABS_LOG("Number Of Successful Frees 0x%x", nbFreeSuccess); - SILABS_LOG(" "); - SILABS_LOG("App Task most bytes ever Free 0x%x", (appTaskValue * 4)); - SILABS_LOG("BLE Event most bytes ever Free 0x%x", (bleEventTaskValue * 4)); - SILABS_LOG("BLE Stack most bytes ever Free 0x%x", (bleTaskValue * 4)); - SILABS_LOG("Link Layer Task most bytes ever Free 0x%x", (linkLayerTaskValue * 4)); - SILABS_LOG("OpenThread Task most bytes ever Free 0x%x", (openThreadTaskValue * 4)); - SILABS_LOG("Event Loop Task most bytes ever Free 0x%x", (eventLoopTaskValue * 4)); -#if CHIP_SYSTEM_CONFIG_USE_LWIP - SILABS_LOG("LWIP Task most bytes ever Free 0x%x", (lwipTaskValue * 4)); -#endif // CHIP_SYSTEM_CONFIG_USE_LWIP - SILABS_LOG(" "); + SILABS_LOG(" "); + SILABS_LOG("Largest Block allocated %lu B", largestBlockAllocated); + SILABS_LOG("Number Of Successful Alloc %lu", nbAllocSuccess); + SILABS_LOG("Number Of Successful Frees %lu", nbFreeSuccess); + SILABS_LOG(" "); + + SILABS_LOG("Thread stack highwatermark "); + for (uint8_t tIdIndex = 0; tIdIndex < threadCount; tIdIndex++) + { + osThreadId_t tId = threadIdTable[tIdIndex]; + if (tId != sMonitorThreadHandle) // don't print stats for this current debug thread. + { + // The smallest amount of free stack space there has been since the thread creation + SILABS_LOG("\t%-10s : %6lu B", osThreadGetName(tId), osThreadGetStackSpace(tId)); + } + } + + SILABS_LOG(" "); SILABS_LOG("============================="); - vTaskDelay(pdMS_TO_TICKS(5000)); + // run loop every 5 seconds + osDelay(osKernelGetTickFreq() * 5); } + + // will never get here. Still, free allocated memory before exiting + delete threadIdTable; } +} // namespace Silabs +} // namespace DeviceLayer +} // namespace chip + extern "C" void memMonitoringTrackAlloc(void * ptr, size_t size) { if (ptr != NULL) { - nbAllocSuccess++; - if (largestBlockAllocated < size) + chip::DeviceLayer::Silabs::nbAllocSuccess++; + if (chip::DeviceLayer::Silabs::largestBlockAllocated < size) { - largestBlockAllocated = size; + chip::DeviceLayer::Silabs::largestBlockAllocated = size; } } } extern "C" void memMonitoringTrackFree(void * ptr, size_t size) { - nbFreeSuccess++; + chip::DeviceLayer::Silabs::nbFreeSuccess++; } diff --git a/examples/platform/silabs/MemMonitoring.h b/examples/platform/silabs/MemMonitoring.h index ffc430ccaf3193..c54aa2acf421ee 100644 --- a/examples/platform/silabs/MemMonitoring.h +++ b/examples/platform/silabs/MemMonitoring.h @@ -19,17 +19,22 @@ #pragma once #ifdef HEAP_MONITORING -#include "FreeRTOS.h" -#define MONITORING_STACK_SIZE_byte 1024 +namespace chip { +namespace DeviceLayer { +namespace Silabs { class MemMonitoring { public: - static void startHeapMonitoring(); + static void StartMonitor(); private: - static void HeapMonitoring(void * pvParameter); + static void MonitorTask(void * pvParameter); }; +} // namespace Silabs +} // namespace DeviceLayer +} // namespace chip + #endif From fcfc9bcc85afa4054cf84cbc1606b64eb305b94d Mon Sep 17 00:00:00 2001 From: Karsten Sperling <113487422+ksperling-apple@users.noreply.github.com> Date: Fri, 3 May 2024 12:13:52 +1200 Subject: [PATCH 33/33] Fix handling of short discriminator in QRCodeSetupPayloadGenerator (#33250) * Fix handling of short discriminator in QRCodeSetupPayloadGenerator If a SetupPayload contains a short discriminator then - isValidQRCodePayload() should return false - trying to generate a QR Code should return INVALID_ARGUMENT - generating with SetAllowInvalidPayload(true) should work (not die) * SetupPayload tweaks Make IsCommonTag, IsVendorTag, and getOptionalVendorData(tag, &info) public. The first two are just encoding spec rules that are useful for clients, and the latter allows clients to read vendor data by tag instead of having to read the whole list. Also use default values instead of explicit constructors for OptionalQRCodeInfo and fix up some doc comments to correctly reference the vendor tag range. * Address review comments Elaborate on the use case for AllowInvalidPayload in the comments, and encode a missing long discriminator as 0, to avoid a client encoding invalid payloads from relying on round-tripping a short discriminator through a QR code. * Handle rendezvousInformation and discriminator the same way * Address review comment: use ValueOr --- .../QRCodeSetupPayloadGenerator.cpp | 12 +++-- src/setup_payload/SetupPayload.cpp | 18 ++----- src/setup_payload/SetupPayload.h | 49 ++++++++----------- src/setup_payload/tests/TestQRCode.cpp | 38 ++++++++++++++ 4 files changed, 72 insertions(+), 45 deletions(-) diff --git a/src/setup_payload/QRCodeSetupPayloadGenerator.cpp b/src/setup_payload/QRCodeSetupPayloadGenerator.cpp index 6ffa2319dadb35..962a0393736683 100644 --- a/src/setup_payload/QRCodeSetupPayloadGenerator.cpp +++ b/src/setup_payload/QRCodeSetupPayloadGenerator.cpp @@ -162,6 +162,11 @@ static CHIP_ERROR generateBitSet(PayloadContents & payload, MutableByteSpan & bi size_t totalPayloadSizeInBits = kTotalPayloadDataSizeInBits + (tlvDataLengthInBytes * 8); VerifyOrReturnError(bits.size() * 8 >= totalPayloadSizeInBits, CHIP_ERROR_BUFFER_TOO_SMALL); + // isValidQRCodePayload() has already performed all relevant checks (including that we have a + // long discriminator and rendevouz information). But if AllowInvalidPayload is set these + // requirements might be violated; in that case simply encode 0 for the relevant fields. + // Encoding an invalid (or partially valid) payload is useful for clients that need to be able + // to serialize and deserialize partially populated or invalid payloads. ReturnErrorOnFailure( populateBits(bits.data(), offset, payload.version, kVersionFieldLengthInBits, kTotalPayloadDataSizeInBits)); ReturnErrorOnFailure( @@ -170,10 +175,11 @@ static CHIP_ERROR generateBitSet(PayloadContents & payload, MutableByteSpan & bi populateBits(bits.data(), offset, payload.productID, kProductIDFieldLengthInBits, kTotalPayloadDataSizeInBits)); ReturnErrorOnFailure(populateBits(bits.data(), offset, static_cast(payload.commissioningFlow), kCommissioningFlowFieldLengthInBits, kTotalPayloadDataSizeInBits)); - VerifyOrReturnError(payload.rendezvousInformation.HasValue(), CHIP_ERROR_INVALID_ARGUMENT); - ReturnErrorOnFailure(populateBits(bits.data(), offset, payload.rendezvousInformation.Value().Raw(), + ReturnErrorOnFailure(populateBits(bits.data(), offset, + payload.rendezvousInformation.ValueOr(RendezvousInformationFlag::kNone).Raw(), kRendezvousInfoFieldLengthInBits, kTotalPayloadDataSizeInBits)); - ReturnErrorOnFailure(populateBits(bits.data(), offset, payload.discriminator.GetLongValue(), + auto const & pd = payload.discriminator; + ReturnErrorOnFailure(populateBits(bits.data(), offset, (!pd.IsShortDiscriminator() ? pd.GetLongValue() : 0), kPayloadDiscriminatorFieldLengthInBits, kTotalPayloadDataSizeInBits)); ReturnErrorOnFailure( populateBits(bits.data(), offset, payload.setUpPINCode, kSetupPINCodeFieldLengthInBits, kTotalPayloadDataSizeInBits)); diff --git a/src/setup_payload/SetupPayload.cpp b/src/setup_payload/SetupPayload.cpp index 3d312cd5846e8d..063456327f6a62 100644 --- a/src/setup_payload/SetupPayload.cpp +++ b/src/setup_payload/SetupPayload.cpp @@ -33,18 +33,6 @@ namespace chip { -// Spec 5.1.4.2 CHIPCommon tag numbers are in the range [0x00, 0x7F] -bool SetupPayload::IsCommonTag(uint8_t tag) -{ - return tag < 0x80; -} - -// Spec 5.1.4.1 Manufacture-specific tag numbers are in the range [0x80, 0xFF] -bool SetupPayload::IsVendorTag(uint8_t tag) -{ - return !IsCommonTag(tag); -} - // Check the Setup Payload for validity // // `vendor_id` and `product_id` are allowed all of uint16_t @@ -79,7 +67,11 @@ bool PayloadContents::isValidQRCodePayload() const return false; } - // Discriminator validity is enforced by the SetupDiscriminator class. + // General discriminator validity is enforced by the SetupDiscriminator class, but it can't be short for QR a code. + if (discriminator.IsShortDiscriminator()) + { + return false; + } if (setUpPINCode >= 1 << kSetupPINCodeFieldLengthInBits) { diff --git a/src/setup_payload/SetupPayload.h b/src/setup_payload/SetupPayload.h index 9b18574480ba6e..6e81e0e0e48ddb 100644 --- a/src/setup_payload/SetupPayload.h +++ b/src/setup_payload/SetupPayload.h @@ -153,29 +153,19 @@ enum optionalQRCodeInfoType */ struct OptionalQRCodeInfo { - OptionalQRCodeInfo() { int32 = 0; } - /*@{*/ uint8_t tag; /**< the tag number of the optional info */ enum optionalQRCodeInfoType type; /**< the type (String or Int) of the optional info */ std::string data; /**< the string value if type is optionalQRCodeInfoTypeString, otherwise should not be set */ - int32_t int32; /**< the integer value if type is optionalQRCodeInfoTypeInt, otherwise should not be set */ + int32_t int32 = 0; /**< the integer value if type is optionalQRCodeInfoTypeInt32, otherwise should not be set */ /*@}*/ }; struct OptionalQRCodeInfoExtension : OptionalQRCodeInfo { - OptionalQRCodeInfoExtension() - { - int32 = 0; - int64 = 0; - uint32 = 0; - uint64 = 0; - } - - int64_t int64; - uint64_t uint32; - uint64_t uint64; + int64_t int64 = 0; /**< the integer value if type is optionalQRCodeInfoTypeInt64, otherwise should not be set */ + uint64_t uint32 = 0; /**< the integer value if type is optionalQRCodeInfoTypeUInt32, otherwise should not be set */ + uint64_t uint64 = 0; /**< the integer value if type is optionalQRCodeInfoTypeUInt64, otherwise should not be set */ }; class SetupPayload : public PayloadContents @@ -193,17 +183,25 @@ class SetupPayload : public PayloadContents CHIP_ERROR addOptionalVendorData(uint8_t tag, std::string data); /** @brief A function to add an optional vendor data - * @param tag 7 bit [0-127] tag number + * @param tag tag number in the [0x80-0xFF] range * @param data Integer representation of data to add * @return Returns a CHIP_ERROR on error, CHIP_NO_ERROR otherwise **/ CHIP_ERROR addOptionalVendorData(uint8_t tag, int32_t data); /** @brief A function to remove an optional vendor data - * @param tag 7 bit [0-127] tag number + * @param tag tag number in the [0x80-0xFF] range * @return Returns a CHIP_ERROR_KEY_NOT_FOUND on error, CHIP_NO_ERROR otherwise **/ CHIP_ERROR removeOptionalVendorData(uint8_t tag); + + /** @brief A function to retrieve an optional QR Code info vendor object + * @param tag tag number in the [0x80-0xFF] range + * @param info retrieved OptionalQRCodeInfo object + * @return Returns a CHIP_ERROR_KEY_NOT_FOUND on error, CHIP_NO_ERROR otherwise + **/ + CHIP_ERROR getOptionalVendorData(uint8_t tag, OptionalQRCodeInfo & info) const; + /** * @brief A function to retrieve the vector of OptionalQRCodeInfo infos * @return Returns a vector of optionalQRCodeInfos @@ -235,21 +233,21 @@ class SetupPayload : public PayloadContents bool operator==(const SetupPayload & input) const; -private: - std::map optionalVendorData; - std::map optionalExtensionData; - /** @brief Checks if the tag is CHIP Common type * @param tag Tag to be checked * @return Returns True if the tag is of Common type **/ - static bool IsCommonTag(uint8_t tag); + static bool IsCommonTag(uint8_t tag) { return tag < 0x80; } /** @brief Checks if the tag is vendor-specific * @param tag Tag to be checked * @return Returns True if the tag is Vendor-specific **/ - static bool IsVendorTag(uint8_t tag); + static bool IsVendorTag(uint8_t tag) { return !IsCommonTag(tag); } + +private: + std::map optionalVendorData; + std::map optionalExtensionData; /** @brief A function to add an optional QR Code info vendor object * @param info Optional QR code info object to add @@ -269,13 +267,6 @@ class SetupPayload : public PayloadContents **/ std::vector getAllOptionalExtensionData() const; - /** @brief A function to retrieve an optional QR Code info vendor object - * @param tag 7 bit [0-127] tag number - * @param info retrieved OptionalQRCodeInfo object - * @return Returns a CHIP_ERROR_KEY_NOT_FOUND on error, CHIP_NO_ERROR otherwise - **/ - CHIP_ERROR getOptionalVendorData(uint8_t tag, OptionalQRCodeInfo & info) const; - /** @brief A function to retrieve an optional QR Code info extended object * @param tag 8 bit [128-255] tag number * @param info retrieved OptionalQRCodeInfoExtension object diff --git a/src/setup_payload/tests/TestQRCode.cpp b/src/setup_payload/tests/TestQRCode.cpp index 1ec508578dec30..6ca349c2884341 100644 --- a/src/setup_payload/tests/TestQRCode.cpp +++ b/src/setup_payload/tests/TestQRCode.cpp @@ -381,6 +381,44 @@ TEST(TestQRCode, TestQRCodeToPayloadGeneration) EXPECT_EQ(result, true); } +TEST(TestQRCode, TestGenerateWithShortDiscriminatorInvalid) +{ + SetupPayload payload = GetDefaultPayload(); + EXPECT_TRUE(payload.isValidQRCodePayload()); + + // A short discriminator isn't valid for a QR Code + payload.discriminator.SetShortValue(1); + EXPECT_FALSE(payload.isValidQRCodePayload()); + + // QRCodeSetupPayloadGenerator should therefore return an error + string base38Rep; + QRCodeSetupPayloadGenerator generator(payload); + EXPECT_EQ(generator.payloadBase38Representation(base38Rep), CHIP_ERROR_INVALID_ARGUMENT); + + // If we allow invalid payloads we should be able to encode + generator.SetAllowInvalidPayload(true); + EXPECT_EQ(generator.payloadBase38Representation(base38Rep), CHIP_NO_ERROR); +} + +TEST(TestQRCode, TestGenerateWithoutRendezvousInformation) +{ + SetupPayload payload = GetDefaultPayload(); + EXPECT_TRUE(payload.isValidQRCodePayload()); + + // Rendezvouz Information is required for a QR code + payload.rendezvousInformation.ClearValue(); + EXPECT_FALSE(payload.isValidQRCodePayload()); + + // QRCodeSetupPayloadGenerator should therefore return an error + string base38Rep; + QRCodeSetupPayloadGenerator generator(payload); + EXPECT_EQ(generator.payloadBase38Representation(base38Rep), CHIP_ERROR_INVALID_ARGUMENT); + + // If we allow invalid payloads we should be able to encode + generator.SetAllowInvalidPayload(true); + EXPECT_EQ(generator.payloadBase38Representation(base38Rep), CHIP_NO_ERROR); +} + TEST(TestQRCode, TestExtractPayload) { EXPECT_EQ(QRCodeSetupPayloadParser::ExtractPayload(string("MT:ABC")), string("ABC"));