From 84ecb78eac60c3f68c21a7ed1cda06a252f1a77f Mon Sep 17 00:00:00 2001 From: Martin Roesch Date: Fri, 4 Mar 2022 15:42:08 +0100 Subject: [PATCH 01/30] Only build dynamic libraries if the target platform supports it. The CMake variable TARGET_SUPPORTS_SHARED_LIBS provides this information. E.g. Zephyr does not support dynamic libraries. --- CMakeLists.txt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6139193b25..18854d0c3c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -309,7 +309,7 @@ set_target_properties(client-static PROPERTIES VERSION ${PROJECT_VERSION} ) -if(NOT MSVC) +if(TARGET_SUPPORTS_SHARED_LIBS AND NOT MSVC) # Since the library symbols are not explicitly exported, no proper DLL and import LIB are generated with MSVC add_library(client-shared SHARED ${client-lib-obj}) target_link_libraries(client-shared PRIVATE ${PRIVATE_LINK_LIBS}) @@ -365,7 +365,7 @@ set_target_properties(server-static PROPERTIES VERSION ${PROJECT_VERSION} ) -if(NOT MSVC) +if(TARGET_SUPPORTS_SHARED_LIBS AND NOT MSVC) # Since the library symbols are not explicitly exported, no proper DLL and import LIB are generated with MSVC add_library(server-shared SHARED ${server-lib-obj}) target_link_libraries(server-shared PRIVATE ${PRIVATE_LINK_LIBS}) @@ -426,7 +426,7 @@ set_target_properties(client-server-static PROPERTIES VERSION ${PROJECT_VERSION} ) -if(NOT MSVC) +if(TARGET_SUPPORTS_SHARED_LIBS AND NOT MSVC) # Since the library symbols are not explicitly exported, no proper DLL and import LIB are generated with MSVC add_library(client-server-shared SHARED ${client-server-lib-obj}) target_link_libraries(client-server-shared PRIVATE ${PRIVATE_LINK_LIBS}) @@ -596,7 +596,7 @@ set(INSTALL_TARGETS server-static server-shared client-server-static client-server-shared ) -if(MSVC) +if(NOT TARGET_SUPPORTS_SHARED_LIBS OR MSVC) # Since the library symbols are not explicitly exported, no proper DLL and import LIB are generated with MSVC set(INSTALL_TARGETS client-static From 8d32cd7d95ac163e50683295df85b6ab1d0b3797 Mon Sep 17 00:00:00 2001 From: Martin Roesch Date: Fri, 4 Mar 2022 15:43:03 +0100 Subject: [PATCH 02/30] Raise CMake Error if the port cannot be determined --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 18854d0c3c..965d241ccf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -177,7 +177,7 @@ elseif(WIN32) file(GLOB PORT_SRC port/windows/*.c) set(PORT_INCLUDE_DIR ${PROJECT_SOURCE_DIR}/port/windows) else() - message(ERROR "Can build only on Linux and Windows!") + message(FATAL_ERROR "Can determine the port to use!") endif() list(APPEND SERVER_SRC ${PORT_SRC}) list(APPEND CLIENT_SRC ${PORT_SRC}) From 6dcf029905a1b38c1513b2334eb79b8e64c8fd71 Mon Sep 17 00:00:00 2001 From: Martin Roesch Date: Fri, 4 Mar 2022 15:54:08 +0100 Subject: [PATCH 03/30] Add CMake variable for compile options TinyCBor queries compile definitions in its header files for overrides that may needed for a target platform (e.g. Zephyr). --- CMakeLists.txt | 7 +++++++ deps/mbedtls.cmake | 3 ++- deps/tinycbor.cmake | 1 + 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 965d241ccf..917372c47b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -82,6 +82,7 @@ include(tools/clang-tidy.cmake) ######## Define compiler flags ######## set(PRIVATE_COMPILE_DEFINITIONS "") set(PUBLIC_COMPILE_DEFINITIONS "") +set(PRIVATE_COMPILE_OPTIONS "") if(OC_DYNAMIC_ALLOCATION_ENABLED) list(APPEND PUBLIC_COMPILE_DEFINITIONS "OC_DYNAMIC_ALLOCATION") endif() @@ -237,10 +238,12 @@ oc_enable_clang_tidy() add_library(common-obj OBJECT ${COMMON_SRC}) target_compile_definitions(common-obj PRIVATE ${PRIVATE_COMPILE_DEFINITIONS} PUBLIC ${PUBLIC_COMPILE_DEFINITIONS}) +target_compile_options(common-obj PRIVATE ${PRIVATE_COMPILE_OPTIONS}) target_include_directories(common-obj PRIVATE ${PROJECT_SOURCE_DIR} ${PROJECT_SOURCE_DIR}/include ${PROJECT_SOURCE_DIR}/port ${PORT_INCLUDE_DIR}) add_library(client-obj OBJECT ${CLIENT_SRC}) target_compile_definitions(client-obj PRIVATE ${PRIVATE_COMPILE_DEFINITIONS} PUBLIC ${PUBLIC_COMPILE_DEFINITIONS} "OC_CLIENT") +target_compile_options(client-obj PRIVATE ${PRIVATE_COMPILE_OPTIONS}) target_include_directories(client-obj PRIVATE ${PROJECT_SOURCE_DIR} ${PROJECT_SOURCE_DIR}/include ${PROJECT_SOURCE_DIR}/port ${PORT_INCLUDE_DIR}) if(OC_SECURITY_ENABLED) target_include_directories(client-obj PRIVATE ${MBEDTLS_INCLUDE_DIRS}) @@ -248,6 +251,7 @@ endif() add_library(server-obj OBJECT ${SERVER_SRC}) target_compile_definitions(server-obj PRIVATE ${PRIVATE_COMPILE_DEFINITIONS} PUBLIC ${PUBLIC_COMPILE_DEFINITIONS} "OC_SERVER") +target_compile_options(server-obj PRIVATE ${PRIVATE_COMPILE_OPTIONS}) target_include_directories(server-obj PRIVATE ${PROJECT_SOURCE_DIR} ${PROJECT_SOURCE_DIR}/include ${PROJECT_SOURCE_DIR}/port ${PORT_INCLUDE_DIR}) if(OC_SECURITY_ENABLED) target_include_directories(server-obj PRIVATE ${MBEDTLS_INCLUDE_DIRS}) @@ -255,6 +259,7 @@ endif() add_library(client-server-obj OBJECT ${CLIENT_SRC}) target_compile_definitions(client-server-obj PRIVATE ${PRIVATE_COMPILE_DEFINITIONS} PUBLIC ${PUBLIC_COMPILE_DEFINITIONS} "OC_CLIENT" "OC_SERVER") +target_compile_options(client-server-obj PRIVATE ${PRIVATE_COMPILE_OPTIONS}) target_include_directories(client-server-obj PRIVATE ${PROJECT_SOURCE_DIR} ${PROJECT_SOURCE_DIR}/include ${PROJECT_SOURCE_DIR}/port ${PORT_INCLUDE_DIR}) if(OC_SECURITY_ENABLED) target_include_directories(client-server-obj PRIVATE ${MBEDTLS_INCLUDE_DIRS}) @@ -263,6 +268,7 @@ endif() if(OC_CLOUD_ENABLED) add_library(cloud-obj OBJECT ${CLOUD_SRC}) target_compile_definitions(cloud-obj PRIVATE ${PRIVATE_COMPILE_DEFINITIONS} PUBLIC ${PUBLIC_COMPILE_DEFINITIONS}) + target_compile_options(cloud-obj PRIVATE ${PRIVATE_COMPILE_OPTIONS}) target_include_directories(cloud-obj PRIVATE ${PROJECT_SOURCE_DIR} ${PROJECT_SOURCE_DIR}/include ${PROJECT_SOURCE_DIR}/port ${PORT_INCLUDE_DIR}) if(OC_SECURITY_ENABLED) target_include_directories(cloud-obj PRIVATE ${MBEDTLS_INCLUDE_DIRS}) @@ -271,6 +277,7 @@ endif() add_library(python-obj OBJECT ${PYTHON_SRC}) target_compile_definitions(python-obj PRIVATE ${PRIVATE_COMPILE_DEFINITIONS} OC_LIBRARY_EXPORT PUBLIC ${PUBLIC_COMPILE_DEFINITIONS} "OC_LIBRARY" "OC_CLIENT") +target_compile_options(python-obj PRIVATE ${PRIVATE_COMPILE_OPTIONS}) set_property(TARGET python-obj PROPERTY C_VISIBILITY_PRESET hidden) set_property(TARGET python-obj PROPERTY VISIBILITY_INLINES_HIDDEN ON) target_include_directories(python-obj PRIVATE ${PROJECT_SOURCE_DIR} ${PROJECT_SOURCE_DIR}/include ${PROJECT_SOURCE_DIR}/port ${PORT_INCLUDE_DIR}) diff --git a/deps/mbedtls.cmake b/deps/mbedtls.cmake index 49f8f31a2f..bdab72f601 100755 --- a/deps/mbedtls.cmake +++ b/deps/mbedtls.cmake @@ -24,7 +24,8 @@ target_include_directories(mbedtls PRIVATE ${PROJECT_SOURCE_DIR}/deps/mbedtls/include ) target_compile_definitions(mbedtls PUBLIC ${PUBLIC_COMPILE_DEFINITIONS} PRIVATE ${PRIVATE_COMPILE_DEFINITIONS} __OC_RANDOM) +target_compile_options(mbedtls PRIVATE ${PRIVATE_COMPILE_OPTIONS}) # do not treat warnings as errors on Windows if(MSVC) target_compile_options(mbedtls PRIVATE /W1 /WX-) -endif() +endif() \ No newline at end of file diff --git a/deps/tinycbor.cmake b/deps/tinycbor.cmake index 6781a78440..8b35470da8 100755 --- a/deps/tinycbor.cmake +++ b/deps/tinycbor.cmake @@ -11,6 +11,7 @@ target_include_directories(tinycbor-master PUBLIC ) target_compile_definitions(tinycbor-master PUBLIC ${PUBLIC_COMPILE_DEFINITIONS}) +target_compile_options(tinycbor-master PRIVATE ${PRIVATE_COMPILE_OPTIONS}) install(DIRECTORY ${PROJECT_SOURCE_DIR}/deps/tinycbor/src/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/iotivity-lite/deps/tinycbor/src COMPONENT dev From 29bcd1fa30298eff17cc9296420ecd537924c1d1 Mon Sep 17 00:00:00 2001 From: Martin Roesch Date: Fri, 4 Mar 2022 16:09:04 +0100 Subject: [PATCH 04/30] Add CMake variable for CMake target dependencies The Zephyr SDK generates some platform header files in a CMake target, which has to be completed before the compilation of iotivity-lite can start. Defining dependencies for our targets delays the targets until the dependent targets have finished. --- CMakeLists.txt | 7 +++++++ deps/mbedtls.cmake | 3 ++- deps/tinycbor.cmake | 1 + 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 917372c47b..519c609214 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -149,6 +149,9 @@ if(OC_DNS_LOOKUP_IPV6_ENABLED) list(APPEND PRIVATE_COMPILE_DEFINITIONS "OC_DNS_LOOKUP_IPV6") endif() +######## Target dependencies ######## +set(TARGET_DEPENDENCIES "") + ######## Gather source files ######## file(GLOB COMMON_SRC ${PROJECT_SOURCE_DIR}/api/c-timestamp/timestamp_format.c @@ -240,6 +243,7 @@ add_library(common-obj OBJECT ${COMMON_SRC}) target_compile_definitions(common-obj PRIVATE ${PRIVATE_COMPILE_DEFINITIONS} PUBLIC ${PUBLIC_COMPILE_DEFINITIONS}) target_compile_options(common-obj PRIVATE ${PRIVATE_COMPILE_OPTIONS}) target_include_directories(common-obj PRIVATE ${PROJECT_SOURCE_DIR} ${PROJECT_SOURCE_DIR}/include ${PROJECT_SOURCE_DIR}/port ${PORT_INCLUDE_DIR}) +add_dependencies(common-obj ${TARGET_DEPENDENCIES}) add_library(client-obj OBJECT ${CLIENT_SRC}) target_compile_definitions(client-obj PRIVATE ${PRIVATE_COMPILE_DEFINITIONS} PUBLIC ${PUBLIC_COMPILE_DEFINITIONS} "OC_CLIENT") @@ -248,6 +252,7 @@ target_include_directories(client-obj PRIVATE ${PROJECT_SOURCE_DIR} ${PROJECT_SO if(OC_SECURITY_ENABLED) target_include_directories(client-obj PRIVATE ${MBEDTLS_INCLUDE_DIRS}) endif() +add_dependencies(client-obj ${TARGET_DEPENDENCIES}) add_library(server-obj OBJECT ${SERVER_SRC}) target_compile_definitions(server-obj PRIVATE ${PRIVATE_COMPILE_DEFINITIONS} PUBLIC ${PUBLIC_COMPILE_DEFINITIONS} "OC_SERVER") @@ -256,6 +261,7 @@ target_include_directories(server-obj PRIVATE ${PROJECT_SOURCE_DIR} ${PROJECT_SO if(OC_SECURITY_ENABLED) target_include_directories(server-obj PRIVATE ${MBEDTLS_INCLUDE_DIRS}) endif() +add_dependencies(server-obj ${TARGET_DEPENDENCIES}) add_library(client-server-obj OBJECT ${CLIENT_SRC}) target_compile_definitions(client-server-obj PRIVATE ${PRIVATE_COMPILE_DEFINITIONS} PUBLIC ${PUBLIC_COMPILE_DEFINITIONS} "OC_CLIENT" "OC_SERVER") @@ -264,6 +270,7 @@ target_include_directories(client-server-obj PRIVATE ${PROJECT_SOURCE_DIR} ${PRO if(OC_SECURITY_ENABLED) target_include_directories(client-server-obj PRIVATE ${MBEDTLS_INCLUDE_DIRS}) endif() +add_dependencies(client-server-obj ${TARGET_DEPENDENCIES}) if(OC_CLOUD_ENABLED) add_library(cloud-obj OBJECT ${CLOUD_SRC}) diff --git a/deps/mbedtls.cmake b/deps/mbedtls.cmake index bdab72f601..d3c2a30df3 100755 --- a/deps/mbedtls.cmake +++ b/deps/mbedtls.cmake @@ -28,4 +28,5 @@ target_compile_options(mbedtls PRIVATE ${PRIVATE_COMPILE_OPTIONS}) # do not treat warnings as errors on Windows if(MSVC) target_compile_options(mbedtls PRIVATE /W1 /WX-) -endif() \ No newline at end of file +endif() +add_dependencies(mbedtls ${TARGET_DEPENDENCIES}) diff --git a/deps/tinycbor.cmake b/deps/tinycbor.cmake index 8b35470da8..19da7fae1c 100755 --- a/deps/tinycbor.cmake +++ b/deps/tinycbor.cmake @@ -12,6 +12,7 @@ target_include_directories(tinycbor-master PUBLIC target_compile_definitions(tinycbor-master PUBLIC ${PUBLIC_COMPILE_DEFINITIONS}) target_compile_options(tinycbor-master PRIVATE ${PRIVATE_COMPILE_OPTIONS}) +add_dependencies(tinycbor-master ${TARGET_DEPENDENCIES}) install(DIRECTORY ${PROJECT_SOURCE_DIR}/deps/tinycbor/src/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/iotivity-lite/deps/tinycbor/src COMPONENT dev From aab57fb907a3b3ac38c4017502b07b0e0be9a0e9 Mon Sep 17 00:00:00 2001 From: Martin Roesch Date: Fri, 4 Mar 2022 16:25:38 +0100 Subject: [PATCH 05/30] Detect Zephyr port If iotivity-lite is used as a CMake subproject in a Zephyr application, detect the Zephyr SDK with the ZEPHYR_BASE variable and setup the build for the Zephyr port: * Set the Zephyr CMake task zephyr_interface as target dependency. * Set the Zephyr include directories globally. * Add the Zephyr compile definitions and options. --- CMakeLists.txt | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 519c609214..675ec37f2a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -180,8 +180,31 @@ if(UNIX) elseif(WIN32) file(GLOB PORT_SRC port/windows/*.c) set(PORT_INCLUDE_DIR ${PROJECT_SOURCE_DIR}/port/windows) +elseif(DEFINED ZEPHYR_BASE) + # Set the Zephyr CMake task zephyr_interface as dependency. + # Zephyr generates some platform headers in that CMake task which needs to be completed + # before iotivity-lite compilation can start or the headers can not be found. + list(APPEND TARGET_DEPENDENCIES zephyr_interface) + + # Set the Zephyr include directories globally. + # Taken from zephyr/cmake/extensions.cmake: zephyr_get_include_directories_for_lang(C includes) + get_property(zephyr_include_dirs TARGET zephyr_interface PROPERTY INTERFACE_INCLUDE_DIRECTORIES) + include_directories(${zephyr_include_dirs}) + + # Add Zephyr compile definitions. + # Taken from zephyr/cmake/extensions.cmake: zephyr_get_compile_definitions_for_lang(C definitions) + get_property(zephyr_compile_defs TARGET zephyr_interface PROPERTY INTERFACE_COMPILE_DEFINITIONS) + list(APPEND PRIVATE_COMPILE_DEFINITIONS ${zephyr_compile_defs}) + + # Add Zephyr compile options. + # Taken from zephyr/cmake/extensions.cmake: zephyr_get_compile_options_for_lang(C options) + get_property(zephyr_compile_opts TARGET zephyr_interface PROPERTY INTERFACE_COMPILE_OPTIONS) + list(APPEND PRIVATE_COMPILE_OPTIONS ${zephyr_compile_opts}) + + file(GLOB PORT_SRC port/zephyr/src/*.c) + set(PORT_INCLUDE_DIR ${PROJECT_SOURCE_DIR}/port/zephyr/src) else() - message(FATAL_ERROR "Can determine the port to use!") + message(FATAL_ERROR "Cannot determine the port to use!") endif() list(APPEND SERVER_SRC ${PORT_SRC}) list(APPEND CLIENT_SRC ${PORT_SRC}) From cda25f5eba886fb903dfb7039d99332efee3342b Mon Sep 17 00:00:00 2001 From: Martin Roesch Date: Fri, 4 Mar 2022 17:06:43 +0100 Subject: [PATCH 06/30] Update tinycbor submodule to v0.6.0 TinyCBOR 0.6.0 allows to disable floating point support with a compile definition CBOR_NO_FLOATING_POINT. It seems that floating point support is only needed in src/cborpretty.c to use functions from the math.h header, which are not available in Zephyr. --- CMakeLists.txt | 1 + deps/tinycbor | 2 +- deps/tinycbor.cmake | 4 +++- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 675ec37f2a..109732bbaf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -195,6 +195,7 @@ elseif(DEFINED ZEPHYR_BASE) # Taken from zephyr/cmake/extensions.cmake: zephyr_get_compile_definitions_for_lang(C definitions) get_property(zephyr_compile_defs TARGET zephyr_interface PROPERTY INTERFACE_COMPILE_DEFINITIONS) list(APPEND PRIVATE_COMPILE_DEFINITIONS ${zephyr_compile_defs}) + list(APPEND PRIVATE_COMPILE_DEFINITIONS CBOR_NO_FLOATING_POINT) # Add Zephyr compile options. # Taken from zephyr/cmake/extensions.cmake: zephyr_get_compile_options_for_lang(C options) diff --git a/deps/tinycbor b/deps/tinycbor index 70aba6ba51..d393c16f3e 160000 --- a/deps/tinycbor +++ b/deps/tinycbor @@ -1 +1 @@ -Subproject commit 70aba6ba51881e5b8d108c105a17ed9cdee6bc30 +Subproject commit d393c16f3eb30d0c47e6f9d92db62272f0ec4dc7 diff --git a/deps/tinycbor.cmake b/deps/tinycbor.cmake index 19da7fae1c..4098f16769 100755 --- a/deps/tinycbor.cmake +++ b/deps/tinycbor.cmake @@ -2,7 +2,9 @@ add_library(tinycbor-master OBJECT ${PROJECT_SOURCE_DIR}/deps/tinycbor/src/cborerrorstrings.c ${PROJECT_SOURCE_DIR}/deps/tinycbor/src/cborencoder.c ${PROJECT_SOURCE_DIR}/deps/tinycbor/src/cborencoder_close_container_checked.c + ${PROJECT_SOURCE_DIR}/deps/tinycbor/src/cborencoder_float.c ${PROJECT_SOURCE_DIR}/deps/tinycbor/src/cborparser.c + ${PROJECT_SOURCE_DIR}/deps/tinycbor/src/cborparser_float.c ${PROJECT_SOURCE_DIR}/deps/tinycbor/src/cborpretty.c ) @@ -10,7 +12,7 @@ target_include_directories(tinycbor-master PUBLIC ${PROJECT_SOURCE_DIR}/deps/tinycbor/src ) -target_compile_definitions(tinycbor-master PUBLIC ${PUBLIC_COMPILE_DEFINITIONS}) +target_compile_definitions(tinycbor-master PUBLIC ${PUBLIC_COMPILE_DEFINITIONS} PRIVATE ${PRIVATE_COMPILE_DEFINITIONS}) target_compile_options(tinycbor-master PRIVATE ${PRIVATE_COMPILE_OPTIONS}) add_dependencies(tinycbor-master ${TARGET_DEPENDENCIES}) From 2eb7a0d6facb83024371b0e22b61453505e5b701 Mon Sep 17 00:00:00 2001 From: Martin Roesch Date: Fri, 4 Mar 2022 17:28:41 +0100 Subject: [PATCH 07/30] Add missing include for strncasecmp --- api/oc_discovery.c | 1 + 1 file changed, 1 insertion(+) diff --git a/api/oc_discovery.c b/api/oc_discovery.c index 66791b72ee..0156c5a7f9 100644 --- a/api/oc_discovery.c +++ b/api/oc_discovery.c @@ -37,6 +37,7 @@ #include "oc_endpoint.h" #ifdef OC_SECURITY +#include #include "security/oc_pstat.h" #include "security/oc_sdi.h" #include "security/oc_tls.h" From 89078ece85c708f256d99e1d4f3860577d00e2a8 Mon Sep 17 00:00:00 2001 From: Martin Roesch Date: Fri, 4 Mar 2022 17:37:28 +0100 Subject: [PATCH 08/30] Remove unneeded wchar.h inclusion --- include/oc_introspection.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/include/oc_introspection.h b/include/oc_introspection.h index 9a793e4012..9ccc369aa4 100644 --- a/include/oc_introspection.h +++ b/include/oc_introspection.h @@ -50,8 +50,6 @@ #ifndef OC_INTROSPECTION_H #define OC_INTROSPECTION_H -#include - #include #include From 8f658cca14ca30206f4c51094854a5b61d9286a1 Mon Sep 17 00:00:00 2001 From: Martin Roesch Date: Fri, 4 Mar 2022 18:00:20 +0100 Subject: [PATCH 09/30] zephyr oc_config.h: Add switch for OC_DYNAMIC_ALLOCATION --- port/zephyr/src/oc_config.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/port/zephyr/src/oc_config.h b/port/zephyr/src/oc_config.h index 1da0a48205..a6ff42b9c9 100644 --- a/port/zephyr/src/oc_config.h +++ b/port/zephyr/src/oc_config.h @@ -30,7 +30,15 @@ typedef uint64_t oc_clock_time_t; /* Server-side parameters */ /* Maximum number of server resources */ #define OC_MAX_APP_RESOURCES (1) +#ifdef OC_DYNAMIC_ALLOCATION +#define OC_COLLECTIONS +#define OC_BLOCK_WISE +/* Enable reallocation during encoding the representation to cbor or run "make" + * with REP_ENCODING_REALLOC=1 */ +//#define OC_REP_ENCODING_REALLOC + +#else /* OC_DYNAMIC_ALLOCATION */ /* Common parameters */ //#define OC_BLOCK_WISE_SET_MTU (80) @@ -58,6 +66,8 @@ typedef uint64_t oc_clock_time_t; /* Maximum number of concurrent DTLS sessions */ #define OC_MAX_DTLS_PEERS (1) +#endif /* !OC_DYNAMIC_ALLOCATION */ + /* Max inactivity timeout before tearing down DTLS connection */ #define OC_DTLS_INACTIVITY_TIMEOUT (10) From e3899b08bf4a981e03b1ef522d39312792d29409 Mon Sep 17 00:00:00 2001 From: Martin Roesch Date: Fri, 4 Mar 2022 18:01:10 +0100 Subject: [PATCH 10/30] zephyr clock.c: Fix k_sleep arguments --- port/zephyr/src/clock.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/port/zephyr/src/clock.c b/port/zephyr/src/clock.c index edae98a912..d3565427a3 100644 --- a/port/zephyr/src/clock.c +++ b/port/zephyr/src/clock.c @@ -36,5 +36,7 @@ oc_clock_seconds(void) void oc_clock_wait(oc_clock_time_t t) { - k_sleep(t); + k_timeout_t kt; + kt.ticks = t; + k_sleep(kt); } From 8067b203b5b4d0e72df21acf0ca33f58ded09b88 Mon Sep 17 00:00:00 2001 From: Martin Roesch Date: Tue, 8 Mar 2022 10:44:43 +0100 Subject: [PATCH 11/30] oc_obt.c: Disable support for float data type if it's disabled in TinyCBOR The Zephyr minimal libc doesn't provide a strtod function implementation. --- security/oc_obt.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/security/oc_obt.c b/security/oc_obt.c index 37ed218406..1b69627902 100644 --- a/security/oc_obt.c +++ b/security/oc_obt.c @@ -3523,11 +3523,15 @@ oc_obt_general_post(oc_uuid_t *uuid, char *query, const char *url, strlen(payload_properties[i])); oc_rep_encode_int(&root_map, payload_int); } else if (strstr(payload_types[i], "float") != NULL) { +#ifndef CBOR_NO_FLOATING_POINT double payload_double = strtod(payload_values[i], NULL); oc_rep_encode_text_string(&root_map, payload_properties[i], strlen(payload_properties[i])); oc_rep_encode_double(&root_map, payload_double); +#else + PRINT("Device does not support float data type.\n"); +#endif } else if (strstr(payload_types[i], "str") != NULL) { oc_rep_encode_text_string(&root_map, payload_properties[i], strlen(payload_properties[i])); From 1923c7f5fddf97c5cdc4f3a769a1689622779633 Mon Sep 17 00:00:00 2001 From: Martin Roesch Date: Tue, 8 Mar 2022 15:40:33 +0100 Subject: [PATCH 12/30] Move raw flash storage implementation to storage_flash.c --- port/zephyr/src/{storage.c => storage_flash.c} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename port/zephyr/src/{storage.c => storage_flash.c} (100%) diff --git a/port/zephyr/src/storage.c b/port/zephyr/src/storage_flash.c similarity index 100% rename from port/zephyr/src/storage.c rename to port/zephyr/src/storage_flash.c From 9dc8246f8690b6059c2df967fd016f5af4e62403 Mon Sep 17 00:00:00 2001 From: Martin Roesch Date: Tue, 8 Mar 2022 16:16:40 +0100 Subject: [PATCH 13/30] Add storage implementation using the Zephyr file-system API --- port/zephyr/src/storage_fs.c | 115 +++++++++++++++++++++++++++++++++++ 1 file changed, 115 insertions(+) create mode 100644 port/zephyr/src/storage_fs.c diff --git a/port/zephyr/src/storage_fs.c b/port/zephyr/src/storage_fs.c new file mode 100644 index 0000000000..3b4a36c75a --- /dev/null +++ b/port/zephyr/src/storage_fs.c @@ -0,0 +1,115 @@ +/* +// Copyright (c) 2022 Kistler Instruments AG, Winterthur, Switzerland +// +// 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 "port/oc_storage.h" +#include + +#ifdef OC_STORAGE +#include +LOG_MODULE_REGISTER(oc_storage, LOG_LEVEL_DBG); +#include +#include +#include +#include + +#define STORE_PATH_SIZE 64 + +static char store_path[STORE_PATH_SIZE]; +static int store_path_len; +static bool path_set = false; + +int +oc_storage_config(const char *store) +{ + LOG_DBG("oc_storage_config: %s", store_path); + store_path_len = strlen(store); + if (store_path_len >= STORE_PATH_SIZE) + return -ENOENT; + + memcpy(store_path, store, store_path_len); + store_path[store_path_len] = '\0'; + path_set = true; + return 0; +} + +long +oc_storage_read(const char *store, uint8_t *buf, size_t size) +{ + LOG_DBG("oc_storage_read: %s", store); + size_t store_len = strlen(store); + if (!path_set || (1 + store_len + store_path_len >= STORE_PATH_SIZE)) { + return -ENOENT; + } + + store_path[store_path_len] = '/'; + strncpy(store_path + store_path_len + 1, store, store_len); + store_path[1 + store_path_len + store_len] = '\0'; + + struct fs_file_t file; + fs_file_t_init(&file); + + int rc = fs_open(&file, store_path, FS_O_READ); + if (rc < 0) { + LOG_ERR("oc_storage_read: Cannot open %s: %d", store_path, rc); + return -EINVAL; + } + rc = fs_read(&file, buf, size); + if (rc < 0) { + LOG_ERR("oc_storage_read: Cannot read %s: %d", store_path, rc); + fs_close(&file); + return -EINVAL; + } + rc = fs_close(&file); + if (rc < 0) { + LOG_ERR("oc_storage_read: Cannot close %s: %d", store_path, rc); + } + return size; +} + +long +oc_storage_write(const char *store, uint8_t *buf, size_t size) +{ + LOG_DBG("oc_storage_read: %s", store); + size_t store_len = strlen(store); + if (!path_set || (1 + store_len + store_path_len >= STORE_PATH_SIZE)) { + return -ENOENT; + } + + store_path[store_path_len] = '/'; + strncpy(store_path + store_path_len + 1, store, store_len); + store_path[1 + store_path_len + store_len] = '\0'; + + struct fs_file_t file; + fs_file_t_init(&file); + + int rc = fs_open(&file, store_path, FS_O_CREATE | FS_O_RDWR); + if (rc < 0) { + LOG_ERR("oc_storage_read: Cannot open %s: %d", store_path, rc); + return -EINVAL; + } + rc = fs_write(&file, buf, size); + if (rc < 0) { + LOG_ERR("oc_storage_read: Cannot write %s: %d", store_path, rc); + fs_close(&file); + return -EINVAL; + } + rc = fs_close(&file); + if (rc < 0) { + LOG_ERR("oc_storage_read: Cannot close %s: %d", store_path, rc); + } + return size; +} +#endif /* OC_STORAGE */ From fe4d6d9b261a3e53c806c0ff5cb0779528372cdd Mon Sep 17 00:00:00 2001 From: Martin Roesch Date: Tue, 8 Mar 2022 16:18:20 +0100 Subject: [PATCH 14/30] Determine storage implementation based on Zephyr configuration --- CMakeLists.txt | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 109732bbaf..5fe1b192be 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -202,7 +202,16 @@ elseif(DEFINED ZEPHYR_BASE) get_property(zephyr_compile_opts TARGET zephyr_interface PROPERTY INTERFACE_COMPILE_OPTIONS) list(APPEND PRIVATE_COMPILE_OPTIONS ${zephyr_compile_opts}) - file(GLOB PORT_SRC port/zephyr/src/*.c) + file(GLOB PORT_SRC port/zephyr/src/[a-r]*.c) + if(CONFIG_FILE_SYSTEM) + message(STATUS "Using file system storage.") + list(APPEND PORT_SRC port/zephyr/src/storage_fs.c) + elseif(CONFIG_FLASH) + message(STATUS "Using raw flash storage.") + list(APPEND PORT_SRC port/zephyr/src/storage_flash.c) + else() + message(FATAL_ERROR "Cannot determine the storage technology to use!") + endif() set(PORT_INCLUDE_DIR ${PROJECT_SOURCE_DIR}/port/zephyr/src) else() message(FATAL_ERROR "Cannot determine the port to use!") From a1f9d7619dc6bf4418e598960221b92d9e7c7490 Mon Sep 17 00:00:00 2001 From: Martin Roesch Date: Tue, 8 Mar 2022 16:41:40 +0100 Subject: [PATCH 15/30] zephyr oc_config.h: Add definition for OC_MULTICAST_RESPONSE_JITTER_MS --- port/zephyr/src/oc_config.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/port/zephyr/src/oc_config.h b/port/zephyr/src/oc_config.h index a6ff42b9c9..5c6d286ddf 100644 --- a/port/zephyr/src/oc_config.h +++ b/port/zephyr/src/oc_config.h @@ -68,6 +68,9 @@ typedef uint64_t oc_clock_time_t; #endif /* !OC_DYNAMIC_ALLOCATION */ +/* jitter added to response to some multicast requests */ +#define OC_MULTICAST_RESPONSE_JITTER_MS (2000) + /* Max inactivity timeout before tearing down DTLS connection */ #define OC_DTLS_INACTIVITY_TIMEOUT (10) From ba011a50bd4504c4f6526ecd4540679478533ad5 Mon Sep 17 00:00:00 2001 From: Martin Roesch Date: Wed, 9 Mar 2022 09:13:08 +0100 Subject: [PATCH 16/30] oc_helpers: Exclude functions only used by oscore. Those functions use the sscanf function, which is not implemented in the minimal libc of Zephyr. --- api/oc_helpers.c | 2 ++ include/oc_helpers.h | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/api/oc_helpers.c b/api/oc_helpers.c index 930698ad2d..677444dcea 100644 --- a/api/oc_helpers.c +++ b/api/oc_helpers.c @@ -258,6 +258,7 @@ oc_join_string_array(oc_string_array_t *ocstringarray, oc_string_t *ocstring) strcpy((char *)oc_string(*ocstring) + len, ""); } +#ifdef OC_OSCORE int oc_conv_byte_array_to_hex_string(const uint8_t *array, size_t array_len, char *hex_str, size_t *hex_str_len) @@ -315,3 +316,4 @@ oc_conv_hex_string_to_byte_array(const char *hex_str, size_t hex_str_len, return 0; } +#endif /* OC_OSCORE */ diff --git a/include/oc_helpers.h b/include/oc_helpers.h index dcb739a828..0ca70d3c14 100644 --- a/include/oc_helpers.h +++ b/include/oc_helpers.h @@ -279,6 +279,7 @@ void _oc_alloc_string_array( #endif oc_string_array_t *ocstringarray, size_t size); +#ifdef OC_OSCORE /** Conversions between hex encoded strings and byte arrays */ /** @@ -304,7 +305,7 @@ int oc_conv_byte_array_to_hex_string(const uint8_t *array, size_t array_len, */ int oc_conv_hex_string_to_byte_array(const char *hex_str, size_t hex_str_len, uint8_t *array, size_t *array_len); - +#endif /* OC_OSCORE */ #ifdef __cplusplus } #endif From 3706fbf6168a02b6b026640aa2868434c317dda1 Mon Sep 17 00:00:00 2001 From: Martin Roesch Date: Mon, 14 Mar 2022 14:36:28 +0100 Subject: [PATCH 17/30] Zephyr oc_storage_config: Fix debug message. --- port/zephyr/src/storage_fs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/port/zephyr/src/storage_fs.c b/port/zephyr/src/storage_fs.c index 3b4a36c75a..28341b9d7a 100644 --- a/port/zephyr/src/storage_fs.c +++ b/port/zephyr/src/storage_fs.c @@ -34,7 +34,7 @@ static bool path_set = false; int oc_storage_config(const char *store) { - LOG_DBG("oc_storage_config: %s", store_path); + LOG_DBG("oc_storage_config: %s", store); store_path_len = strlen(store); if (store_path_len >= STORE_PATH_SIZE) return -ENOENT; From 6f976165fa289e486cc457cea84e385d5a61ce89 Mon Sep 17 00:00:00 2001 From: Martin Roesch Date: Tue, 15 Mar 2022 10:08:03 +0100 Subject: [PATCH 18/30] zephyr oc_config.h: Add definition for OC_NETWORK_MONITOR --- port/zephyr/src/oc_config.h | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/port/zephyr/src/oc_config.h b/port/zephyr/src/oc_config.h index 5c6d286ddf..c78755185f 100644 --- a/port/zephyr/src/oc_config.h +++ b/port/zephyr/src/oc_config.h @@ -27,9 +27,26 @@ typedef uint64_t oc_clock_time_t; #define OC_INTS_POOL_SIZE (16) #define OC_DOUBLES_POOL_SIZE (16) +/* jitter added to response to some multicast requests */ +#define OC_MULTICAST_RESPONSE_JITTER_MS (2000) + +/* Max inactivity timeout before tearing down DTLS connection */ +#define OC_DTLS_INACTIVITY_TIMEOUT (10) + +/* Add support for passing network up/down events to the app */ +#define OC_NETWORK_MONITOR +/* Add support for passing TCP/TLS/DTLS session connection events to the app */ +#define OC_SESSION_EVENTS +/* Add request history for deduplicate UDP/DTLS messages */ +#define OC_REQUEST_HISTORY + +/* Add support observable for oic/res */ +//#define OC_DISCOVERY_RESOURCE_OBSERVABLE + /* Server-side parameters */ /* Maximum number of server resources */ #define OC_MAX_APP_RESOURCES (1) + #ifdef OC_DYNAMIC_ALLOCATION #define OC_COLLECTIONS #define OC_BLOCK_WISE @@ -68,18 +85,6 @@ typedef uint64_t oc_clock_time_t; #endif /* !OC_DYNAMIC_ALLOCATION */ -/* jitter added to response to some multicast requests */ -#define OC_MULTICAST_RESPONSE_JITTER_MS (2000) - -/* Max inactivity timeout before tearing down DTLS connection */ -#define OC_DTLS_INACTIVITY_TIMEOUT (10) - -/* Add request history for deduplicate UDP/DTLS messages */ -#define OC_REQUEST_HISTORY - -/* Add support observable for oic/res */ -//#define OC_DISCOVERY_RESOURCE_OBSERVABLE - /* library features that require persistent storage */ #ifdef OC_SECURITY #define OC_STORAGE From 0876d7807a88f5a203218c9bf7439dd465f3d765 Mon Sep 17 00:00:00 2001 From: Martin Roesch Date: Tue, 15 Mar 2022 10:24:09 +0100 Subject: [PATCH 19/30] Add include dirs from net/ip subsystem --- CMakeLists.txt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5fe1b192be..9fb6b7f5f4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -189,7 +189,11 @@ elseif(DEFINED ZEPHYR_BASE) # Set the Zephyr include directories globally. # Taken from zephyr/cmake/extensions.cmake: zephyr_get_include_directories_for_lang(C includes) get_property(zephyr_include_dirs TARGET zephyr_interface PROPERTY INTERFACE_INCLUDE_DIRECTORIES) - include_directories(${zephyr_include_dirs}) + get_property(posix_subsys_include_dirs TARGET posix_subsys PROPERTY INTERFACE_INCLUDE_DIRECTORIES) + # The Zephyr IP subsystem provides helper functions for IPv6 multicast functions in the + # subsys/net/ip/ipv6.h header file. But this header file is not provided by any Zephyr CMake target. + set(net_ip_subsys_include_dirs ${ZEPHYR_BASE}/subsys/net/ip) + include_directories(${zephyr_include_dirs} ${posix_subsys_include_dirs} ${net_ip_subsys_include_dirs}) # Add Zephyr compile definitions. # Taken from zephyr/cmake/extensions.cmake: zephyr_get_compile_definitions_for_lang(C definitions) From a506e431996392ce679721733d520011893e33b1 Mon Sep 17 00:00:00 2001 From: Martin Roesch Date: Tue, 15 Mar 2022 10:28:19 +0100 Subject: [PATCH 20/30] Port Linux ipadapter implementation to Zephyr * Replace netlink sockets with Zephyr network manager * Replace shutdown_pipe pipe with a Zephyr socketpair * Use Zephyr functions for multicast address and group management --- port/zephyr/src/ipadapter.c | 1654 ++++++++++++++++++++++++++++++----- port/zephyr/src/ipadapter.h | 23 + port/zephyr/src/ipcontext.h | 138 +++ 3 files changed, 1572 insertions(+), 243 deletions(-) create mode 100644 port/zephyr/src/ipadapter.h create mode 100644 port/zephyr/src/ipcontext.h diff --git a/port/zephyr/src/ipadapter.c b/port/zephyr/src/ipadapter.c index 57ea520dd2..6404c0a7ae 100644 --- a/port/zephyr/src/ipadapter.c +++ b/port/zephyr/src/ipadapter.c @@ -1,5 +1,6 @@ /* // Copyright (c) 2016 Intel Corporation +// Copyright (c) 2022 Kistler Instruments // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -13,370 +14,1537 @@ // See the License for the specific language governing permissions and // limitations under the License. */ - +#include +LOG_MODULE_REGISTER(oc_ipadapter, LOG_LEVEL_DBG); +#define _GNU_SOURCE +#include "ipadapter.h" +#include "ipcontext.h" +#include "oc_config.h" +#ifdef OC_TCP +#include "tcpadapter.h" +#endif #include "oc_buffer.h" +#include "oc_core_res.h" #include "oc_endpoint.h" +#include "oc_network_monitor.h" +#include "port/oc_assert.h" #include "port/oc_connectivity.h" +#include "util/oc_atomic.h" +#include +#include #include +#include +#include +#include "ipv6.h" +#include +#include +#include #include -#include - -#include -#include -#include -#include - -/* Server's receive socket */ -static struct net_context *udp_recv6; - -/* "All OCF nodes" multicast address and port */ -#define OCF_MCAST_IP6ADDR \ - { \ - { \ - { \ - 0xff, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x01, 0x58 \ - } \ - } \ - } -static struct in6_addr in6addr_mcast = OCF_MCAST_IP6ADDR; -#define OCF_MCAST_PORT (5683) -/* Multicast receive socket */ -static struct net_context *mcast_recv6; -static struct sockaddr_in6 mcast_addr6; -static struct sockaddr_in6 my_addr6; - -static struct in6_addr in6addr_my; +#include +#include +#include -#ifdef OC_SECURITY -/* DTLS receive socket */ -static struct net_context *dtls_recv6; -static struct sockaddr_in6 dtls_addr6; -#define MY_DTLS_PORT (56789) -#endif /* OC_SECURITY */ -static oc_endpoint_t *eps; -/* For synchronizing the network receive thread with IoTivity-Lite's - * event loop. +#define OCF_PORT_UNSECURED (5683) +static const uint8_t ALL_OCF_NODES_LL[] = { + 0xff, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x01, 0x58 +}; +static const uint8_t ALL_OCF_NODES_RL[] = { + 0xff, 0x03, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x01, 0x58 +}; +static const uint8_t ALL_OCF_NODES_SL[] = { + 0xff, 0x05, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x01, 0x58 +}; + +#ifdef OC_WKCORE +static const uint8_t ALL_COAP_NODES_LL[] = { 0xff, 0x02, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0xFD }; +static const uint8_t ALL_COAP_NODES_RL[] = { 0xff, 0x03, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0xFD }; +static const uint8_t ALL_COAP_NODES_SL[] = { 0xff, 0x05, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0xFD }; +#endif + +#define ALL_COAP_NODES_V4 0xe00001bb + +#define NETWORK_THREAD_STACKSIZE (1024 + CONFIG_TEST_EXTRA_STACKSIZE) +static pthread_attr_t oc_network_thread_attr; +K_THREAD_STACK_DEFINE(oc_network_thread_stack, NETWORK_THREAD_STACKSIZE); +static pthread_mutex_t oc_network_mutex; +static struct net_mgmt_event_callback net_mgmt_event_if_cb; +bool ifchange_initialized; + +OC_LIST(ip_contexts); +OC_MEMB(ip_context_s, ip_context_t, OC_MAX_NUM_DEVICES); + +OC_MEMB(device_eps, oc_endpoint_t, 8 * OC_MAX_NUM_DEVICES); // fix + +#ifdef OC_NETWORK_MONITOR +/** + * Structure to manage interface list. */ -static struct k_sem sem; +typedef struct ip_interface +{ + struct ip_interface *next; + int if_index; +} ip_interface_t; + +OC_LIST(ip_interface_list); +OC_MEMB(ip_interface_s, ip_interface_t, OC_MAX_IP_INTERFACES); + +OC_LIST(oc_network_interface_cb_list); +OC_MEMB(oc_network_interface_cb_s, oc_network_interface_cb_t, + OC_MAX_NETWORK_INTERFACE_CBS); + +static ip_interface_t * +get_ip_interface(int target_index) +{ + ip_interface_t *if_item = oc_list_head(ip_interface_list); + while (if_item != NULL && if_item->if_index != target_index) { + if_item = if_item->next; + } + return if_item; +} + +static bool +add_ip_interface(int target_index) +{ + if (get_ip_interface(target_index)) + return false; + + ip_interface_t *new_if = oc_memb_alloc(&ip_interface_s); + if (!new_if) { + OC_ERR("Failed to allocate memory for ip interface list item"); + return false; + } + new_if->if_index = target_index; + oc_list_add(ip_interface_list, new_if); + OC_DBG("Added to ip interface list: %d", new_if->if_index); + return true; +} + +static void +check_new_ip_interfaces_cb(struct net_if *iface, void *user_data) +{ + add_ip_interface(net_if_get_by_iface(iface)); +} + +static bool +check_new_ip_interfaces(void) +{ + net_if_foreach(&check_new_ip_interfaces_cb, NULL); + return true; +} + +static bool +remove_ip_interface(int target_index) +{ + ip_interface_t *if_item = get_ip_interface(target_index); + if (!if_item) { + return false; + } + + oc_list_remove(ip_interface_list, if_item); + oc_memb_free(&ip_interface_s, if_item); + OC_DBG("Removed from ip interface list: %d", target_index); + return true; +} + +static void +remove_all_ip_interface(void) +{ + ip_interface_t *if_item = oc_list_head(ip_interface_list), *next; + while (if_item != NULL) { + next = if_item->next; + oc_list_remove(ip_interface_list, if_item); + oc_memb_free(&ip_interface_s, if_item); + if_item = next; + } +} + +static void +remove_all_network_interface_cbs(void) +{ + oc_network_interface_cb_t *cb_item = + oc_list_head(oc_network_interface_cb_list), + *next; + while (cb_item != NULL) { + next = cb_item->next; + oc_list_remove(oc_network_interface_cb_list, cb_item); + oc_memb_free(&oc_network_interface_cb_s, cb_item); + cb_item = next; + } +} +#endif /* OC_NETWORK_MONITOR */ + +#ifdef OC_SESSION_EVENTS +OC_LIST(oc_session_event_cb_list); +OC_MEMB(oc_session_event_cb_s, oc_session_event_cb_t, OC_MAX_SESSION_EVENT_CBS); + +static void +remove_all_session_event_cbs(void) +{ + oc_session_event_cb_t *cb_item = oc_list_head(oc_session_event_cb_list), + *next; + while (cb_item != NULL) { + next = cb_item->next; + oc_list_remove(oc_session_event_cb_list, cb_item); + oc_memb_free(&oc_session_event_cb_s, cb_item); + cb_item = next; + } +} + +#endif /* OC_SESSION_EVENTS */ void oc_network_event_handler_mutex_init(void) { - k_sem_init(&sem, 0, 1); - k_sem_give(&sem); + if (pthread_mutex_init(&oc_network_mutex, NULL) != 0) { + oc_abort("error initializing network event handler mutex"); + } } void oc_network_event_handler_mutex_lock(void) { - k_sem_take(&sem, K_FOREVER); + pthread_mutex_lock(&oc_network_mutex); } void oc_network_event_handler_mutex_unlock(void) { - k_sem_give(&sem); + pthread_mutex_unlock(&oc_network_mutex); } void oc_network_event_handler_mutex_destroy(void) { + ifchange_initialized = false; +#ifdef OC_NETWORK_MONITOR + remove_all_ip_interface(); + remove_all_network_interface_cbs(); +#endif /* OC_NETWORK_MONITOR */ +#ifdef OC_SESSION_EVENTS + remove_all_session_event_cbs(); +#endif /* OC_SESSION_EVENTS */ + pthread_mutex_destroy(&oc_network_mutex); +} + +static ip_context_t * +get_ip_context_for_device(size_t device) +{ + ip_context_t *dev = oc_list_head(ip_contexts); + while (dev != NULL && dev->device != device) { + dev = dev->next; + } + if (!dev) { + return NULL; + } + return dev; +} + +#ifdef OC_IPV4 +static int +net_if_manage_ipv4_mcast_group(struct net_if *iface) +{ + struct in_addr addr; + addr.s_addr = htonl(ALL_COAP_NODES_V4); + struct net_if_mcast_addr *mcast_addr = net_if_ipv4_maddr_lookup(&addr, &iface); + if(mcast_addr == NULL) { + OC_DBG("Add IPv4 multicast address on interface with index %d", net_if_get_by_iface(iface)); + mcast_addr = net_if_ipv4_maddr_add(iface, &addr); + if(mcast_addr == NULL) { + OC_ERR("Failed to add IPv4 multicast address"); + return -1; + } + } + if(!net_if_ipv4_maddr_is_joined(mcast_addr)) { + OC_DBG("Join IPv4 multicast address on interface with index %d", net_if_get_by_iface(iface)); + net_if_ipv4_maddr_join(mcast_addr); + } + return 0; +} +#endif /* OC_IPV4 */ + +static int +net_if_manage_ipv6_mcast_group(struct net_if *iface) +{ + /* Link-local scope */ + struct in6_addr addr; + memcpy(addr.s6_addr, ALL_OCF_NODES_LL, 16); +// struct net_if_mcast_addr *mcast_addr = net_if_ipv6_maddr_lookup(&addr, &iface); +// if(mcast_addr == NULL) +// { +// OC_ERR("No link-local multicast address on interface with index %d", net_if_get_by_iface(iface)); +// return -1; +// } +// net_if_ipv6_maddr_join(mcast_addr); + int ret = net_ipv6_mld_join(iface, &addr); + if (ret == -EALREADY) + { + return 0; + } + else if (ret < 0) + { + OC_ERR("Cannot join link-local IPv6 multicast group (%d)", ret); + return -1; + } + + /* Realm-local scope */ + memcpy(addr.s6_addr, ALL_OCF_NODES_RL, 16); +// mcast_addr = net_if_ipv6_maddr_lookup(&addr, &iface); +// if(mcast_addr == NULL) +// { +// OC_ERR("No realm-local multicast address on interface with index %d", net_if_get_by_iface(iface)); +// return -1; +// } +// net_if_ipv6_maddr_join(mcast_addr); + ret = net_ipv6_mld_join(iface, &addr); + if (ret == -EALREADY) + { + return 0; + } + else if (ret < 0) + { + OC_ERR("Cannot join realm-local IPv6 multicast group (%d)", ret); + return -1; + } + + /* Site-local scope */ + memcpy(addr.s6_addr, ALL_OCF_NODES_SL, 16); +// mcast_addr = net_if_ipv6_maddr_lookup(&addr, &iface); +// if(mcast_addr == NULL) +// { +// OC_ERR("No site-local multicast address on interface with index %d", net_if_get_by_iface(iface)); +// return -1; +// } +// net_if_ipv6_maddr_join(mcast_addr); + ret = net_ipv6_mld_join(iface, &addr); + if (ret == -EALREADY) + { + return 0; + } + else if (ret < 0) + { + OC_ERR("Cannot join site-local IPv6 multicast group (%d)", ret); + return -1; + } + return 0; } static void -oc_network_receive(struct net_context *context, struct net_pkt *pkt, int status, - void *user_data) -{ - oc_message_t *message = oc_allocate_message(); - - if (message) { - uint16_t pos; - struct net_udp_hdr *udp = - (struct net_udp_hdr *)((u8_t *)(NET_IPV6_HDR(pkt)) + - sizeof(struct net_ipv6_hdr)); - size_t bytes_read = net_pkt_appdatalen(pkt); - if (bytes_read < 0) { - oc_message_unref(message); +configure_mcast_socket_net_if(struct net_if *iface, void *user_data) +{ + int sa_family = *(int*)user_data; + /* Ignore interfaces that are down */ + if (!net_if_is_up(iface)) { + return; + } + /* Ignore interfaces not belonging to the address family under consideration + */ + if(sa_family == AF_INET6) { + net_if_manage_ipv6_mcast_group(iface); + } +#ifdef OC_IPV4 + else if (sa_family == AF_INET) { + net_if_manage_ipv4_mcast_group(iface); + } +#endif +} + +static int +configure_mcast_socket(int mcast_sock, int sa_family) +{ + net_if_foreach(&configure_mcast_socket_net_if, &sa_family); + return 0; +} + +struct get_interface_addresses_params { + ip_context_t *dev; + unsigned char family; + uint16_t port; + bool secure; + bool tcp; +}; + +static void +get_interface_addresses_net_if(struct net_if *iface, void *user_data) +{ + struct get_interface_addresses_params *params = user_data; + oc_endpoint_t ep = { 0 }; + ep.interface_index = net_if_get_by_iface(iface); + /* Ignore interfaces that are down */ + if (!net_if_is_up(iface)) { + OC_DBG("Interface %d is down", ep.interface_index); + return; + } + + if (params->secure) { + ep.flags |= SECURED; + } +#ifdef OC_IPV4 + if (params->family == AF_INET) { + ep.addr.ipv4.port = params->port; + } else +#endif /* OC_IPV4 */ + if (params->family == AF_INET6) { + ep.addr.ipv6.port = params->port; + } +#ifdef OC_TCP + if (params->tcp) { + ep.flags |= TCP; + } +#endif /* OC_TCP */ + if (params->family == AF_INET6) { + ep.flags |= IPV6; + struct net_if_ipv6 *ipv6; + if (net_if_config_ipv6_get(iface, &ipv6) < 0) { + OC_ERR("net_if_config_ipv6_get for interface %d failed", + ep.interface_index); return; } - - size_t offset_from_start = net_pkt_get_len(pkt) - bytes_read; - bytes_read = (bytes_read < OC_PDU_SIZE) ? bytes_read : OC_PDU_SIZE; - struct net_buf *frag = net_frag_read(pkt->frags, offset_from_start, &pos, - bytes_read, message->data); - if (!frag && pos == 0xffff) { - net_pkt_unref(pkt); - oc_message_unref(message); + for (int i = 0; i < NET_IF_MAX_IPV6_ADDR; i++) { + if (!ipv6->unicast[i].is_used || ipv6->unicast[i].address.family != AF_INET6) { + continue; + } + if (net_ipv6_is_addr_unspecified(&(ipv6->unicast[i].address.in6_addr)) || + net_ipv6_is_addr_loopback(&(ipv6->unicast[i].address.in6_addr))) { + continue; + } + memcpy(ep.addr.ipv6.address, ipv6->unicast[i].address.in6_addr.s6_addr, 16); + ep.addr.ipv6.scope = ipv6->unicast[i].address.in6_addr.s6_addr[1]; + oc_endpoint_t *new_ep = oc_memb_alloc(&device_eps); + if (!new_ep) { + return; + } + memcpy(new_ep, &ep, sizeof(oc_endpoint_t)); +#ifdef OC_DEBUG + char buf[IPADDR_BUFF_SIZE]; + SNPRINTFipaddr(buf, IPADDR_BUFF_SIZE, ep); + OC_DBG("add endpoint: %s, family: %d, if index: %d, secure: %d, tcp: %d", + buf, (int)params->family, ep.interface_index, + (int)params->secure, (int)params->tcp); +#endif /* OC_DEBUG */ + oc_list_add(params->dev->eps, new_ep); + } + } +#ifdef OC_IPV4 + if (params->family == AF_INET) { + ep.flags |= IPV4; + struct net_if_ipv4 *ipv4; + if (net_if_config_ipv4_get(iface, &ipv4) < 0) { + OC_ERR("net_if_config_ipv6_get for interface %d failed", + ep.interface_index); return; } + for (int i = 0; i < NET_IF_MAX_IPV4_ADDR; i++) { + if (!ipv4->unicast[i].is_used || ipv4->unicast[i].address.family != AF_INET) { + continue; + } + if (net_ipv4_is_addr_unspecified(&(ipv4->unicast[i].address.in_addr)) || + net_ipv4_is_addr_loopback(&(ipv4->unicast[i].address.in_addr))) { + continue; + } + memcpy(ep.addr.ipv4.address, ipv4->unicast[i].address.in_addr.s4_addr, 4); + oc_endpoint_t *new_ep = oc_memb_alloc(&device_eps); + if (!new_ep) { + return; + } + memcpy(new_ep, &ep, sizeof(oc_endpoint_t)); +#ifdef OC_DEBUG + char buf[IPADDR_BUFF_SIZE]; + SNPRINTFipaddr(buf, IPADDR_BUFF_SIZE, ep); + OC_DBG("add endpoint: %s, family: %d, if index: %d, secure: %d, tcp: %d", + buf, (int)params->family, ep.interface_index, + (int)params->secure, (int)params->tcp); +#endif /* OC_DEBUG */ + oc_list_add(params->dev->eps, new_ep); + } + } +#endif /* OC_IPV4 */ +} - message->length = bytes_read; - if (user_data != NULL) { - message->endpoint.flags = IPV6 | SECURED; +static void +get_interface_addresses(ip_context_t *dev, unsigned char family, uint16_t port, + bool secure, bool tcp) +{ + struct get_interface_addresses_params params = { + .dev = dev, + .family = family, + .port = port, + .secure = secure, + .tcp = tcp + }; + net_if_foreach(&get_interface_addresses_net_if, ¶ms); +} + +static void +free_endpoints_list(ip_context_t *dev) +{ + oc_endpoint_t *ep = oc_list_pop(dev->eps); + + while (ep != NULL) { + oc_memb_free(&device_eps, ep); + ep = oc_list_pop(dev->eps); + } +} + +static void +refresh_endpoints_list(ip_context_t *dev) +{ + free_endpoints_list(dev); + + get_interface_addresses(dev, AF_INET6, dev->port, false, false); +#ifdef OC_SECURITY + get_interface_addresses(dev, AF_INET6, dev->dtls_port, true, false); +#endif /* OC_SECURITY */ +#ifdef OC_IPV4 + get_interface_addresses(dev, AF_INET, dev->port4, false, false); +#ifdef OC_SECURITY + get_interface_addresses(dev, AF_INET, dev->dtls4_port, true, false); +#endif /* OC_SECURITY */ +#endif /* OC_IPV4 */ + +#ifdef OC_TCP + get_interface_addresses(dev, AF_INET6, dev->tcp.port, false, true); +#ifdef OC_SECURITY + get_interface_addresses(dev, AF_INET6, dev->tcp.tls_port, true, true); +#endif /* OC_SECURITY */ +#ifdef OC_IPV4 + get_interface_addresses(dev, AF_INET, dev->tcp.port4, false, true); #ifdef OC_SECURITY - message->encrypted = 1; + get_interface_addresses(dev, AF_INET, dev->tcp.tls4_port, true, true); #endif /* OC_SECURITY */ - } else - message->endpoint.flags = IPV6; - memcpy(message->endpoint.addr.ipv6.address, &NET_IPV6_HDR(pkt)->src, 16); - message->endpoint.addr.ipv6.scope = 0; - message->endpoint.addr.ipv6.port = ntohs(udp->src_port); - message->endpoint.device = 0; - - OC_DBG("oc_network_receive: received %d bytes", (int)message->length); +#endif /* OC_IPV4 */ +#endif /* OC_TCP */ +} + +oc_endpoint_t * +oc_connectivity_get_endpoints(size_t device) +{ + ip_context_t *dev = get_ip_context_for_device(device); + + if (!dev) { + return NULL; + } + + bool refresh = false; + bool swapped = false; + int8_t expected = OC_ATOMIC_LOAD8(dev->flags); + while ((expected & IP_CONTEXT_FLAG_REFRESH_ENDPOINT_LIST) != 0) { + int8_t desired = expected & ~IP_CONTEXT_FLAG_REFRESH_ENDPOINT_LIST; + OC_ATOMIC_COMPARE_AND_SWAP8(dev->flags, expected, desired, swapped); + if (swapped) { + refresh = true; + break; + } + } + + if (refresh || oc_list_length(dev->eps) == 0) { + refresh_endpoints_list(dev); + } + + return oc_list_head(dev->eps); +} + +/* Called after network interface up/down events. + * This function reconfigures IPv6/v4 multicast sockets for + * all logical devices. + */ +static void +process_interface_change_event(struct net_if *iface, oc_interface_event_t event) +{ + int num_devices = oc_core_get_num_devices(); + + if (event == NETWORK_INTERFACE_UP) { +#ifdef OC_NETWORK_MONITOR + if (add_ip_interface(net_if_get_by_iface(iface))) { + oc_network_interface_event(event); + } +#endif /* OC_NETWORK_MONITOR */ + } else if (event == NETWORK_INTERFACE_DOWN) { +#ifdef OC_NETWORK_MONITOR + if (remove_ip_interface(net_if_get_by_iface(iface))) { + oc_network_interface_event(event); + } +#endif /* OC_NETWORK_MONITOR */ + } + + for (int i = 0; i < num_devices; i++) { + ip_context_t *dev = get_ip_context_for_device(i); + oc_network_event_handler_mutex_lock(); + refresh_endpoints_list(dev); + oc_network_event_handler_mutex_unlock(); + } +} + +static int +recv_msg(int sock, uint8_t *recv_buf, int recv_buf_size, + oc_endpoint_t *endpoint, bool multicast) +{ + struct sockaddr server_sockaddr; + socklen_t server_sockaddr_len; + server_sockaddr_len = sizeof(server_sockaddr); + int ret = zsock_getsockname(sock, &server_sockaddr, &server_sockaddr_len); + if (ret < 0) { + OC_ERR("getsockname() failed: %d", errno); + return -1; + } + struct sockaddr client_sockaddr; + socklen_t client_sockaddr_len; + client_sockaddr_len = sizeof(client_sockaddr); + + ret = recvfrom(sock, recv_buf, recv_buf_size, 0, &client_sockaddr, &client_sockaddr_len); + if (ret < 0) { + OC_ERR("recvfrom() failed: %d", errno); + return -1; + } + + if (client_sockaddr.sa_family == AF_INET6) { + /* Set source address of packet in endpoint structure */ + struct sockaddr_in6 *c6 = net_sin6(&client_sockaddr); + memcpy(endpoint->addr.ipv6.address, c6->sin6_addr.s6_addr, + sizeof(c6->sin6_addr.s6_addr)); + endpoint->addr.ipv6.scope = c6->sin6_scope_id; + endpoint->addr.ipv6.port = ntohs(c6->sin6_port); + /* Set receiving network interface index */ + struct net_if *iface; + struct net_if_addr* if_addr = net_if_ipv6_addr_lookup(&net_sin6(&server_sockaddr)->sin6_addr, &iface); + endpoint->interface_index = net_if_get_by_iface(iface); + /* For a unicast receiving socket, extract the interface address + * into the endpoint's addr_local attribute. + * This would be used to set the source address of a response that + * results from this message. + */ + if (!multicast) { + memcpy(endpoint->addr_local.ipv6.address, if_addr->address.in6_addr.s6_addr, 16); + } else { + memset(endpoint->addr_local.ipv6.address, 0, 16); + } + } +#ifdef OC_IPV4 + else if (client_sockaddr.sa_family == AF_INET) { + /* Set source address of packet in endpoint structure */ + struct sockaddr_in *c4 = net_sin(&client_sockaddr); + memcpy(endpoint->addr.ipv4.address, &c4->sin_addr.s_addr, + sizeof(c4->sin_addr.s_addr)); + endpoint->addr.ipv6.port = ntohs(c4->sin_port); + /* Set receiving network interface index */ + struct net_if *iface; + struct net_if_addr* if_addr = net_if_ipv4_addr_lookup(&net_sin(&server_sockaddr)->sin_addr, &iface); + endpoint->interface_index = net_if_get_by_iface(iface); + /* For a unicast receiving socket, extract the interface address + * into the endpoint's addr_local attribute. + * This would be used to set the source address of a response that + * results from this message. + */ + if (!multicast) { + memcpy(endpoint->addr_local.ipv4.address, &if_addr->address.in_addr.s_addr, 4); + } else { + memset(endpoint->addr_local.ipv4.address, 0, 4); + } + } +#endif /* OC_IPV4 */ + return ret; +} + +static void +oc_udp_add_socks_to_fd_set(ip_context_t *dev) +{ + FD_SET(dev->server_sock, &dev->rfds); + FD_SET(dev->mcast_sock, &dev->rfds); +#ifdef OC_SECURITY + FD_SET(dev->secure_sock, &dev->rfds); +#endif /* OC_SECURITY */ + +#ifdef OC_IPV4 + FD_SET(dev->server4_sock, &dev->rfds); + FD_SET(dev->mcast4_sock, &dev->rfds); +#ifdef OC_SECURITY + FD_SET(dev->secure4_sock, &dev->rfds); +#endif /* OC_SECURITY */ +#endif /* OC_IPV4 */ +} + +static adapter_receive_state_t +oc_udp_receive_message(ip_context_t *dev, fd_set *fds, oc_message_t *message) +{ + if (FD_ISSET(dev->server_sock, fds)) { + int count = recv_msg(dev->server_sock, message->data, OC_PDU_SIZE, + &message->endpoint, false); + if (count < 0) { + return ADAPTER_STATUS_ERROR; + } + message->length = (size_t)count; + message->endpoint.flags = IPV6; + FD_CLR(dev->server_sock, fds); + return ADAPTER_STATUS_RECEIVE; + } + + if (FD_ISSET(dev->mcast_sock, fds)) { + int count = recv_msg(dev->mcast_sock, message->data, OC_PDU_SIZE, + &message->endpoint, true); + if (count < 0) { + return ADAPTER_STATUS_ERROR; + } + message->length = (size_t)count; + message->endpoint.flags = IPV6 | MULTICAST; + FD_CLR(dev->mcast_sock, fds); + return ADAPTER_STATUS_RECEIVE; + } + +#ifdef OC_IPV4 + if (FD_ISSET(dev->server4_sock, fds)) { + int count = recv_msg(dev->server4_sock, message->data, OC_PDU_SIZE, + &message->endpoint, false); + if (count < 0) { + return ADAPTER_STATUS_ERROR; + } + message->length = (size_t)count; + message->endpoint.flags = IPV4; + FD_CLR(dev->server4_sock, fds); + return ADAPTER_STATUS_RECEIVE; + } + + if (FD_ISSET(dev->mcast4_sock, fds)) { + int count = recv_msg(dev->mcast4_sock, message->data, OC_PDU_SIZE, + &message->endpoint, true); + if (count < 0) { + return ADAPTER_STATUS_ERROR; + } + message->length = (size_t)count; + message->endpoint.flags = IPV4 | MULTICAST; + FD_CLR(dev->mcast4_sock, fds); + return ADAPTER_STATUS_RECEIVE; + } +#endif /* OC_IPV4 */ + +#ifdef OC_SECURITY + if (FD_ISSET(dev->secure_sock, fds)) { + int count = recv_msg(dev->secure_sock, message->data, OC_PDU_SIZE, + &message->endpoint, false); + if (count < 0) { + return ADAPTER_STATUS_ERROR; + } + message->length = (size_t)count; + message->endpoint.flags = IPV6 | SECURED; + message->encrypted = 1; + FD_CLR(dev->secure_sock, fds); + return ADAPTER_STATUS_RECEIVE; + } +#ifdef OC_IPV4 + if (FD_ISSET(dev->secure4_sock, fds)) { + int count = recv_msg(dev->secure4_sock, message->data, OC_PDU_SIZE, + &message->endpoint, false); + if (count < 0) { + return ADAPTER_STATUS_ERROR; + } + message->length = (size_t)count; + message->endpoint.flags = IPV4 | SECURED; + message->encrypted = 1; + FD_CLR(dev->secure4_sock, fds); + return ADAPTER_STATUS_RECEIVE; + } +#endif /* OC_IPV4 */ +#endif /* OC_SECURITY */ + + return ADAPTER_STATUS_NONE; +} + +static void * +network_event_thread(void *data) +{ + ip_context_t *dev = (ip_context_t *)data; + + fd_set setfds; + FD_ZERO(&dev->rfds); + FD_SET(dev->shutdown_pipe[0], &dev->rfds); + oc_udp_add_socks_to_fd_set(dev); +#ifdef OC_TCP + oc_tcp_add_socks_to_fd_set(dev); +#endif /* OC_TCP */ + + int i, n; + while (OC_ATOMIC_LOAD8(dev->terminate) != 1) { + setfds = ip_context_rfds_fd_copy(dev); + n = select(FD_SETSIZE, &setfds, NULL, NULL, NULL); + + if (FD_ISSET(dev->shutdown_pipe[0], &setfds)) { + char buf; + // write to pipe shall not block - so read the byte we wrote + if (read(dev->shutdown_pipe[0], &buf, 1) < 0) { + // intentionally left blank + } + } + + if (OC_ATOMIC_LOAD8(dev->terminate)) { + break; + } + + for (i = 0; i < n; i++) { + oc_message_t *message = oc_allocate_message(); + if (!message) { + OC_WRN("Failed to allocate message!"); + break; + } + + message->endpoint.device = dev->device; + + if (oc_udp_receive_message(dev, &setfds, message) == ADAPTER_STATUS_RECEIVE) { + goto common; + } +#ifdef OC_TCP + if (oc_tcp_receive_message(dev, &setfds, message) == ADAPTER_STATUS_RECEIVE) { + goto common; + } +#endif /* OC_TCP */ + + oc_message_unref(message); + continue; + + common: #ifdef OC_DEBUG - PRINT("oc_network_receive: incoming message from "); - PRINTipaddr(message->endpoint); - PRINT("\n\n"); + PRINT("Incoming message of size %zd bytes from ", message->length); + PRINTipaddr(message->endpoint); + PRINT("\n"); #endif /* OC_DEBUG */ - oc_network_event(message); + oc_network_event(message); + } } - - net_pkt_unref(pkt); + pthread_exit(NULL); + return NULL; } -static inline void -udp_sent(struct net_context *context, int status, void *token, void *user_data) +static int +send_msg(int sock, struct sockaddr *receiver, oc_message_t *message) { - if (!status) { - OC_DBG("oc_send_buffer: sent %d bytes", POINTER_TO_UINT(token)); - } else if (status < 0) { - OC_DBG("oc_send_buffer: failed: (%d)", status); + int bytes_sent = 0, x; + uint8_t *buf = message->data; + size_t remaining = message->length; + while (bytes_sent < (int)message->length) { + buf += bytes_sent; + remaining -= bytes_sent; + x = sendto(sock, buf, remaining, 0, receiver, sizeof(struct sockaddr)); + if (x < 0) { + OC_WRN("sendto() returned errno %d", errno); + break; + } + bytes_sent += x; } + OC_DBG("Sent %d bytes", bytes_sent); + + if (bytes_sent == 0) { + return -1; + } + + return bytes_sent; } int oc_send_buffer(oc_message_t *message) { #ifdef OC_DEBUG - PRINT("oc_send_buffer: outgoing message to "); + PRINT("Outgoing message of size %zd bytes to ", message->length); PRINTipaddr(message->endpoint); - PRINT("\n\n"); + PRINT("\n"); #endif /* OC_DEBUG */ - /* Populate destination address structure */ - struct sockaddr_in6 peer_addr; - memcpy(peer_addr.sin6_addr.in6_u.u6_addr8, - message->endpoint.addr.ipv6.address, 16); - peer_addr.sin6_family = AF_INET6; - peer_addr.sin6_port = htons(message->endpoint.addr.ipv6.port); + struct sockaddr receiver; + memset(&receiver, 0, sizeof(struct sockaddr)); +#ifdef OC_IPV4 + if (message->endpoint.flags & IPV4) { + struct sockaddr_in *r = (struct sockaddr_in *)&receiver; + memcpy(&r->sin_addr.s_addr, message->endpoint.addr.ipv4.address, + sizeof(r->sin_addr.s_addr)); + r->sin_family = AF_INET; + r->sin_port = htons(message->endpoint.addr.ipv4.port); + } else { +#else + { +#endif + struct sockaddr_in6 *r = net_sin6(&receiver); + memcpy(r->sin6_addr.s6_addr, message->endpoint.addr.ipv6.address, + sizeof(r->sin6_addr.s6_addr)); + r->sin6_family = AF_INET6; + r->sin6_port = htons(message->endpoint.addr.ipv6.port); + r->sin6_scope_id = message->endpoint.addr.ipv6.scope; + } + int send_sock = -1; + + ip_context_t *dev = get_ip_context_for_device(message->endpoint.device); + + if (!dev) { + return -1; + } + +#ifdef OC_TCP + if (message->endpoint.flags & TCP) { + return oc_tcp_send_buffer(dev, message, &receiver); + } +#endif /* OC_TCP */ - /* Network buffer to hold data to be sent */ - struct net_pkt *send_pkt; #ifdef OC_SECURITY if (message->endpoint.flags & SECURED) { - send_pkt = net_pkt_get_tx(dtls_recv6, K_NO_WAIT); +#ifdef OC_IPV4 + if (message->endpoint.flags & IPV4) { + send_sock = dev->secure4_sock; + } else { + send_sock = dev->secure_sock; + } +#else /* OC_IPV4 */ + send_sock = dev->secure_sock; +#endif /* !OC_IPV4 */ } else #endif /* OC_SECURITY */ +#ifdef OC_IPV4 + if (message->endpoint.flags & IPV4) { + send_sock = dev->server4_sock; + } else { + send_sock = dev->server_sock; + } +#else /* OC_IPV4 */ { - send_pkt = net_pkt_get_tx(udp_recv6, K_NO_WAIT); + send_sock = dev->server_sock; } - if (!send_pkt) { - OC_WRN("oc_send_buffer: cannot acquire send_pkt"); +#endif /* !OC_IPV4 */ + + return send_msg(send_sock, &receiver, message); +} + +#ifdef OC_CLIENT +void +oc_send_discovery_request(oc_message_t *message) +{ + // TODO: implement sending of multicast message + OC_ERR("Not implemented"); +} +#endif /* OC_CLIENT */ + +#ifdef OC_NETWORK_MONITOR +int +oc_add_network_interface_event_callback(interface_event_handler_t cb) +{ + if (!cb) + return -1; + + oc_network_interface_cb_t *cb_item = + oc_memb_alloc(&oc_network_interface_cb_s); + if (!cb_item) { + OC_ERR("Failed to allocate memory for network interface callback"); return -1; } - bool status = - net_pkt_append_all(send_pkt, message->length, message->data, K_NO_WAIT); - if (!status) { - OC_WRN("oc_send_buffer: cannot populate send_pkt"); + cb_item->handler = cb; + oc_list_add(oc_network_interface_cb_list, cb_item); + return 0; +} + +int +oc_remove_network_interface_event_callback(interface_event_handler_t cb) +{ + if (!cb) return -1; + + oc_network_interface_cb_t *cb_item = + oc_list_head(oc_network_interface_cb_list); + while (cb_item != NULL && cb_item->handler != cb) { + cb_item = cb_item->next; } + if (!cb_item) { + return -1; + } + oc_list_remove(oc_network_interface_cb_list, cb_item); - int ret = net_context_sendto( - send_pkt, (struct sockaddr *)&peer_addr, sizeof(struct sockaddr_in6), - udp_sent, 0, UINT_TO_POINTER(net_pkt_get_len(send_pkt)), NULL); - if (ret < 0) { - OC_WRN("oc_send_buffer: cannot send data to peer (%d)", ret); - net_pkt_unref(send_pkt); - return ret; + oc_memb_free(&oc_network_interface_cb_s, cb_item); + return 0; +} + +void +handle_network_interface_event_callback(oc_interface_event_t event) +{ + if (oc_list_length(oc_network_interface_cb_list) > 0) { + oc_network_interface_cb_t *cb_item = + oc_list_head(oc_network_interface_cb_list); + while (cb_item) { + cb_item->handler(event); + cb_item = cb_item->next; + } } - return message->length; } +#endif /* OC_NETWORK_MONITOR */ -static void -free_endpoints(void) +#ifdef OC_SESSION_EVENTS +int +oc_add_session_event_callback(session_event_handler_t cb) { - oc_endpoint_t *ep = eps, *next; - while (ep != NULL) { - next = ep->next; - oc_free_endpoint(ep); - ep = next; + if (!cb) + return -1; + + oc_session_event_cb_t *cb_item = oc_memb_alloc(&oc_session_event_cb_s); + if (!cb_item) { + OC_ERR("Failed to allocate memory for session event callback"); + return -1; } + + cb_item->handler = cb; + oc_list_add(oc_session_event_cb_list, cb_item); + return 0; } -oc_endpoint_t * -oc_connectivity_get_endpoints(size_t device) +int +oc_remove_session_event_callback(session_event_handler_t cb) +{ + if (!cb) + return -1; + + oc_session_event_cb_t *cb_item = oc_list_head(oc_session_event_cb_list); + while (cb_item != NULL && cb_item->handler != cb) { + cb_item = cb_item->next; + } + if (!cb_item) { + return -1; + } + oc_list_remove(oc_session_event_cb_list, cb_item); + + oc_memb_free(&oc_session_event_cb_s, cb_item); + return 0; +} + +void +handle_session_event_callback(const oc_endpoint_t *endpoint, + oc_session_state_t state) { - (void)device; - if (!eps) { - oc_endpoint_t *ep = oc_new_endpoint(); - if (!ep) { - return NULL; + if (oc_list_length(oc_session_event_cb_list) > 0) { + oc_session_event_cb_t *cb_item = oc_list_head(oc_session_event_cb_list); + while (cb_item) { + cb_item->handler(endpoint, state); + cb_item = cb_item->next; } - eps = ep; - memset(ep, 0, sizeof(oc_endpoint_t)); - ep->flags = IPV6; - net_addr_pton(AF_INET6, CONFIG_NET_APP_MY_IPV6_ADDR, ep->addr.ipv6.address); - ep->addr.ipv6.port = ntohs(my_addr6.sin6_port); - ep->device = 0; + } +} +#endif /* OC_SESSION_EVENTS */ + +#ifdef OC_IPV4 +static int +connectivity_ipv4_init(ip_context_t *dev) +{ + struct sockaddr_in *addr; + OC_DBG("Initializing IPv4 connectivity for device %zd", dev->device); + + // Initialize IPv4 socket + memset(&dev->server4, 0, sizeof(struct sockaddr_storage)); + addr = (struct sockaddr_in *)&dev->server4; + addr->sin_family = AF_INET; + addr->sin_addr.s_addr = INADDR_ANY; + addr->sin_port = 0; + + dev->server4_sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (dev->server4_sock < 0) { + OC_ERR("Failed to create IPv4 socket for device %zd: %d", dev->device, errno); + return -1; + } + + if (bind(dev->server4_sock, (struct sockaddr *)&dev->server4, sizeof(dev->server4)) == -1) { + OC_ERR("Failed to bind the IPv4 socket for device %zd: %d", dev->device, errno); + return -1; + } + + socklen_t socklen = sizeof(dev->server4); + if (getsockname(dev->server4_sock, (struct sockaddr *)&dev->server4, &socklen) == -1) { + OC_ERR("Failed to get the IPv4 socket name for device %zd: %d", dev->device, errno); + return -1; + } + addr = (struct sockaddr_in *)&dev->server4; + dev->port4 = ntohs(addr->sin_port); + + // Initialize IPv4 multicast socket + memset(&dev->mcast4, 0, sizeof(struct sockaddr_storage)); + addr = (struct sockaddr_in *)&dev->mcast4; + addr->sin_family = AF_INET; + addr->sin_port = htons(OCF_PORT_UNSECURED); + addr->sin_addr.s_addr = INADDR_ANY; + + dev->mcast4_sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (dev->mcast4_sock < 0) { + OC_ERR("Failed to create IPv4 multicast socket for device %zd: %d", dev->device, errno); + return -1; + } + + int on = 1; + if (setsockopt(dev->mcast4_sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1) { + OC_ERR("Failed to set the reuseaddr option on the IPv4 multicast socket for device %zd: %d", dev->device, errno); + return -1; + } + + if (bind(dev->mcast4_sock, (struct sockaddr *)&dev->mcast4, sizeof(dev->mcast4)) == -1) { + OC_ERR("Failed to bind the IPv4 multicast socket for device %zd: %d", dev->device, errno); + return -1; + } + + if (configure_mcast_socket(dev->mcast4_sock, AF_INET) < 0) { + OC_ERR("Failed to configure the IPv4 multicast socket for device %zd", dev->device); + return -1; + } + #ifdef OC_SECURITY - oc_endpoint_t *ep_sec = oc_new_endpoint(); - if (ep_sec) { - memset(ep_sec, 0, sizeof(oc_endpoint_t)); - ep_sec->flags = IPV6 | SECURED; - net_addr_pton(AF_INET6, CONFIG_NET_APP_MY_IPV6_ADDR, - ep_sec->addr.ipv6.address); - ep_sec->addr.ipv6.port = ntohs(dtls_addr6.sin6_port); - ep_sec->device = 0; - ep->next = ep_sec; - } + // Initialize secure IPv4 socket + memset(&dev->secure4, 0, sizeof(struct sockaddr_storage)); + addr = (struct sockaddr_in *)&dev->secure4; + addr->sin_family = AF_INET; + addr->sin_port = 0; + addr->sin_addr.s_addr = INADDR_ANY; + + dev->secure4_sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (dev->secure4_sock < 0) { + OC_ERR("Failed to create secure IPv4 socket for device %zd: %d", dev->device, errno); + return -1; + } + + if (bind(dev->secure4_sock, (struct sockaddr *)&dev->secure4, sizeof(dev->secure4)) == -1) { + OC_ERR("Failed to bind the secure IPv4 socket for device %zd: %d", dev->device, errno); + return -1; + } + + socklen = sizeof(dev->secure4); + if (getsockname(dev->secure4_sock, (struct sockaddr *)&dev->secure4, &socklen) == -1) { + OC_ERR("Failed to get the secure IPv4 socket name for device %zd: %d", dev->device, errno); + return -1; + } + addr = (struct sockaddr_in *)&dev->secure4; + dev->dtls4_port = ntohs(addr->sin_port); #endif /* OC_SECURITY */ + + OC_DBG("Successfully initialized IPv4 connectivity for device %zd", dev->device); + return 0; +} +#endif + +static void +net_mgmt_event_if_handler(struct net_mgmt_event_callback *cb, uint32_t mgmt_event, struct net_if *iface) +{ + switch(mgmt_event) + { + case NET_EVENT_IF_UP: + { + OC_DBG("event: NET_EVENT_IF_UP"); + process_interface_change_event(iface, NETWORK_INTERFACE_UP); + } + break; + case NET_EVENT_IF_DOWN: + { + OC_DBG("event: NET_EVENT_IF_DOWN"); + process_interface_change_event(iface, NETWORK_INTERFACE_DOWN); + } + break; + default: + OC_WRN("unhandled event: 0x%x", mgmt_event); + break; } - return eps; } int oc_connectivity_init(size_t device) { - (void)device; - int ret; + struct sockaddr_in6 *addr; + OC_DBG("Initializing connectivity for device %zd", device); - /* Record OCF's multicast address with network interface */ - net_if_ipv6_maddr_add(net_if_get_default(), &in6addr_mcast); + ip_context_t *dev = (ip_context_t *)oc_memb_alloc(&ip_context_s); + if (!dev) { + oc_abort("Insufficient memory"); + } + oc_list_add(ip_contexts, dev); + dev->device = device; + OC_LIST_STRUCT_INIT(dev, eps); - net_ipaddr_copy(&mcast_addr6.sin6_addr, &in6addr_mcast); - mcast_addr6.sin6_family = AF_INET6; - mcast_addr6.sin6_port = htons(OCF_MCAST_PORT); + if (pthread_mutex_init(&dev->rfds_mutex, NULL) != 0) { + OC_ERR("Failed to initialize mutex for receive file descriptors for device %zd", dev->device); + oc_abort("Failed to initialize mutex"); + } - /* Wildcard address set for server with randomly chosen port */ - my_addr6.sin6_family = AF_INET6; + if (zsock_socketpair(AF_UNIX, SOCK_STREAM, 0, dev->shutdown_pipe) < 0) { + OC_ERR("Failed to create the shutdown_pipe socketpair: %d", errno); + return -1; + } - /* Add unicast IPV6 address to interface so that node can communicate */ - /* Would be good to have the address auto-configured in case some router is - * distributing pre-fixes*/ - if (net_addr_pton(AF_INET6, CONFIG_NET_APP_MY_IPV6_ADDR, &in6addr_my) < 0) { - NET_ERR("Invalid IPv6 address %s", CONFIG_NET_APP_MY_IPV6_ADDR); + if (set_nonblock_socket(dev->shutdown_pipe[0]) < 0) { + OC_ERR("Could not set shutdown_pipe[0] to non-blocking mode: %d", errno); + return -1; } -#ifdef OC_DEBUG - struct net_if_addr *ifaddr = -#endif - net_if_ipv6_addr_add(net_if_get_default(), &in6addr_my, NET_ADDR_MANUAL, 0); -#ifdef OC_DEBUG - OC_DBG("=====>>>Interface unicast address added @ %p", ifaddr); -#endif + // Initialize IPv6 socket + memset(&dev->server, 0, sizeof(struct sockaddr_storage)); + addr = (struct sockaddr_in6 *)&dev->server; + addr->sin6_family = AF_INET6; + addr->sin6_port = 0; + addr->sin6_addr = in6addr_any; -#ifdef OC_SECURITY - dtls_addr6.sin6_port = htons(MY_DTLS_PORT); - dtls_addr6.sin6_family = AF_INET6; -#endif /* OC_SECURITY */ + dev->server_sock = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); + if (dev->server_sock < 0) { + OC_ERR("Failed to create IPv6 socket for device %zd: %d", dev->device, errno); + return -1; + } - ret = net_context_get(AF_INET6, SOCK_DGRAM, IPPROTO_UDP, &udp_recv6); - if (ret < 0) { - OC_WRN("oc_connectivity_init: cannot get UDP network context for server" - "receive (%d)", - ret); - goto error; + int sockopt_on = 1; + if (setsockopt(dev->server_sock, IPPROTO_IPV6, IPV6_V6ONLY, &sockopt_on, sizeof(sockopt_on)) == -1) { + OC_ERR("Failed to set the IPv6 only option on the IPv6 socket for device %zd: %d", dev->device, errno); + return -1; } - ret = net_context_bind(udp_recv6, (struct sockaddr *)&my_addr6, - sizeof(struct sockaddr_in6)); - if (ret < 0) { - OC_WRN("oc_connectivity_init: cannot bind UDP port %d to server's network" - "context (%d)", - ntohs(my_addr6.sin6_port), ret); - goto error; + if (bind(dev->server_sock, (struct sockaddr *)&dev->server, sizeof(dev->server)) == -1) { + OC_ERR("Failed to bind the IPv6 socket for device %zd: %d", dev->device, errno); + return -1; } - ret = net_context_get(AF_INET6, SOCK_DGRAM, IPPROTO_UDP, &mcast_recv6); - if (ret < 0) { - OC_WRN("oc_connectivity_init: cannot get UDP network context for OCF" - "multicast receive (%d)", - ret); - goto error; + socklen_t socklen = sizeof(dev->server); + if (getsockname(dev->server_sock, (struct sockaddr *)&dev->server, &socklen) == -1) { + OC_ERR("Failed to get the IPv6 socket name for device %zd: %d", dev->device, errno); + return -1; } + addr = (struct sockaddr_in6 *)&dev->server; + dev->port = ntohs(addr->sin6_port); - ret = net_context_bind(mcast_recv6, (struct sockaddr *)&mcast_addr6, - sizeof(struct sockaddr_in6)); - if (ret < 0) { - OC_WRN("oc_connectivity_init: cannot bind OCF multicast network context" - "(%d)", - ret); - goto error; + // Initialize IPv6 multicast socket + memset(&dev->mcast, 0, sizeof(struct sockaddr_storage)); + addr = (struct sockaddr_in6 *)&dev->mcast; + addr->sin6_family = AF_INET6; + addr->sin6_port = htons(OCF_PORT_UNSECURED); + addr->sin6_addr = in6addr_any; + + dev->mcast_sock = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); + if (dev->server_sock < 0) { + OC_ERR("Failed to create IPv6 multicast socket for device %zd: %d", dev->device, errno); + return -1; + } + + if (setsockopt(dev->mcast_sock, SOL_SOCKET, SO_REUSEADDR, &sockopt_on, sizeof(sockopt_on)) == -1) { + OC_ERR("Failed to set the reuseaddr option on the IPv6 multicast socket for device %zd: %d", dev->device, errno); + return -1; + } + + if (bind(dev->mcast_sock, (struct sockaddr *)&dev->mcast, sizeof(dev->mcast)) == -1) { + OC_ERR("Failed to bind the IPv6 multicast socket for device %zd: %d", dev->device, errno); + return -1; + } + + if (configure_mcast_socket(dev->mcast_sock, AF_INET6) < 0) { + OC_ERR("Failed to configure the IPv6 multicast socket for device %zd", dev->device); + return -1; } #ifdef OC_SECURITY - ret = net_context_get(AF_INET6, SOCK_DGRAM, IPPROTO_UDP, &dtls_recv6); - if (ret < 0) { - OC_WRN("oc_connectivity_init: cannot get DTLS network context" - "(%d)", - ret); - goto error; + // Initialize secure IPv6 socket + memset(&dev->secure, 0, sizeof(struct sockaddr_storage)); + addr = (struct sockaddr_in6 *)&dev->secure; + // TODO: The following 3 lines cause a "Unaligned memory access" CPU fault +// addr->sin6_family = AF_INET6; +// addr->sin6_port = 0; +// addr->sin6_addr = in6addr_any; + + dev->secure_sock = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); + if (dev->secure_sock < 0) { + OC_ERR("Failed to create secure IPv6 socket for device %zd: %d", dev->device, errno); + return -1; } - ret = net_context_bind(dtls_recv6, (struct sockaddr *)&dtls_addr6, - sizeof(struct sockaddr_in6)); - if (ret < 0) { - OC_WRN("oc_connectivity_init: cannot bind DTLS network context" - "(%d)", - ret); - goto error; + if (setsockopt(dev->secure_sock, IPPROTO_IPV6, IPV6_V6ONLY, &sockopt_on, sizeof(sockopt_on)) == -1) { + OC_ERR("Failed to set the IPv6 only option on the secure IPv6 socket for device %zd: %d", dev->device, errno); + return -1; } -#endif /* OC_SECURITY */ - ret = net_context_recv(mcast_recv6, oc_network_receive, 0, NULL); - if (ret < 0) { - OC_WRN("oc_connectivity_init: net_context_recv error from multicast socket:" - "(%d)", - ret); - goto error; + if (bind(dev->secure_sock, (struct sockaddr *)&dev->secure, sizeof(dev->secure)) == -1) { + OC_ERR("Failed to bind the secure IPv6 socket for device %zd: %d", dev->device, errno); + return -1; } - ret = net_context_recv(udp_recv6, oc_network_receive, 0, NULL); - if (ret < 0) { - OC_WRN("oc_connectivity_init: net_context_recv error from server socket:" - "(%d)", - ret); - goto error; + socklen = sizeof(dev->secure); + if (getsockname(dev->secure_sock, (struct sockaddr *)&dev->secure, &socklen) == -1) { + OC_ERR("Failed to get the secure IPv6 socket name for device %zd: %d", dev->device, errno); + return -1; } + addr = (struct sockaddr_in6 *)&dev->secure; + dev->dtls_port = ntohs(addr->sin6_port); +#endif /* OC_SECURITY */ +#ifdef OC_IPV4 + if (connectivity_ipv4_init(dev) != 0) { + OC_ERR("Failed to initialize IPv4 connectivity for device %zd", dev->device); + return -1; + } +#endif /* OC_IPV4 */ + + OC_DBG("=======ip port info.========"); + OC_DBG(" ipv6 port : %u", dev->port); #ifdef OC_SECURITY - static uint16_t dtls_port = MY_DTLS_PORT; - ret = net_context_recv(dtls_recv6, oc_network_receive, 0, &dtls_port); - if (ret < 0) { - OC_WRN("oc_connectivity_init: net_context_recv error from DTLS socket:" - "(%d)", - ret); - goto error; + OC_DBG(" ipv6 secure : %u", dev->dtls_port); +#endif +#ifdef OC_IPV4 + OC_DBG(" ipv4 port : %u", dev->port4); +#ifdef OC_SECURITY + OC_DBG(" ipv4 secure : %u", dev->dtls4_port); +#endif +#endif + +#ifdef OC_TCP + if (oc_tcp_connectivity_init(dev) != 0) { + OC_ERR("Could not initialize TCP adapter"); } -#endif /* OC_SECURITY */ +#endif /* OC_TCP */ - OC_DBG("oc_connectivity_init: successfully initialized connectivity"); - return 0; + /* Register network management event callbacks to listen for network interface changes. + */ + if (!ifchange_initialized) { + net_mgmt_init_event_callback(&net_mgmt_event_if_cb, net_mgmt_event_if_handler, NET_EVENT_IF_UP | NET_EVENT_IF_DOWN); + net_mgmt_add_event_callback(&net_mgmt_event_if_cb); +#ifdef OC_NETWORK_MONITOR + if (!check_new_ip_interfaces()) { + OC_ERR("Check for new IP interfaces failed"); + return -1; + } +#endif /* OC_NETWORK_MONITOR */ + ifchange_initialized = true; + } -error: - OC_ERR("oc_connectivity_init: failed to initialize connectivity"); - return -1; + int ret = pthread_attr_init(&oc_network_thread_attr); + if (ret != 0) { + OC_ERR("Failed to initialize network thread for device %zd: pthread_attr_init() failed: %d", dev->device, errno); + return -1; + } + ret = pthread_attr_setstack(&oc_network_thread_attr, &oc_network_thread_stack, NETWORK_THREAD_STACKSIZE); + if (ret != 0) { + OC_ERR("Failed to initialize network thread for device %zd: pthread_attr_setstack() failed: %d", dev->device, errno); + return -1; + } + ret = pthread_create(&dev->event_thread, &oc_network_thread_attr, &network_event_thread, dev); + if (ret != 0) { + OC_ERR("Failed to initialize network thread for device %zd: pthread_create() failed: %d", dev->device, errno); + return -1; + } + + OC_DBG("Successfully initialized connectivity for device %zd", device); + + return 0; } void oc_connectivity_shutdown(size_t device) { - (void)device; + ip_context_t *dev = get_ip_context_for_device(device); + OC_ATOMIC_STORE8(dev->terminate, 1); + if (write(dev->shutdown_pipe[1], "\n", 1) < 0) { + OC_WRN("cannot wakeup network thread"); + } + + pthread_join(dev->event_thread, NULL); + + close(dev->server_sock); + close(dev->mcast_sock); + +#ifdef OC_IPV4 + close(dev->server4_sock); + close(dev->mcast4_sock); +#endif /* OC_IPV4 */ + #ifdef OC_SECURITY - net_context_put(dtls_recv6); + close(dev->secure_sock); +#ifdef OC_IPV4 + close(dev->secure4_sock); +#endif /* OC_IPV4 */ #endif /* OC_SECURITY */ - net_context_put(udp_recv6); - net_context_put(mcast_recv6); - free_endpoints(); + +#ifdef OC_TCP + oc_tcp_connectivity_shutdown(dev); +#endif /* OC_TCP */ + + close(dev->shutdown_pipe[1]); + close(dev->shutdown_pipe[0]); + + pthread_mutex_destroy(&dev->rfds_mutex); + + free_endpoints_list(dev); + + oc_list_remove(ip_contexts, dev); + oc_memb_free(&ip_context_s, dev); } -#ifdef OC_CLIENT +#ifdef OC_TCP void -oc_send_discovery_request(oc_message_t *message) +oc_connectivity_end_session(oc_endpoint_t *endpoint) { - oc_send_buffer(message); + if (endpoint->flags & TCP) { + ip_context_t *dev = get_ip_context_for_device(endpoint->device); + if (dev) { + oc_tcp_end_session(dev, endpoint); + } + } +} +#endif /* OC_TCP */ + +#ifdef OC_DNS_LOOKUP +#ifdef OC_DNS_CACHE +typedef struct oc_dns_cache_t +{ + struct oc_dns_cache_t *next; + oc_string_t domain; + union dev_addr addr; +} oc_dns_cache_t; + +OC_MEMB(dns_s, oc_dns_cache_t, 1); +OC_LIST(dns_cache); + +static oc_dns_cache_t * +oc_dns_lookup_cache(const char *domain) +{ + if (oc_list_length(dns_cache) == 0) { + return NULL; + } + oc_dns_cache_t *c = (oc_dns_cache_t *)oc_list_head(dns_cache); + while (c) { + if (strlen(domain) == oc_string_len(c->domain) && + memcmp(domain, oc_string(c->domain), oc_string_len(c->domain)) == 0) { + return c; + } + c = c->next; + } + return NULL; +} + +static int +oc_dns_cache_domain(const char *domain, union dev_addr *addr) +{ + oc_dns_cache_t *c = (oc_dns_cache_t *)oc_memb_alloc(&dns_s); + if (c) { + oc_new_string(&c->domain, domain, strlen(domain)); + memcpy(&c->addr, addr, sizeof(union dev_addr)); + oc_list_add(dns_cache, c); + return 0; + } + return -1; +} + +void +oc_dns_clear_cache(void) +{ + oc_dns_cache_t *c = (oc_dns_cache_t *)oc_list_pop(dns_cache); + while (c) { + oc_free_string(&c->domain); + oc_memb_free(&dns_s, c); + c = (oc_dns_cache_t *)oc_list_pop(dns_cache); + } +} +#endif /* OC_DNS_CACHE */ + +int +oc_dns_lookup(const char *domain, oc_string_t *addr, enum transport_flags flags) +{ + if (!domain || !addr) { + OC_ERR("Error of input parameters"); + return -1; + } + int ret = -1; + union dev_addr a; + +#ifdef OC_DNS_CACHE + oc_dns_cache_t *c = oc_dns_lookup_cache(domain); + + if (!c) { +#endif /* OC_DNS_CACHE */ + memset(&a, 0, sizeof(union dev_addr)); + + struct addrinfo hints, *result = NULL; + memset(&hints, 0, sizeof(hints)); + hints.ai_family = (flags & IPV6) ? AF_INET6 : AF_INET; + hints.ai_socktype = (flags & TCP) ? SOCK_STREAM : SOCK_DGRAM; + ret = getaddrinfo(domain, NULL, &hints, &result); + + if (ret == 0) { + if (flags & IPV6) { + struct sockaddr_in6 *r = (struct sockaddr_in6 *)result->ai_addr; + memcpy(a.ipv6.address, r->sin6_addr.s6_addr, + sizeof(r->sin6_addr.s6_addr)); + a.ipv6.port = ntohs(r->sin6_port); + a.ipv6.scope = r->sin6_scope_id; + } +#ifdef OC_IPV4 + else { + struct sockaddr_in *r = (struct sockaddr_in *)result->ai_addr; + memcpy(a.ipv4.address, &r->sin_addr.s_addr, sizeof(r->sin_addr.s_addr)); + a.ipv4.port = ntohs(r->sin_port); + } +#endif /* OC_IPV4 */ +#ifdef OC_DNS_CACHE + oc_dns_cache_domain(domain, &a); +#endif /* OC_DNS_CACHE */ + } + freeaddrinfo(result); +#ifdef OC_DNS_CACHE + } else { + ret = 0; + memcpy(&a, &c->addr, sizeof(union dev_addr)); + } +#endif /* OC_DNS_CACHE */ + + if (ret == 0) { + char address[INET6_ADDRSTRLEN + 2] = { 0 }; + const char *dest = NULL; + if (flags & IPV6) { + address[0] = '['; + dest = inet_ntop(AF_INET6, (void *)a.ipv6.address, address + 1, + INET6_ADDRSTRLEN); + size_t addr_len = strlen(address); + address[addr_len] = ']'; + address[addr_len + 1] = '\0'; + } +#ifdef OC_IPV4 + else { + dest = + inet_ntop(AF_INET, (void *)a.ipv4.address, address, INET_ADDRSTRLEN); + } +#endif /* OC_IPV4 */ + if (dest) { + OC_DBG("%s address is %s", domain, address); + oc_new_string(addr, address, strlen(address)); + } else { + ret = -1; + } + } + + return ret; +} +#endif /* OC_DNS_LOOKUP */ + +int +set_nonblock_socket(int sockfd) +{ + int flags = zsock_fcntl(sockfd, F_GETFL, 0); + if (flags < 0) { + return -1; + } + + return zsock_fcntl(sockfd, F_SETFL, flags | O_NONBLOCK); +} + +void +ip_context_rfds_fd_set(ip_context_t *dev, int sockfd) +{ + pthread_mutex_lock(&dev->rfds_mutex); + FD_SET(sockfd, &dev->rfds); + pthread_mutex_unlock(&dev->rfds_mutex); +} + +void +ip_context_rfds_fd_clr(ip_context_t *dev, int sockfd) +{ + pthread_mutex_lock(&dev->rfds_mutex); + FD_CLR(sockfd, &dev->rfds); + pthread_mutex_unlock(&dev->rfds_mutex); +} + +fd_set +ip_context_rfds_fd_copy(ip_context_t *dev) +{ + fd_set setfds; + pthread_mutex_lock(&dev->rfds_mutex); + memcpy(&setfds, &dev->rfds, sizeof(dev->rfds)); + pthread_mutex_unlock(&dev->rfds_mutex); + return setfds; } -#endif /* OC_CLIENT */ diff --git a/port/zephyr/src/ipadapter.h b/port/zephyr/src/ipadapter.h new file mode 100644 index 0000000000..c037219c6d --- /dev/null +++ b/port/zephyr/src/ipadapter.h @@ -0,0 +1,23 @@ +/**************************************************************************** + * + * Copyright 2019 Jozef Kralik 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. + * + ******************************************************************/ +#ifndef IPADAPTER_H +#define IPADAPTER_H + +int set_nonblock_socket(int sockfd); + +#endif /* IPADAPTER_H */ \ No newline at end of file diff --git a/port/zephyr/src/ipcontext.h b/port/zephyr/src/ipcontext.h new file mode 100644 index 0000000000..e6f66f6cbb --- /dev/null +++ b/port/zephyr/src/ipcontext.h @@ -0,0 +1,138 @@ +/**************************************************************************** + * + * Copyright 2018 Samsung Electronics 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. + * + ****************************************************************************/ + +#ifndef IPCONTEXT_H +#define IPCONTEXT_H + +#include "oc_endpoint.h" +#include "util/oc_atomic.h" +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + ADAPTER_STATUS_NONE = 0, /* Nothing happens */ + ADAPTER_STATUS_ACCEPT, /* Receiving no meaningful data */ + ADAPTER_STATUS_RECEIVE, /* Receiving meaningful data */ + ADAPTER_STATUS_ERROR /* Error */ +} adapter_receive_state_t; + +#ifdef OC_TCP +typedef struct tcp_context_t +{ + struct sockaddr_storage server; + int server_sock; + uint16_t port; +#ifdef OC_SECURITY + struct sockaddr_storage secure; + int secure_sock; + uint16_t tls_port; +#endif /* OC_SECURITY */ +#ifdef OC_IPV4 + struct sockaddr_storage server4; + int server4_sock; + uint16_t port4; +#ifdef OC_SECURITY + struct sockaddr_storage secure4; + int secure4_sock; + uint16_t tls4_port; +#endif /* OC_SECURITY */ +#endif /* OC_IPV4 */ + int connect_pipe[2]; +} tcp_context_t; +#endif + +typedef enum { + IP_CONTEXT_FLAG_REFRESH_ENDPOINT_LIST = + 1 << 0, ///< used to signal that endpoint list needs to be refreshed +} ip_context_flags_t; + +typedef struct ip_context_t +{ + struct ip_context_t *next; + OC_LIST_STRUCT(eps); /// < not thread-safe, must be used only from main thread + struct sockaddr_storage mcast; + struct sockaddr_storage server; + int mcast_sock; + int server_sock; + uint16_t port; +#ifdef OC_SECURITY + struct sockaddr_storage secure; + int secure_sock; + uint16_t dtls_port; +#endif /* OC_SECURITY */ +#ifdef OC_IPV4 + struct sockaddr_storage mcast4; + struct sockaddr_storage server4; + int mcast4_sock; + int server4_sock; + uint16_t port4; +#ifdef OC_SECURITY + struct sockaddr_storage secure4; + int secure4_sock; + uint16_t dtls4_port; +#endif /* OC_SECURITY */ +#endif /* OC_IPV4 */ +#ifdef OC_TCP + tcp_context_t tcp; +#endif + pthread_t event_thread; + OC_ATOMIC_INT8_T terminate; + size_t device; + pthread_mutex_t rfds_mutex; + fd_set rfds; + int shutdown_pipe[2]; + OC_ATOMIC_INT8_T flags; +} ip_context_t; + +/** + * Set a given file descriptor to a set (dev->rfds) under the mutex(rfds_mutex). + * + * @param[in] dev the device network context. + * @param[in] sockfd the file descriptor. + */ +void ip_context_rfds_fd_set(ip_context_t *dev, int sockfd); + +/** + * Remove a given file descriptor from a set (dev->rfds) under the + * mutex(rfds_mutex). + * + * @param[in] dev the device network context. + * @param[in] sockfd the file descriptor. + */ +void ip_context_rfds_fd_clr(ip_context_t *dev, int sockfd); + +/** + * Make a copy of file descriptor set (dev->rfds) under the mutex(rfds_mutex). + * + * @param[in] dev the device network context. + * + * @return a copy of file descriptor set. + */ +fd_set ip_context_rfds_fd_copy(ip_context_t *dev); + +#ifdef __cplusplus +} +#endif + +#endif /* IPCONTEXT_H */ From ea295f4ac3a240dc1cc0786e9059b271d907db04 Mon Sep 17 00:00:00 2001 From: Martin Roesch Date: Fri, 18 Mar 2022 12:22:27 +0100 Subject: [PATCH 21/30] Add 16 padding bits to struct ip_context_t for word alignment. --- port/zephyr/src/ipcontext.h | 1 + 1 file changed, 1 insertion(+) diff --git a/port/zephyr/src/ipcontext.h b/port/zephyr/src/ipcontext.h index e6f66f6cbb..ba6c378386 100644 --- a/port/zephyr/src/ipcontext.h +++ b/port/zephyr/src/ipcontext.h @@ -76,6 +76,7 @@ typedef struct ip_context_t int mcast_sock; int server_sock; uint16_t port; + uint16_t padding; #ifdef OC_SECURITY struct sockaddr_storage secure; int secure_sock; From 4c328794ab7318cc87224d39b1b593cd6baac233 Mon Sep 17 00:00:00 2001 From: Martin Roesch Date: Fri, 18 Mar 2022 12:23:25 +0100 Subject: [PATCH 22/30] Initialize secure IPv6 socket --- port/zephyr/src/ipadapter.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/port/zephyr/src/ipadapter.c b/port/zephyr/src/ipadapter.c index 6404c0a7ae..3a2330706e 100644 --- a/port/zephyr/src/ipadapter.c +++ b/port/zephyr/src/ipadapter.c @@ -1235,10 +1235,9 @@ oc_connectivity_init(size_t device) // Initialize secure IPv6 socket memset(&dev->secure, 0, sizeof(struct sockaddr_storage)); addr = (struct sockaddr_in6 *)&dev->secure; - // TODO: The following 3 lines cause a "Unaligned memory access" CPU fault -// addr->sin6_family = AF_INET6; -// addr->sin6_port = 0; -// addr->sin6_addr = in6addr_any; + addr->sin6_family = AF_INET6; + addr->sin6_port = 0; + addr->sin6_addr = in6addr_any; dev->secure_sock = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); if (dev->secure_sock < 0) { From 659dc836e53911c33ebab84c6c85f38b79b1d381 Mon Sep 17 00:00:00 2001 From: Martin Roesch Date: Fri, 18 Mar 2022 12:27:20 +0100 Subject: [PATCH 23/30] Fix mbedtls build when dynamic memory allocation is disabled --- deps/mbedtls.cmake | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/deps/mbedtls.cmake b/deps/mbedtls.cmake index d3c2a30df3..8c7018f52d 100755 --- a/deps/mbedtls.cmake +++ b/deps/mbedtls.cmake @@ -13,9 +13,13 @@ file(GLOB MBEDTLS_SRC ) list(REMOVE_ITEM MBEDTLS_SRC ${PROJECT_SOURCE_DIR}/deps/mbedtls/library/certs.c - ${PROJECT_SOURCE_DIR}/deps/mbedtls/library/memory_buffer_alloc.c ${PROJECT_SOURCE_DIR}/deps/mbedtls/library/x509_crl.c ) +if(OC_DYNAMIC_ALLOCATION_ENABLED) + list(REMOVE_ITEM MBEDTLS_SRC + ${PROJECT_SOURCE_DIR}/deps/mbedtls/library/memory_buffer_alloc.c + ) +endif() add_library(mbedtls OBJECT ${MBEDTLS_SRC}) target_include_directories(mbedtls PRIVATE ${PROJECT_SOURCE_DIR} From ad62bb22be1a03531988590013a6f52b2b669892 Mon Sep 17 00:00:00 2001 From: Martin Roesch Date: Fri, 18 Mar 2022 12:30:20 +0100 Subject: [PATCH 24/30] zephyr oc_config.h: Fix definitions when dynamic memory allocation is disabled --- port/zephyr/src/oc_config.h | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/port/zephyr/src/oc_config.h b/port/zephyr/src/oc_config.h index c78755185f..8eedb5fc91 100644 --- a/port/zephyr/src/oc_config.h +++ b/port/zephyr/src/oc_config.h @@ -57,7 +57,8 @@ typedef uint64_t oc_clock_time_t; #else /* OC_DYNAMIC_ALLOCATION */ /* Common parameters */ -//#define OC_BLOCK_WISE_SET_MTU (80) +/* Prescriptive lower layers MTU size, enable block-wise transfers */ +#define OC_BLOCK_WISE_SET_MTU (700) /* Maximum size of request/response PDUs */ #define OC_MAX_APP_DATA_SIZE (600) @@ -81,7 +82,18 @@ typedef uint64_t oc_clock_time_t; #define OC_MAX_NUM_SUBJECTS (1) /* Maximum number of concurrent DTLS sessions */ -#define OC_MAX_DTLS_PEERS (1) +#define OC_MAX_TLS_PEERS (1) + +/* Maximum number of interfaces for IP adapter */ +#define OC_MAX_IP_INTERFACES (2) + +/* Maximum number of callbacks for Network interface event monitoring */ +#define OC_MAX_NETWORK_INTERFACE_CBS (2) + +/* Maximum number of callbacks for connection of session */ +#define OC_MAX_SESSION_EVENT_CBS (2) + +#define OC_MAX_DOXM_OWNED_CBS (2) #endif /* !OC_DYNAMIC_ALLOCATION */ From 75e87cc6c15390b8c275eaad278a8bffa0f7370d Mon Sep 17 00:00:00 2001 From: Martin Roesch Date: Fri, 18 Mar 2022 18:21:23 +0100 Subject: [PATCH 25/30] Define OC_CLOCK_CONF_TICKS_PER_SECOND from Zephyr configuration --- port/zephyr/src/oc_config.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/port/zephyr/src/oc_config.h b/port/zephyr/src/oc_config.h index 8eedb5fc91..0df5fec9f5 100644 --- a/port/zephyr/src/oc_config.h +++ b/port/zephyr/src/oc_config.h @@ -21,7 +21,7 @@ #include typedef uint64_t oc_clock_time_t; #include -#define OC_CLOCK_CONF_TICKS_PER_SECOND (1000) +#define OC_CLOCK_CONF_TICKS_PER_SECOND (CONFIG_SYS_CLOCK_TICKS_PER_SEC) #define OC_BYTES_POOL_SIZE (1024) #define OC_INTS_POOL_SIZE (16) From 6a784bb57a18eb25beb52c0a096a4749dda751b6 Mon Sep 17 00:00:00 2001 From: Martin Roesch Date: Fri, 18 Mar 2022 18:49:30 +0100 Subject: [PATCH 26/30] zephyr oc_config.h: Synchonize with linux port --- port/zephyr/src/oc_config.h | 48 ++++++++++++++++++++++++------------- 1 file changed, 32 insertions(+), 16 deletions(-) diff --git a/port/zephyr/src/oc_config.h b/port/zephyr/src/oc_config.h index 0df5fec9f5..5b8bf1d365 100644 --- a/port/zephyr/src/oc_config.h +++ b/port/zephyr/src/oc_config.h @@ -19,19 +19,20 @@ /* Time resolution */ #include + +#ifdef __cplusplus +extern "C" { +#endif + typedef uint64_t oc_clock_time_t; #include #define OC_CLOCK_CONF_TICKS_PER_SECOND (CONFIG_SYS_CLOCK_TICKS_PER_SEC) -#define OC_BYTES_POOL_SIZE (1024) -#define OC_INTS_POOL_SIZE (16) -#define OC_DOUBLES_POOL_SIZE (16) - /* jitter added to response to some multicast requests */ #define OC_MULTICAST_RESPONSE_JITTER_MS (2000) /* Max inactivity timeout before tearing down DTLS connection */ -#define OC_DTLS_INACTIVITY_TIMEOUT (10) +#define OC_DTLS_INACTIVITY_TIMEOUT (600) /* Add support for passing network up/down events to the app */ #define OC_NETWORK_MONITOR @@ -40,13 +41,12 @@ typedef uint64_t oc_clock_time_t; /* Add request history for deduplicate UDP/DTLS messages */ #define OC_REQUEST_HISTORY +/* Add batch interface support to /oic/res */ +#define OC_RES_BATCH_SUPPORT + /* Add support observable for oic/res */ //#define OC_DISCOVERY_RESOURCE_OBSERVABLE -/* Server-side parameters */ -/* Maximum number of server resources */ -#define OC_MAX_APP_RESOURCES (1) - #ifdef OC_DYNAMIC_ALLOCATION #define OC_COLLECTIONS #define OC_BLOCK_WISE @@ -56,12 +56,26 @@ typedef uint64_t oc_clock_time_t; //#define OC_REP_ENCODING_REALLOC #else /* OC_DYNAMIC_ALLOCATION */ +/* List of constraints below for a build that does not employ dynamic + memory allocation +*/ +/* Memory pool sizes */ +#define OC_BYTES_POOL_SIZE (1800) +#define OC_INTS_POOL_SIZE (100) +#define OC_DOUBLES_POOL_SIZE (4) + +/* Server-side parameters */ +/* Maximum number of server resources */ +#define OC_MAX_APP_RESOURCES (4) + +#define OC_MAX_NUM_COLLECTIONS (1) + /* Common parameters */ /* Prescriptive lower layers MTU size, enable block-wise transfers */ #define OC_BLOCK_WISE_SET_MTU (700) -/* Maximum size of request/response PDUs */ -#define OC_MAX_APP_DATA_SIZE (600) +/* Maximum size of request/response payloads */ +#define OC_MAX_APP_DATA_SIZE (2048) /* Maximum number of concurrent requests */ #define OC_MAX_NUM_CONCURRENT_REQUESTS (2) @@ -72,16 +86,14 @@ typedef uint64_t oc_clock_time_t; /* Number of devices on the OCF platform */ #define OC_MAX_NUM_DEVICES (1) +/* Maximum number of endpoints */ #define OC_MAX_NUM_ENDPOINTS (4) -/* Maximum size of uri for a collection resource */ -//#define OC_MAX_COLLECTIONS_INSTANCE_URI_SIZE (64) - /* Security layer */ /* Maximum number of authorized clients */ -#define OC_MAX_NUM_SUBJECTS (1) +#define OC_MAX_NUM_SUBJECTS (2) -/* Maximum number of concurrent DTLS sessions */ +/* Maximum number of concurrent (D)TLS sessions */ #define OC_MAX_TLS_PEERS (1) /* Maximum number of interfaces for IP adapter */ @@ -111,4 +123,8 @@ typedef uint64_t oc_clock_time_t; #define OC_STORAGE #endif +#ifdef __cplusplus +} +#endif + #endif /* OC_CONFIG_H */ From c66f4a16b76ea24e3f0eefe2da39fe907e8351b1 Mon Sep 17 00:00:00 2001 From: Martin Roesch Date: Tue, 5 Apr 2022 11:18:37 +0200 Subject: [PATCH 27/30] Only add_dependencies if TARGET_DEPENDENCIES is not empty --- CMakeLists.txt | 16 ++++++++++++---- deps/mbedtls.cmake | 4 +++- deps/tinycbor.cmake | 4 +++- 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9fb6b7f5f4..60ca9e4f40 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -280,7 +280,9 @@ add_library(common-obj OBJECT ${COMMON_SRC}) target_compile_definitions(common-obj PRIVATE ${PRIVATE_COMPILE_DEFINITIONS} PUBLIC ${PUBLIC_COMPILE_DEFINITIONS}) target_compile_options(common-obj PRIVATE ${PRIVATE_COMPILE_OPTIONS}) target_include_directories(common-obj PRIVATE ${PROJECT_SOURCE_DIR} ${PROJECT_SOURCE_DIR}/include ${PROJECT_SOURCE_DIR}/port ${PORT_INCLUDE_DIR}) -add_dependencies(common-obj ${TARGET_DEPENDENCIES}) +if(TARGET_DEPENDENCIES) + add_dependencies(common-obj ${TARGET_DEPENDENCIES}) +endif() add_library(client-obj OBJECT ${CLIENT_SRC}) target_compile_definitions(client-obj PRIVATE ${PRIVATE_COMPILE_DEFINITIONS} PUBLIC ${PUBLIC_COMPILE_DEFINITIONS} "OC_CLIENT") @@ -289,7 +291,9 @@ target_include_directories(client-obj PRIVATE ${PROJECT_SOURCE_DIR} ${PROJECT_SO if(OC_SECURITY_ENABLED) target_include_directories(client-obj PRIVATE ${MBEDTLS_INCLUDE_DIRS}) endif() -add_dependencies(client-obj ${TARGET_DEPENDENCIES}) +if(TARGET_DEPENDENCIES) + add_dependencies(client-obj ${TARGET_DEPENDENCIES}) +endif() add_library(server-obj OBJECT ${SERVER_SRC}) target_compile_definitions(server-obj PRIVATE ${PRIVATE_COMPILE_DEFINITIONS} PUBLIC ${PUBLIC_COMPILE_DEFINITIONS} "OC_SERVER") @@ -298,7 +302,9 @@ target_include_directories(server-obj PRIVATE ${PROJECT_SOURCE_DIR} ${PROJECT_SO if(OC_SECURITY_ENABLED) target_include_directories(server-obj PRIVATE ${MBEDTLS_INCLUDE_DIRS}) endif() -add_dependencies(server-obj ${TARGET_DEPENDENCIES}) +if(TARGET_DEPENDENCIES) + add_dependencies(server-obj ${TARGET_DEPENDENCIES}) +endif() add_library(client-server-obj OBJECT ${CLIENT_SRC}) target_compile_definitions(client-server-obj PRIVATE ${PRIVATE_COMPILE_DEFINITIONS} PUBLIC ${PUBLIC_COMPILE_DEFINITIONS} "OC_CLIENT" "OC_SERVER") @@ -307,7 +313,9 @@ target_include_directories(client-server-obj PRIVATE ${PROJECT_SOURCE_DIR} ${PRO if(OC_SECURITY_ENABLED) target_include_directories(client-server-obj PRIVATE ${MBEDTLS_INCLUDE_DIRS}) endif() -add_dependencies(client-server-obj ${TARGET_DEPENDENCIES}) +if(TARGET_DEPENDENCIES) + add_dependencies(client-server-obj ${TARGET_DEPENDENCIES}) +endif() if(OC_CLOUD_ENABLED) add_library(cloud-obj OBJECT ${CLOUD_SRC}) diff --git a/deps/mbedtls.cmake b/deps/mbedtls.cmake index 8c7018f52d..b1de6a70e8 100755 --- a/deps/mbedtls.cmake +++ b/deps/mbedtls.cmake @@ -33,4 +33,6 @@ target_compile_options(mbedtls PRIVATE ${PRIVATE_COMPILE_OPTIONS}) if(MSVC) target_compile_options(mbedtls PRIVATE /W1 /WX-) endif() -add_dependencies(mbedtls ${TARGET_DEPENDENCIES}) +if(TARGET_DEPENDENCIES) + add_dependencies(mbedtls ${TARGET_DEPENDENCIES}) +endif() diff --git a/deps/tinycbor.cmake b/deps/tinycbor.cmake index 4098f16769..9d12c3f41f 100755 --- a/deps/tinycbor.cmake +++ b/deps/tinycbor.cmake @@ -14,7 +14,9 @@ target_include_directories(tinycbor-master PUBLIC target_compile_definitions(tinycbor-master PUBLIC ${PUBLIC_COMPILE_DEFINITIONS} PRIVATE ${PRIVATE_COMPILE_DEFINITIONS}) target_compile_options(tinycbor-master PRIVATE ${PRIVATE_COMPILE_OPTIONS}) -add_dependencies(tinycbor-master ${TARGET_DEPENDENCIES}) +if(TARGET_DEPENDENCIES) + add_dependencies(tinycbor-master ${TARGET_DEPENDENCIES}) +endif() install(DIRECTORY ${PROJECT_SOURCE_DIR}/deps/tinycbor/src/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/iotivity-lite/deps/tinycbor/src COMPONENT dev From 309cee47a4e1646882f0baf4bdfaa66f826ef4be Mon Sep 17 00:00:00 2001 From: Cascoda Bot Date: Tue, 5 Apr 2022 12:21:08 +0000 Subject: [PATCH 28/30] Automatic format commit --- port/zephyr/src/ipadapter.c | 296 ++++++++++++++++++++--------------- port/zephyr/src/storage_fs.c | 24 +-- 2 files changed, 186 insertions(+), 134 deletions(-) diff --git a/port/zephyr/src/ipadapter.c b/port/zephyr/src/ipadapter.c index 3a2330706e..f4a31a7ba7 100644 --- a/port/zephyr/src/ipadapter.c +++ b/port/zephyr/src/ipadapter.c @@ -248,17 +248,20 @@ net_if_manage_ipv4_mcast_group(struct net_if *iface) { struct in_addr addr; addr.s_addr = htonl(ALL_COAP_NODES_V4); - struct net_if_mcast_addr *mcast_addr = net_if_ipv4_maddr_lookup(&addr, &iface); - if(mcast_addr == NULL) { - OC_DBG("Add IPv4 multicast address on interface with index %d", net_if_get_by_iface(iface)); + struct net_if_mcast_addr *mcast_addr = + net_if_ipv4_maddr_lookup(&addr, &iface); + if (mcast_addr == NULL) { + OC_DBG("Add IPv4 multicast address on interface with index %d", + net_if_get_by_iface(iface)); mcast_addr = net_if_ipv4_maddr_add(iface, &addr); - if(mcast_addr == NULL) { + if (mcast_addr == NULL) { OC_ERR("Failed to add IPv4 multicast address"); return -1; } } - if(!net_if_ipv4_maddr_is_joined(mcast_addr)) { - OC_DBG("Join IPv4 multicast address on interface with index %d", net_if_get_by_iface(iface)); + if (!net_if_ipv4_maddr_is_joined(mcast_addr)) { + OC_DBG("Join IPv4 multicast address on interface with index %d", + net_if_get_by_iface(iface)); net_if_ipv4_maddr_join(mcast_addr); } return 0; @@ -271,60 +274,51 @@ net_if_manage_ipv6_mcast_group(struct net_if *iface) /* Link-local scope */ struct in6_addr addr; memcpy(addr.s6_addr, ALL_OCF_NODES_LL, 16); -// struct net_if_mcast_addr *mcast_addr = net_if_ipv6_maddr_lookup(&addr, &iface); -// if(mcast_addr == NULL) -// { -// OC_ERR("No link-local multicast address on interface with index %d", net_if_get_by_iface(iface)); -// return -1; -// } -// net_if_ipv6_maddr_join(mcast_addr); + // struct net_if_mcast_addr *mcast_addr = net_if_ipv6_maddr_lookup(&addr, + // &iface); if(mcast_addr == NULL) + // { + // OC_ERR("No link-local multicast address on interface with index %d", + // net_if_get_by_iface(iface)); return -1; + // } + // net_if_ipv6_maddr_join(mcast_addr); int ret = net_ipv6_mld_join(iface, &addr); - if (ret == -EALREADY) - { + if (ret == -EALREADY) { return 0; - } - else if (ret < 0) - { + } else if (ret < 0) { OC_ERR("Cannot join link-local IPv6 multicast group (%d)", ret); return -1; } /* Realm-local scope */ memcpy(addr.s6_addr, ALL_OCF_NODES_RL, 16); -// mcast_addr = net_if_ipv6_maddr_lookup(&addr, &iface); -// if(mcast_addr == NULL) -// { -// OC_ERR("No realm-local multicast address on interface with index %d", net_if_get_by_iface(iface)); -// return -1; -// } -// net_if_ipv6_maddr_join(mcast_addr); + // mcast_addr = net_if_ipv6_maddr_lookup(&addr, &iface); + // if(mcast_addr == NULL) + // { + // OC_ERR("No realm-local multicast address on interface with index %d", + // net_if_get_by_iface(iface)); return -1; + // } + // net_if_ipv6_maddr_join(mcast_addr); ret = net_ipv6_mld_join(iface, &addr); - if (ret == -EALREADY) - { + if (ret == -EALREADY) { return 0; - } - else if (ret < 0) - { + } else if (ret < 0) { OC_ERR("Cannot join realm-local IPv6 multicast group (%d)", ret); return -1; } /* Site-local scope */ memcpy(addr.s6_addr, ALL_OCF_NODES_SL, 16); -// mcast_addr = net_if_ipv6_maddr_lookup(&addr, &iface); -// if(mcast_addr == NULL) -// { -// OC_ERR("No site-local multicast address on interface with index %d", net_if_get_by_iface(iface)); -// return -1; -// } -// net_if_ipv6_maddr_join(mcast_addr); + // mcast_addr = net_if_ipv6_maddr_lookup(&addr, &iface); + // if(mcast_addr == NULL) + // { + // OC_ERR("No site-local multicast address on interface with index %d", + // net_if_get_by_iface(iface)); return -1; + // } + // net_if_ipv6_maddr_join(mcast_addr); ret = net_ipv6_mld_join(iface, &addr); - if (ret == -EALREADY) - { + if (ret == -EALREADY) { return 0; - } - else if (ret < 0) - { + } else if (ret < 0) { OC_ERR("Cannot join site-local IPv6 multicast group (%d)", ret); return -1; } @@ -334,14 +328,14 @@ net_if_manage_ipv6_mcast_group(struct net_if *iface) static void configure_mcast_socket_net_if(struct net_if *iface, void *user_data) { - int sa_family = *(int*)user_data; + int sa_family = *(int *)user_data; /* Ignore interfaces that are down */ if (!net_if_is_up(iface)) { return; } /* Ignore interfaces not belonging to the address family under consideration */ - if(sa_family == AF_INET6) { + if (sa_family == AF_INET6) { net_if_manage_ipv6_mcast_group(iface); } #ifdef OC_IPV4 @@ -358,7 +352,8 @@ configure_mcast_socket(int mcast_sock, int sa_family) return 0; } -struct get_interface_addresses_params { +struct get_interface_addresses_params +{ ip_context_t *dev; unsigned char family; uint16_t port; @@ -386,7 +381,7 @@ get_interface_addresses_net_if(struct net_if *iface, void *user_data) ep.addr.ipv4.port = params->port; } else #endif /* OC_IPV4 */ - if (params->family == AF_INET6) { + if (params->family == AF_INET6) { ep.addr.ipv6.port = params->port; } #ifdef OC_TCP @@ -403,14 +398,16 @@ get_interface_addresses_net_if(struct net_if *iface, void *user_data) return; } for (int i = 0; i < NET_IF_MAX_IPV6_ADDR; i++) { - if (!ipv6->unicast[i].is_used || ipv6->unicast[i].address.family != AF_INET6) { + if (!ipv6->unicast[i].is_used || + ipv6->unicast[i].address.family != AF_INET6) { continue; } if (net_ipv6_is_addr_unspecified(&(ipv6->unicast[i].address.in6_addr)) || net_ipv6_is_addr_loopback(&(ipv6->unicast[i].address.in6_addr))) { continue; } - memcpy(ep.addr.ipv6.address, ipv6->unicast[i].address.in6_addr.s6_addr, 16); + memcpy(ep.addr.ipv6.address, ipv6->unicast[i].address.in6_addr.s6_addr, + 16); ep.addr.ipv6.scope = ipv6->unicast[i].address.in6_addr.s6_addr[1]; oc_endpoint_t *new_ep = oc_memb_alloc(&device_eps); if (!new_ep) { @@ -421,8 +418,8 @@ get_interface_addresses_net_if(struct net_if *iface, void *user_data) char buf[IPADDR_BUFF_SIZE]; SNPRINTFipaddr(buf, IPADDR_BUFF_SIZE, ep); OC_DBG("add endpoint: %s, family: %d, if index: %d, secure: %d, tcp: %d", - buf, (int)params->family, ep.interface_index, - (int)params->secure, (int)params->tcp); + buf, (int)params->family, ep.interface_index, (int)params->secure, + (int)params->tcp); #endif /* OC_DEBUG */ oc_list_add(params->dev->eps, new_ep); } @@ -437,7 +434,8 @@ get_interface_addresses_net_if(struct net_if *iface, void *user_data) return; } for (int i = 0; i < NET_IF_MAX_IPV4_ADDR; i++) { - if (!ipv4->unicast[i].is_used || ipv4->unicast[i].address.family != AF_INET) { + if (!ipv4->unicast[i].is_used || + ipv4->unicast[i].address.family != AF_INET) { continue; } if (net_ipv4_is_addr_unspecified(&(ipv4->unicast[i].address.in_addr)) || @@ -454,8 +452,8 @@ get_interface_addresses_net_if(struct net_if *iface, void *user_data) char buf[IPADDR_BUFF_SIZE]; SNPRINTFipaddr(buf, IPADDR_BUFF_SIZE, ep); OC_DBG("add endpoint: %s, family: %d, if index: %d, secure: %d, tcp: %d", - buf, (int)params->family, ep.interface_index, - (int)params->secure, (int)params->tcp); + buf, (int)params->family, ep.interface_index, (int)params->secure, + (int)params->tcp); #endif /* OC_DEBUG */ oc_list_add(params->dev->eps, new_ep); } @@ -468,11 +466,7 @@ get_interface_addresses(ip_context_t *dev, unsigned char family, uint16_t port, bool secure, bool tcp) { struct get_interface_addresses_params params = { - .dev = dev, - .family = family, - .port = port, - .secure = secure, - .tcp = tcp + .dev = dev, .family = family, .port = port, .secure = secure, .tcp = tcp }; net_if_foreach(&get_interface_addresses_net_if, ¶ms); } @@ -593,7 +587,8 @@ recv_msg(int sock, uint8_t *recv_buf, int recv_buf_size, socklen_t client_sockaddr_len; client_sockaddr_len = sizeof(client_sockaddr); - ret = recvfrom(sock, recv_buf, recv_buf_size, 0, &client_sockaddr, &client_sockaddr_len); + ret = recvfrom(sock, recv_buf, recv_buf_size, 0, &client_sockaddr, + &client_sockaddr_len); if (ret < 0) { OC_ERR("recvfrom() failed: %d", errno); return -1; @@ -608,7 +603,8 @@ recv_msg(int sock, uint8_t *recv_buf, int recv_buf_size, endpoint->addr.ipv6.port = ntohs(c6->sin6_port); /* Set receiving network interface index */ struct net_if *iface; - struct net_if_addr* if_addr = net_if_ipv6_addr_lookup(&net_sin6(&server_sockaddr)->sin6_addr, &iface); + struct net_if_addr *if_addr = + net_if_ipv6_addr_lookup(&net_sin6(&server_sockaddr)->sin6_addr, &iface); endpoint->interface_index = net_if_get_by_iface(iface); /* For a unicast receiving socket, extract the interface address * into the endpoint's addr_local attribute. @@ -616,7 +612,8 @@ recv_msg(int sock, uint8_t *recv_buf, int recv_buf_size, * results from this message. */ if (!multicast) { - memcpy(endpoint->addr_local.ipv6.address, if_addr->address.in6_addr.s6_addr, 16); + memcpy(endpoint->addr_local.ipv6.address, + if_addr->address.in6_addr.s6_addr, 16); } else { memset(endpoint->addr_local.ipv6.address, 0, 16); } @@ -630,7 +627,8 @@ recv_msg(int sock, uint8_t *recv_buf, int recv_buf_size, endpoint->addr.ipv6.port = ntohs(c4->sin_port); /* Set receiving network interface index */ struct net_if *iface; - struct net_if_addr* if_addr = net_if_ipv4_addr_lookup(&net_sin(&server_sockaddr)->sin_addr, &iface); + struct net_if_addr *if_addr = + net_if_ipv4_addr_lookup(&net_sin(&server_sockaddr)->sin_addr, &iface); endpoint->interface_index = net_if_get_by_iface(iface); /* For a unicast receiving socket, extract the interface address * into the endpoint's addr_local attribute. @@ -638,7 +636,8 @@ recv_msg(int sock, uint8_t *recv_buf, int recv_buf_size, * results from this message. */ if (!multicast) { - memcpy(endpoint->addr_local.ipv4.address, &if_addr->address.in_addr.s_addr, 4); + memcpy(endpoint->addr_local.ipv4.address, + &if_addr->address.in_addr.s_addr, 4); } else { memset(endpoint->addr_local.ipv4.address, 0, 4); } @@ -789,11 +788,13 @@ network_event_thread(void *data) message->endpoint.device = dev->device; - if (oc_udp_receive_message(dev, &setfds, message) == ADAPTER_STATUS_RECEIVE) { + if (oc_udp_receive_message(dev, &setfds, message) == + ADAPTER_STATUS_RECEIVE) { goto common; } #ifdef OC_TCP - if (oc_tcp_receive_message(dev, &setfds, message) == ADAPTER_STATUS_RECEIVE) { + if (oc_tcp_receive_message(dev, &setfds, message) == + ADAPTER_STATUS_RECEIVE) { goto common; } #endif /* OC_TCP */ @@ -1040,18 +1041,23 @@ connectivity_ipv4_init(ip_context_t *dev) dev->server4_sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); if (dev->server4_sock < 0) { - OC_ERR("Failed to create IPv4 socket for device %zd: %d", dev->device, errno); + OC_ERR("Failed to create IPv4 socket for device %zd: %d", dev->device, + errno); return -1; } - if (bind(dev->server4_sock, (struct sockaddr *)&dev->server4, sizeof(dev->server4)) == -1) { - OC_ERR("Failed to bind the IPv4 socket for device %zd: %d", dev->device, errno); + if (bind(dev->server4_sock, (struct sockaddr *)&dev->server4, + sizeof(dev->server4)) == -1) { + OC_ERR("Failed to bind the IPv4 socket for device %zd: %d", dev->device, + errno); return -1; } socklen_t socklen = sizeof(dev->server4); - if (getsockname(dev->server4_sock, (struct sockaddr *)&dev->server4, &socklen) == -1) { - OC_ERR("Failed to get the IPv4 socket name for device %zd: %d", dev->device, errno); + if (getsockname(dev->server4_sock, (struct sockaddr *)&dev->server4, + &socklen) == -1) { + OC_ERR("Failed to get the IPv4 socket name for device %zd: %d", dev->device, + errno); return -1; } addr = (struct sockaddr_in *)&dev->server4; @@ -1066,23 +1072,30 @@ connectivity_ipv4_init(ip_context_t *dev) dev->mcast4_sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); if (dev->mcast4_sock < 0) { - OC_ERR("Failed to create IPv4 multicast socket for device %zd: %d", dev->device, errno); + OC_ERR("Failed to create IPv4 multicast socket for device %zd: %d", + dev->device, errno); return -1; } int on = 1; - if (setsockopt(dev->mcast4_sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1) { - OC_ERR("Failed to set the reuseaddr option on the IPv4 multicast socket for device %zd: %d", dev->device, errno); + if (setsockopt(dev->mcast4_sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == + -1) { + OC_ERR("Failed to set the reuseaddr option on the IPv4 multicast socket " + "for device %zd: %d", + dev->device, errno); return -1; } - if (bind(dev->mcast4_sock, (struct sockaddr *)&dev->mcast4, sizeof(dev->mcast4)) == -1) { - OC_ERR("Failed to bind the IPv4 multicast socket for device %zd: %d", dev->device, errno); + if (bind(dev->mcast4_sock, (struct sockaddr *)&dev->mcast4, + sizeof(dev->mcast4)) == -1) { + OC_ERR("Failed to bind the IPv4 multicast socket for device %zd: %d", + dev->device, errno); return -1; } if (configure_mcast_socket(dev->mcast4_sock, AF_INET) < 0) { - OC_ERR("Failed to configure the IPv4 multicast socket for device %zd", dev->device); + OC_ERR("Failed to configure the IPv4 multicast socket for device %zd", + dev->device); return -1; } @@ -1096,46 +1109,48 @@ connectivity_ipv4_init(ip_context_t *dev) dev->secure4_sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); if (dev->secure4_sock < 0) { - OC_ERR("Failed to create secure IPv4 socket for device %zd: %d", dev->device, errno); + OC_ERR("Failed to create secure IPv4 socket for device %zd: %d", + dev->device, errno); return -1; } - if (bind(dev->secure4_sock, (struct sockaddr *)&dev->secure4, sizeof(dev->secure4)) == -1) { - OC_ERR("Failed to bind the secure IPv4 socket for device %zd: %d", dev->device, errno); + if (bind(dev->secure4_sock, (struct sockaddr *)&dev->secure4, + sizeof(dev->secure4)) == -1) { + OC_ERR("Failed to bind the secure IPv4 socket for device %zd: %d", + dev->device, errno); return -1; } socklen = sizeof(dev->secure4); - if (getsockname(dev->secure4_sock, (struct sockaddr *)&dev->secure4, &socklen) == -1) { - OC_ERR("Failed to get the secure IPv4 socket name for device %zd: %d", dev->device, errno); + if (getsockname(dev->secure4_sock, (struct sockaddr *)&dev->secure4, + &socklen) == -1) { + OC_ERR("Failed to get the secure IPv4 socket name for device %zd: %d", + dev->device, errno); return -1; } addr = (struct sockaddr_in *)&dev->secure4; dev->dtls4_port = ntohs(addr->sin_port); #endif /* OC_SECURITY */ - OC_DBG("Successfully initialized IPv4 connectivity for device %zd", dev->device); + OC_DBG("Successfully initialized IPv4 connectivity for device %zd", + dev->device); return 0; } #endif static void -net_mgmt_event_if_handler(struct net_mgmt_event_callback *cb, uint32_t mgmt_event, struct net_if *iface) +net_mgmt_event_if_handler(struct net_mgmt_event_callback *cb, + uint32_t mgmt_event, struct net_if *iface) { - switch(mgmt_event) - { - case NET_EVENT_IF_UP: - { + switch (mgmt_event) { + case NET_EVENT_IF_UP: { OC_DBG("event: NET_EVENT_IF_UP"); process_interface_change_event(iface, NETWORK_INTERFACE_UP); - } - break; - case NET_EVENT_IF_DOWN: - { + } break; + case NET_EVENT_IF_DOWN: { OC_DBG("event: NET_EVENT_IF_DOWN"); process_interface_change_event(iface, NETWORK_INTERFACE_DOWN); - } - break; + } break; default: OC_WRN("unhandled event: 0x%x", mgmt_event); break; @@ -1157,7 +1172,9 @@ oc_connectivity_init(size_t device) OC_LIST_STRUCT_INIT(dev, eps); if (pthread_mutex_init(&dev->rfds_mutex, NULL) != 0) { - OC_ERR("Failed to initialize mutex for receive file descriptors for device %zd", dev->device); + OC_ERR( + "Failed to initialize mutex for receive file descriptors for device %zd", + dev->device); oc_abort("Failed to initialize mutex"); } @@ -1180,24 +1197,32 @@ oc_connectivity_init(size_t device) dev->server_sock = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); if (dev->server_sock < 0) { - OC_ERR("Failed to create IPv6 socket for device %zd: %d", dev->device, errno); + OC_ERR("Failed to create IPv6 socket for device %zd: %d", dev->device, + errno); return -1; } int sockopt_on = 1; - if (setsockopt(dev->server_sock, IPPROTO_IPV6, IPV6_V6ONLY, &sockopt_on, sizeof(sockopt_on)) == -1) { - OC_ERR("Failed to set the IPv6 only option on the IPv6 socket for device %zd: %d", dev->device, errno); + if (setsockopt(dev->server_sock, IPPROTO_IPV6, IPV6_V6ONLY, &sockopt_on, + sizeof(sockopt_on)) == -1) { + OC_ERR("Failed to set the IPv6 only option on the IPv6 socket for device " + "%zd: %d", + dev->device, errno); return -1; } - if (bind(dev->server_sock, (struct sockaddr *)&dev->server, sizeof(dev->server)) == -1) { - OC_ERR("Failed to bind the IPv6 socket for device %zd: %d", dev->device, errno); + if (bind(dev->server_sock, (struct sockaddr *)&dev->server, + sizeof(dev->server)) == -1) { + OC_ERR("Failed to bind the IPv6 socket for device %zd: %d", dev->device, + errno); return -1; } socklen_t socklen = sizeof(dev->server); - if (getsockname(dev->server_sock, (struct sockaddr *)&dev->server, &socklen) == -1) { - OC_ERR("Failed to get the IPv6 socket name for device %zd: %d", dev->device, errno); + if (getsockname(dev->server_sock, (struct sockaddr *)&dev->server, + &socklen) == -1) { + OC_ERR("Failed to get the IPv6 socket name for device %zd: %d", dev->device, + errno); return -1; } addr = (struct sockaddr_in6 *)&dev->server; @@ -1212,22 +1237,29 @@ oc_connectivity_init(size_t device) dev->mcast_sock = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); if (dev->server_sock < 0) { - OC_ERR("Failed to create IPv6 multicast socket for device %zd: %d", dev->device, errno); + OC_ERR("Failed to create IPv6 multicast socket for device %zd: %d", + dev->device, errno); return -1; } - if (setsockopt(dev->mcast_sock, SOL_SOCKET, SO_REUSEADDR, &sockopt_on, sizeof(sockopt_on)) == -1) { - OC_ERR("Failed to set the reuseaddr option on the IPv6 multicast socket for device %zd: %d", dev->device, errno); + if (setsockopt(dev->mcast_sock, SOL_SOCKET, SO_REUSEADDR, &sockopt_on, + sizeof(sockopt_on)) == -1) { + OC_ERR("Failed to set the reuseaddr option on the IPv6 multicast socket " + "for device %zd: %d", + dev->device, errno); return -1; } - if (bind(dev->mcast_sock, (struct sockaddr *)&dev->mcast, sizeof(dev->mcast)) == -1) { - OC_ERR("Failed to bind the IPv6 multicast socket for device %zd: %d", dev->device, errno); + if (bind(dev->mcast_sock, (struct sockaddr *)&dev->mcast, + sizeof(dev->mcast)) == -1) { + OC_ERR("Failed to bind the IPv6 multicast socket for device %zd: %d", + dev->device, errno); return -1; } if (configure_mcast_socket(dev->mcast_sock, AF_INET6) < 0) { - OC_ERR("Failed to configure the IPv6 multicast socket for device %zd", dev->device); + OC_ERR("Failed to configure the IPv6 multicast socket for device %zd", + dev->device); return -1; } @@ -1241,23 +1273,31 @@ oc_connectivity_init(size_t device) dev->secure_sock = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); if (dev->secure_sock < 0) { - OC_ERR("Failed to create secure IPv6 socket for device %zd: %d", dev->device, errno); + OC_ERR("Failed to create secure IPv6 socket for device %zd: %d", + dev->device, errno); return -1; } - if (setsockopt(dev->secure_sock, IPPROTO_IPV6, IPV6_V6ONLY, &sockopt_on, sizeof(sockopt_on)) == -1) { - OC_ERR("Failed to set the IPv6 only option on the secure IPv6 socket for device %zd: %d", dev->device, errno); + if (setsockopt(dev->secure_sock, IPPROTO_IPV6, IPV6_V6ONLY, &sockopt_on, + sizeof(sockopt_on)) == -1) { + OC_ERR("Failed to set the IPv6 only option on the secure IPv6 socket for " + "device %zd: %d", + dev->device, errno); return -1; } - if (bind(dev->secure_sock, (struct sockaddr *)&dev->secure, sizeof(dev->secure)) == -1) { - OC_ERR("Failed to bind the secure IPv6 socket for device %zd: %d", dev->device, errno); + if (bind(dev->secure_sock, (struct sockaddr *)&dev->secure, + sizeof(dev->secure)) == -1) { + OC_ERR("Failed to bind the secure IPv6 socket for device %zd: %d", + dev->device, errno); return -1; } socklen = sizeof(dev->secure); - if (getsockname(dev->secure_sock, (struct sockaddr *)&dev->secure, &socklen) == -1) { - OC_ERR("Failed to get the secure IPv6 socket name for device %zd: %d", dev->device, errno); + if (getsockname(dev->secure_sock, (struct sockaddr *)&dev->secure, + &socklen) == -1) { + OC_ERR("Failed to get the secure IPv6 socket name for device %zd: %d", + dev->device, errno); return -1; } addr = (struct sockaddr_in6 *)&dev->secure; @@ -1266,7 +1306,8 @@ oc_connectivity_init(size_t device) #ifdef OC_IPV4 if (connectivity_ipv4_init(dev) != 0) { - OC_ERR("Failed to initialize IPv4 connectivity for device %zd", dev->device); + OC_ERR("Failed to initialize IPv4 connectivity for device %zd", + dev->device); return -1; } #endif /* OC_IPV4 */ @@ -1289,10 +1330,13 @@ oc_connectivity_init(size_t device) } #endif /* OC_TCP */ - /* Register network management event callbacks to listen for network interface changes. + /* Register network management event callbacks to listen for network interface + * changes. */ if (!ifchange_initialized) { - net_mgmt_init_event_callback(&net_mgmt_event_if_cb, net_mgmt_event_if_handler, NET_EVENT_IF_UP | NET_EVENT_IF_DOWN); + net_mgmt_init_event_callback(&net_mgmt_event_if_cb, + net_mgmt_event_if_handler, + NET_EVENT_IF_UP | NET_EVENT_IF_DOWN); net_mgmt_add_event_callback(&net_mgmt_event_if_cb); #ifdef OC_NETWORK_MONITOR if (!check_new_ip_interfaces()) { @@ -1305,17 +1349,25 @@ oc_connectivity_init(size_t device) int ret = pthread_attr_init(&oc_network_thread_attr); if (ret != 0) { - OC_ERR("Failed to initialize network thread for device %zd: pthread_attr_init() failed: %d", dev->device, errno); + OC_ERR("Failed to initialize network thread for device %zd: " + "pthread_attr_init() failed: %d", + dev->device, errno); return -1; } - ret = pthread_attr_setstack(&oc_network_thread_attr, &oc_network_thread_stack, NETWORK_THREAD_STACKSIZE); + ret = pthread_attr_setstack(&oc_network_thread_attr, &oc_network_thread_stack, + NETWORK_THREAD_STACKSIZE); if (ret != 0) { - OC_ERR("Failed to initialize network thread for device %zd: pthread_attr_setstack() failed: %d", dev->device, errno); + OC_ERR("Failed to initialize network thread for device %zd: " + "pthread_attr_setstack() failed: %d", + dev->device, errno); return -1; } - ret = pthread_create(&dev->event_thread, &oc_network_thread_attr, &network_event_thread, dev); + ret = pthread_create(&dev->event_thread, &oc_network_thread_attr, + &network_event_thread, dev); if (ret != 0) { - OC_ERR("Failed to initialize network thread for device %zd: pthread_create() failed: %d", dev->device, errno); + OC_ERR("Failed to initialize network thread for device %zd: " + "pthread_create() failed: %d", + dev->device, errno); return -1; } diff --git a/port/zephyr/src/storage_fs.c b/port/zephyr/src/storage_fs.c index 28341b9d7a..4cb110aece 100644 --- a/port/zephyr/src/storage_fs.c +++ b/port/zephyr/src/storage_fs.c @@ -63,18 +63,18 @@ oc_storage_read(const char *store, uint8_t *buf, size_t size) int rc = fs_open(&file, store_path, FS_O_READ); if (rc < 0) { - LOG_ERR("oc_storage_read: Cannot open %s: %d", store_path, rc); - return -EINVAL; + LOG_ERR("oc_storage_read: Cannot open %s: %d", store_path, rc); + return -EINVAL; } rc = fs_read(&file, buf, size); if (rc < 0) { - LOG_ERR("oc_storage_read: Cannot read %s: %d", store_path, rc); - fs_close(&file); - return -EINVAL; + LOG_ERR("oc_storage_read: Cannot read %s: %d", store_path, rc); + fs_close(&file); + return -EINVAL; } rc = fs_close(&file); if (rc < 0) { - LOG_ERR("oc_storage_read: Cannot close %s: %d", store_path, rc); + LOG_ERR("oc_storage_read: Cannot close %s: %d", store_path, rc); } return size; } @@ -97,18 +97,18 @@ oc_storage_write(const char *store, uint8_t *buf, size_t size) int rc = fs_open(&file, store_path, FS_O_CREATE | FS_O_RDWR); if (rc < 0) { - LOG_ERR("oc_storage_read: Cannot open %s: %d", store_path, rc); - return -EINVAL; + LOG_ERR("oc_storage_read: Cannot open %s: %d", store_path, rc); + return -EINVAL; } rc = fs_write(&file, buf, size); if (rc < 0) { - LOG_ERR("oc_storage_read: Cannot write %s: %d", store_path, rc); - fs_close(&file); - return -EINVAL; + LOG_ERR("oc_storage_read: Cannot write %s: %d", store_path, rc); + fs_close(&file); + return -EINVAL; } rc = fs_close(&file); if (rc < 0) { - LOG_ERR("oc_storage_read: Cannot close %s: %d", store_path, rc); + LOG_ERR("oc_storage_read: Cannot close %s: %d", store_path, rc); } return size; } From e56ef85658575de4d2fe3546d0e02268ced59dd8 Mon Sep 17 00:00:00 2001 From: Martin Roesch Date: Thu, 7 Apr 2022 15:07:46 +0200 Subject: [PATCH 29/30] Add atomic implementation for Zephyr --- util/oc_atomic.h | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/util/oc_atomic.h b/util/oc_atomic.h index 0846d4361d..cf9e84381e 100644 --- a/util/oc_atomic.h +++ b/util/oc_atomic.h @@ -116,6 +116,34 @@ extern "C" { #endif // defined(_WIN32) || defined(_WIN64) +#if defined(__ZEPHYR__) + +#include + +#define OC_ATOMIC +#define OC_ATOMIC_INT8_T atomic_t +#define OC_ATOMIC_UINT8_T atomic_t +#define OC_ATOMIC_INT32_T atomic_t +#define OC_ATOMIC_UINT32_T atomic_t + +#define OC_ATOMIC_LOAD32(x) atomic_get(&(x)) +#define OC_ATOMIC_STORE32(x, val) atomic_set(&(x), (val)) +#define OC_ATOMIC_INCREMENT32(x) atomic_inc(&(x)) +#define OC_ATOMIC_DECREMENT32(x) atomic_dec(&(x)) + +#define OC_ATOMIC_COMPARE_AND_SWAP32(x, expected, desired, result) \ + do { \ + (result) = atomic_cas(&(x), expected, desired); \ + } while (0) + +// aliases for compatibility +#define OC_ATOMIC_LOAD8(x) OC_ATOMIC_LOAD32(x) +#define OC_ATOMIC_STORE8(x, val) OC_ATOMIC_STORE32(x, val) +#define OC_ATOMIC_COMPARE_AND_SWAP8(x, expected, desired, result) \ + OC_ATOMIC_COMPARE_AND_SWAP32(x, expected, desired, result) + +#endif // defined(__ZEPHYR__) + // fallback to volatile on platforms without atomic support #ifndef OC_ATOMIC From d52d1e8caac278d9995271721eb7bfa9972b8ddf Mon Sep 17 00:00:00 2001 From: Martin Roesch Date: Mon, 29 Aug 2022 16:05:37 +0200 Subject: [PATCH 30/30] Add README for zephyr port update. --- port/zephyr/README.md | 293 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 293 insertions(+) create mode 100644 port/zephyr/README.md diff --git a/port/zephyr/README.md b/port/zephyr/README.md new file mode 100644 index 0000000000..af5a655e9e --- /dev/null +++ b/port/zephyr/README.md @@ -0,0 +1,293 @@ +# Usage of Zephyr Port + +## Zephyr application setup + +The iotivity-lite port for Zephyr currently has to be built as +[Third-party Library Code](https://docs.zephyrproject.org/latest/develop/application/index.html#third-party-library-code) +of the [Zephyr application](https://docs.zephyrproject.org/latest/develop/application/index.html). + +Add the iotivity-lite git repository as a sub-directory (e.g. a git submodule) to the Zephyr application structure: + +``` +/app +├── iotivity-lite +├── CMakeLists.txt +├── prj.conf +└── src + └── main.c +``` + +The `app/CMakeLists.txt` needs to add the `iotivity-lite` as a subdirectory to cross-compile it to Zephyr +(the iotivity-lite CMake will detect that it has the zephyr port has to be used and also does some checks +on the Zephyr configuration, e.g. detect whether the zephyr file system is enabled an can be used for storage). + +If needed, the Zephyr application can configure the iotivity-lite build by pre-setting CMake variables that +iotivity-lite uses prior to the `add_subdirectory` command. + +Finally, the Zephyr application then links to one of the `*-static` CMake targets from iotivity-lite. + +For example: + +``` +cmake_minimum_required(VERSION 3.10) + +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) + +project(iotivity_lite_app) + +target_sources(app PRIVATE src/main.c) + +# Configure iotivity-lite build by pre-setting CMake variables +set(BUILD_EXAMPLE_APPLICATIONS OFF CACHE BOOL "Build example applications." FORCE) +set(OC_IDD_API_ENABLED OFF CACHE BOOL "Enable the Introspection Device Data API." FORCE) +set(OC_TCP_ENABLED OFF CACHE BOOL "Enable OCF communications over TCP. Necessary for Cloud communications." FORCE) +set(OC_IPV4_ENABLED ON CACHE BOOL "Enable IPv4 support." FORCE) +#set(OC_DEBUG_ENABLED ON CACHE BOOL "Enable debug messages." FORCE) +set(OC_SECURITY_ENABLED ON CACHE BOOL "Enable security." FORCE) + +# Build iotivity-lite sub-project +add_subdirectory(iotivity-lite) + +# Link iotivity-lite to application +target_link_libraries(app PUBLIC server-static) +``` + +## Zephyr project configuration + +The iotivity-lite build requires some Zephyr modules and project configuration to be present + +### Storage + +iotivity-lite can use either the LittleFS file-system module or the raw flash as storage. + +Note: During the port update only the LittleFS file-system has been tested. The raw flash storage +just has been taken from the previous port without modification and has not been tested. + +The following project configuration snippet sets up the LittleFS file-system module for the application: + +``` +CONFIG_FLASH=y +CONFIG_FLASH_SHELL=y +CONFIG_FLASH_MAP=y +CONFIG_FLASH_MAP_SHELL=y + +CONFIG_FILE_SYSTEM=y +CONFIG_FILE_SYSTEM_LITTLEFS=y +CONFIG_FILE_SYSTEM_SHELL=y +``` + +### Posix + +iotivity-lite requires the posix API with pthread: + +``` +CONFIG_POSIX_API=y +CONFIG_PTHREAD_IPC=y +# increase pthread count (default 5) +# Needed? +CONFIG_MAX_PTHREAD_COUNT=10 +``` + +### Networking + +Currently the networking should be initialized automatically by Zephyr with `CONFIG_NET_CONFIG_AUTO_INIT=y`. +This causes the networking stack to be initialized by Zephyr prior to calling the `main()` function of the +application. + +Also the protocols need to be enabled according to the iotivity-lite build configuration: `CONFIG_NET_UDP, CONFIG_NET_ARP, CONFIG_NET_IPV6, CONFIG_NET_IPV4, CONFIG_NET_IPV4_IGMP, CONFIG_NET_DHCPV4` + +It is required to increase the number of IPv6 multicast addresses to accommodate the iotivity-lite multicast addresses. + +The `ipadapter.c` implementation of the Zephyr port also uses the socket API and network management events, +which need to be enabled with `CONFIG_NET_SOCKETS`, `CONFIG_NET_MGMT`, and `CONFIG_NET_MGMT_EVENT`. + +On the [STM32H747I Discovery Board](https://docs.zephyrproject.org/latest/boards/arm/stm32h747i_disco/doc/index.html) +the port was tested with, the packet buffer sizes needed to be increased as well. + +``` +CONFIG_NETWORKING=y +CONFIG_NET_IPV6=y +CONFIG_NET_IPV4=y +CONFIG_NET_ARP=y +CONFIG_NET_UDP=y +CONFIG_NET_DHCPV4=y +CONFIG_NET_IPV4_IGMP=y + +# Initialize the networking system automatically +CONFIG_NET_CONFIG_SETTINGS=y +CONFIG_NET_CONFIG_AUTO_INIT=y +CONFIG_NET_CONFIG_NEED_IPV4=y + +# increase number of ipv6 multicast addresses (default 3). +# iotivity-lite adds 3 (6 is OC_WKCORE is is defined). +CONFIG_NET_IF_MCAST_IPV6_ADDR_COUNT=5 + +# Increase network packet buffer counts +CONFIG_NET_PKT_RX_COUNT=400 +CONFIG_NET_PKT_TX_COUNT=400 +CONFIG_NET_BUF_RX_COUNT=600 +CONFIG_NET_BUF_TX_COUNT=600 + +CONFIG_NET_MGMT=y +CONFIG_NET_MGMT_EVENT=y + +CONFIG_NET_SOCKETS=y +# Needed? +CONFIG_NET_SOCKETS_POLL_MAX=20 +CONFIG_NET_SOCKETPAIR=y +``` + +## iotivity-lite initialization + +With the iotivity-lite library linked and the Zephyr configuration done, the Zephyr application can use the +iotivity-lite stack like on any other platform and drive the iotivity-lite event loop using Zephyr primitives. + +For example: + +``` +#include +LOG_MODULE_REGISTER(iotivity_lite_example, LOG_LEVEL_DBG); + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +static struct k_sem block; + +FS_LITTLEFS_DECLARE_DEFAULT_CONFIG(storage); +static struct fs_mount_t lfs_storage_mnt = { + .type = FS_LITTLEFS, + .fs_data = &storage, + .storage_dev = (void *)FLASH_AREA_ID(storage), + .mnt_point = "/lfs", +}; + +static void +signal_event_loop(void) +{ + k_sem_give(&block); +} + +static void +register_resources(void) +{ + // Here custom resources can be created during initialization of iotivity-lite +} + +static void +set_device_custom_property(void *data) +{ + (void)data; + oc_set_custom_device_property(snr, "123456"); +} + +static int +app_init(void) +{ + int ret = oc_init_platform("Zephyr", NULL, NULL); + ret |= oc_add_device("/oic/d", + "x.com.zephyr.device", + "Zephyr Board", + "ocf.2.2.5", + "ocf.res.1.3.0,ocf.sh.1.3.0", + set_device_custom_property, NULL); + return ret; +} + +void main(void) +{ + int rc; + struct fs_mount_t *mp = &lfs_storage_mnt; + unsigned int id = (uintptr_t)mp->storage_dev; + const struct flash_area *pfa; + struct fs_statvfs sbuf; + + static const oc_handler_t handler = { + .init = app_init, + .signal_event_loop = signal_event_loop, + .register_resources = register_resources + }; + + k_sem_init(&block, 0, 1); + + LOG_INF("Mount LittleFS partition"); + rc = flash_area_open(id, &pfa); + if (rc < 0) { + LOG_ERR("FAIL: unable to find flash area %u: %d", id, rc); + return; + } + LOG_INF("Flash area %u at 0x%x on %s for %u bytes", + id, (unsigned int)pfa->fa_off, pfa->fa_dev_name, + (unsigned int)pfa->fa_size); + flash_area_close(pfa); + + rc = fs_mount(mp); + if (rc < 0) { + LOG_ERR("FAIL: mount id %" PRIuPTR " at %s: %d", + (uintptr_t)mp->storage_dev, mp->mnt_point, rc); + return; + } + LOG_INF("%s mount: %d", mp->mnt_point, rc); + + rc = fs_statvfs(mp->mnt_point, &sbuf); + if (rc < 0) { + LOG_ERR("FAIL: statvfs: %d", rc); + goto out; + } + + LOG_INF("%s: bsize = %lu; frsize = %lu; blocks = %lu ; bfree = %lu", + mp->mnt_point, + sbuf.f_bsize, sbuf.f_frsize, + sbuf.f_blocks, sbuf.f_bfree); + +#ifdef OC_STORAGE + oc_storage_config(lfs_storage_mnt.mnt_point); +#endif + if (oc_main_init(&handler) < 0) { + LOG_ERR("iotivity-lite initialization failed!"); + goto out; + } + + // Run iotivity-lite event loop + oc_clock_time_t next_event; + k_timeout_t k_tmo; + + while (true) { + next_event = oc_main_poll(); + if (next_event == 0) + next_event = K_FOREVER.ticks; + else + next_event -= oc_clock_time(); + k_tmo.ticks = next_event; + k_sem_take(&block, k_tmo); + } + + oc_main_shutdown(); +out: + rc = fs_unmount(mp); + LOG_INF("%s unmount: %d", mp->mnt_point, rc); +} +``` + +## Build Zephyr application + +With this setup, the Zephyr application including the iotivity-lite stack can be built using the +[Zephyr Toolchain](https://docs.zephyrproject.org/latest/develop/application/index.html#building-an-application). + +For example using `west`: +``` +cd /app +west build -b +``` \ No newline at end of file