Skip to content

Commit

Permalink
Improve monitoring of DTLS peers' activity using monotonic timer
Browse files Browse the repository at this point in the history
The previous implementation of monitoring DTLS peers' activity relied
on the absolute system time to track the last activity timestamp.
However, this approach had the unintended consequence of being
affected by changes in the system time. For instance, modifying
the system time by an interval equivalent to the DTLS inactivity
timeout would trigger a false inactivity timeout and result in
the closure of the DTLS session.

To address this issue, the monitoring mechanism has been updated
to utilize a monotonic timer. This timer is independent of
system time changes and provides a more accurate measure of
the duration of inactivity. By using a monotonic timer, the DTLS
session will only be closed if no activity occurs within the
specified timeout period, regardless of any changes in
the system time.

This refactor improves the reliability and accuracy of DTLS peer
monitoring, ensuring that the DTLS sessions are closed based on
actual inactivity rather than being influenced by system time
adjustments.
  • Loading branch information
Danielius1922 authored and Daniel Adam committed May 25, 2023
1 parent b2fae09 commit 051b52c
Show file tree
Hide file tree
Showing 25 changed files with 934 additions and 200 deletions.
15 changes: 11 additions & 4 deletions .github/workflows/cmake-linux.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,8 @@ jobs:
# ipv4 on, tcp on, pki off
- args: "-DOC_IPV4_ENABLED=ON -DOC_TCP_ENABLED=ON -DOC_PKI_ENABLED=OFF"
# cloud on (ipv4+tcp on), collections create on, maintenance resource on
- args: "-DOC_CLOUD_ENABLED=ON -DOC_COLLECTIONS_IF_CREATE_ENABLED=ON "
# debug on, well-known core resource on
- args: "-DOC_CLOUD_ENABLED=ON -DOC_COLLECTIONS_IF_CREATE_ENABLED=ON"
# debug on
- args: "-DOC_DEBUG_ENABLED=ON"
# debug on, cloud on (ipv4+tcp on)
- args: "-DOC_CLOUD_ENABLED=ON -DOC_DEBUG_ENABLED=ON "
Expand All @@ -60,8 +60,8 @@ jobs:
- args: "-DOC_SECURITY_ENABLED=OFF -DOC_TCP_ENABLED=ON"
# secure off, ipv4 on, tcp on
- args: "-DOC_SECURITY_ENABLED=OFF -DOC_TCP_ENABLED=ON -DOC_IPV4_ENABLED=ON"
# collection create if on, push notification on
- args: "-DOC_COLLECTIONS_IF_CREATE_ENABLED=ON"
# /oic/res observable on, rep realloc on
- args: "-DOC_DISCOVERY_RESOURCE_OBSERVABLE_ENABLED=ON -DOC_REPRESENTATION_REALLOC_ENCODING_ENABLED=ON"
# everything off (dynamic allocation off, secure off, pki off, idd off, oscore off, well-known core resource off, software update off, push notifications off, plgd-time off)
- args: "-DOC_DYNAMIC_ALLOCATION_ENABLED=OFF -DOC_SECURITY_ENABLED=OFF -DOC_PKI_ENABLED=OFF -DOC_IDD_API_ENABLED=OFF -DOC_OSCORE_ENABLED=OFF -DOC_WKCORE_ENABLED=OFF -DOC_SOFTWARE_UPDATE_ENABLED=OFF -DOC_MNT_ENABLED=OFF -DOC_PUSH_ENABLED=OFF -DPLGD_DEV_TIME_ENABLED=OFF"
uses: ./.github/workflows/unit-test-with-cfg.yml
Expand Down Expand Up @@ -91,14 +91,20 @@ jobs:
include:
# address sanitizer
- args: -DOC_ASAN_ENABLED=ON
install_faketime: true
# leak sanitizer
- args: -DOC_LSAN_ENABLED=ON
# there is some linker issue when LSAN and faketime are used together
install_faketime: false
# thread sanitizer
- args: -DOC_TSAN_ENABLED=ON
install_faketime: true
# undefined behaviour sanitizer
- args: -DOC_UBSAN_ENABLED=ON
install_faketime: true
# TODO: update gtest
# - args: -DOC_MSAN_ENABLED=ON
# install_faketime: true
uses: ./.github/workflows/unit-test-with-cfg.yml
with:
build_args: -DOC_CLOUD_ENABLED=ON -DOC_COLLECTIONS_IF_CREATE_ENABLED=ON -DOC_MNT_ENABLED=ON -DOC_WKCORE_ENABLED=ON -DOC_SOFTWARE_UPDATE_ENABLED=ON -DOC_PUSH_ENABLED=ON -DOC_RESOURCE_ACCESS_IN_RFOTM_ENABLED=ON -DPLGD_DEV_TIME_ENABLED=ON ${{ matrix.args }}
Expand All @@ -107,3 +113,4 @@ jobs:
coverage: false
install_mbedtls: ${{ github.event_name == 'workflow_dispatch' && inputs.install_mbedtls }}
install_tinycbor: ${{ github.event_name == 'workflow_dispatch' && inputs.install_tinycbor }}
install_faketime: ${{ matrix.install_faketime }}
11 changes: 7 additions & 4 deletions .github/workflows/sonar-cloud-analysis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,13 @@ jobs:
fail-fast: false
matrix:
include:
# cloud (ipv4+tcp) on, collection create on, push on, rfotm on
- build_args: "-DOC_CLOUD_ENABLED=ON -DOC_COLLECTIONS_IF_CREATE_ENABLED=ON -DOC_PUSH_ENABLED=ON -DOC_RESOURCE_ACCESS_IN_RFOTM_ENABLED=ON"
# dynamic allocation off
- build_args: "-DOC_DYNAMIC_ALLOCATION_ENABLED=OFF -DOC_RESOURCE_ACCESS_IN_RFOTM_ENABLED=ON"
# security off
# ipv6 dns on, oscore off, rep realloc on
- build_args: "-DOC_DNS_LOOKUP_IPV6_ENABLED=ON -DOC_OSCORE_ENABLED=OFF -DOC_REP_ENCODING_REALLOC=ON"
# ipv4 on, tcp on, dynamic allocation off, rfotm on
- build_args: "-DOC_IPV4_ENABLED=ON -DOC_TCP_ENABLED=ON -DOC_DYNAMIC_ALLOCATION_ENABLED=OFF -DOC_RESOURCE_ACCESS_IN_RFOTM_ENABLED=ON"
# security off, cloud (ipv4+tcp), collection create on, push on
- build_args: "-DOC_SECURITY_ENABLED=OFF -DOC_CLOUD_ENABLED=ON -DOC_COLLECTIONS_IF_CREATE_ENABLED=ON -DOC_PUSH_ENABLED=ON"

uses: ./.github/workflows/unit-test-with-cfg.yml
Expand All @@ -37,7 +40,7 @@ jobs:
uses: ./.github/workflows/plgd-device-test-with-cfg.yml
with:
name: cloud-server
build_args: "-DOC_COLLECTIONS_IF_CREATE_ENABLED=ON -DOC_MNT_ENABLED=ON -DOC_OSCORE_ENABLED=OFF -DOC_COVERAGE_ENABLED=ON -DPLGD_DEV_TIME_ENABLED=ON"
build_args: "-DOC_COLLECTIONS_IF_CREATE_ENABLED=ON -DOC_MNT_ENABLED=ON -DOC_OSCORE_ENABLED=OFF -DPLGD_DEV_TIME_ENABLED=ON -DOC_COVERAGE_ENABLED=ON "
build_type: Debug
# try with SHA384
cert_signature_algorithm: ECDSA-SHA384
Expand Down
19 changes: 18 additions & 1 deletion .github/workflows/unit-test-with-cfg.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ on:
type: boolean
required: false
default: false
install_faketime:
type: boolean
required: false
default: true
install_mbedtls:
type: boolean
required: false
Expand All @@ -47,11 +51,24 @@ jobs:
run: |
echo compiler='-DCMAKE_CXX_COMPILER=clang++ -DCMAKE_C_COMPILER=clang' >> $GITHUB_OUTPUT
- name: Checkout libfaketime
uses: actions/checkout@v3
with:
repository: wolfcw/libfaketime
path: libfaketime

- name: Install libfaketime
if: ${{ inputs.install_faketime }}
working-directory: libfaketime
run: |
make FAKETIME_COMPILE_CFLAGS="-DFAKE_SETTIME"
sudo make install
- name: Install mbedTLS
if: ${{ inputs.install_mbedtls }}
run: |
mkdir build_mbedtls && cd build_mbedtls
cmake -DCMAKE_VERBOSE_MAKEFILE=ON -DCMAKE_BUILD_TYPE=${{ inputs.build_type }} ${{ steps.cmake_flags.outputs.compiler }} ${{ inputs.build_args }} -DBUILD_TESTING=OFF ..
cmake -DCMAKE_VERBOSE_MAKEFILE=ON -DCMAKE_BUILD_TYPE=${{ inputs.build_type }} ${{ steps.cmake_flags.outputs.compiler }} ${{ inputs.build_args }} -DBUILD_TESTING=ON ..
OC_SECURITY_ENABLED=$(cmake -LA -N . | grep OC_SECURITY_ENABLED | cut -d "=" -f2)
if [ "${OC_SECURITY_ENABLED}" = "ON" ]; then
make mbedtls mbedx509 mbedcrypto
Expand Down
87 changes: 64 additions & 23 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -255,8 +255,9 @@ elseif(OC_LOG_MAXIMUM_LOG_LEVEL STREQUAL "TRACE")
else()
message(FATAL_ERROR "Invalid OC_LOG_MAXIMUM_LOG_LEVEL: ${OC_LOG_MAXIMUM_LOG_LEVEL}")
endif()
list(APPEND PRIVATE_COMPILE_DEFINITIONS "OC_LOG_MAXIMUM_LEVEL=${OC_LOG_MAXIMUM_LEVEL}")
list(APPEND TEST_COMPILE_DEFINITIONS "OC_LOG_MAXIMUM_LEVEL=${OC_LOG_MAXIMUM_LEVEL}")
# clang-tidy triggers bugprone-macro-parentheses if the value is not in ()
list(APPEND PRIVATE_COMPILE_DEFINITIONS "OC_LOG_MAXIMUM_LEVEL=(${OC_LOG_MAXIMUM_LEVEL})")
list(APPEND TEST_COMPILE_DEFINITIONS "OC_LOG_MAXIMUM_LEVEL=(${OC_LOG_MAXIMUM_LEVEL})")

if(OC_PUSH_ENABLED)
list(APPEND PUBLIC_COMPILE_DEFINITIONS "OC_PUSH")
Expand Down Expand Up @@ -833,59 +834,67 @@ if(BUILD_TESTING AND(UNIX OR MINGW))

set(OC_UNITTESTS)
# Helper macro to build unit test
macro(package_add_test TESTNAME)
add_executable(${TESTNAME} ${ARGN})
target_compile_options(${TESTNAME} PRIVATE ${TEST_COMPILE_OPTIONS})
target_compile_features(${TESTNAME} PRIVATE cxx_nullptr)
target_compile_definitions(${TESTNAME} PRIVATE ${PUBLIC_COMPILE_DEFINITIONS} ${TEST_COMPILE_DEFINITIONS})
target_include_directories(${TESTNAME} SYSTEM PRIVATE ${PROJECT_SOURCE_DIR}/deps/gtest/include)
target_include_directories(${TESTNAME} PRIVATE
macro(oc_package_add_test)
set(options)
set(oneValueArgs TARGET)
set(multiValueArgs ENVIRONMENT SOURCES)
cmake_parse_arguments(OC_PACKAGE_ADD_TEST "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})

add_executable(${OC_PACKAGE_ADD_TEST_TARGET} ${OC_PACKAGE_ADD_TEST_SOURCES})
target_compile_options(${OC_PACKAGE_ADD_TEST_TARGET} PRIVATE ${TEST_COMPILE_OPTIONS})
target_compile_definitions(${OC_PACKAGE_ADD_TEST_TARGET} PRIVATE ${PUBLIC_COMPILE_DEFINITIONS} ${TEST_COMPILE_DEFINITIONS})
target_include_directories(${OC_PACKAGE_ADD_TEST_TARGET} SYSTEM PRIVATE ${PROJECT_SOURCE_DIR}/deps/gtest/include)
target_include_directories(${OC_PACKAGE_ADD_TEST_TARGET} PRIVATE
${PROJECT_SOURCE_DIR}
${PROJECT_SOURCE_DIR}/include
${PORT_INCLUDE_DIR}
${PROJECT_SOURCE_DIR}/messaging/coap
)

if(OC_SECURITY_ENABLED)
target_include_directories(${TESTNAME} PRIVATE
target_include_directories(${OC_PACKAGE_ADD_TEST_TARGET} PRIVATE
${PROJECT_SOURCE_DIR}/security
)
endif()

if(OC_CLOUD_ENABLED)
target_include_directories(${TESTNAME} PRIVATE ${PROJECT_SOURCE_DIR}/api/cloud)
target_include_directories(${OC_PACKAGE_ADD_TEST_TARGET} PRIVATE ${PROJECT_SOURCE_DIR}/api/cloud)
endif()

target_link_libraries(${TESTNAME} PRIVATE ${TEST_LINK_LIBS})
target_link_libraries(${OC_PACKAGE_ADD_TEST_TARGET} PRIVATE ${TEST_LINK_LIBS})
if(OC_COMPILER_IS_GCC OR OC_COMPILER_IS_CLANG)
target_link_libraries(${TESTNAME} PRIVATE "-Wl,--unresolved-symbols=ignore-in-shared-libs")
target_link_libraries(${OC_PACKAGE_ADD_TEST_TARGET} PRIVATE "-Wl,--unresolved-symbols=ignore-in-shared-libs")
endif()
add_test(NAME ${TESTNAME} COMMAND ${TESTNAME})
set_target_properties(${TESTNAME} PROPERTIES FOLDER unittests)
set_tests_properties(${TESTNAME} PROPERTIES LABELS oc-unittest)
add_test(NAME ${OC_PACKAGE_ADD_TEST_TARGET} COMMAND ${OC_PACKAGE_ADD_TEST_TARGET})

list(APPEND OC_UNITTESTS ${TESTNAME})
set_property(TEST ${OC_PACKAGE_ADD_TEST_TARGET} PROPERTY FOLDER unittests)
set_property(TEST ${OC_PACKAGE_ADD_TEST_TARGET} PROPERTY LABELS oc-unittest)
if (OC_PACKAGE_ADD_TEST_ENVIRONMENT)
set_property(TEST ${OC_PACKAGE_ADD_TEST_TARGET} PROPERTY ENVIRONMENT "${OC_PACKAGE_ADD_TEST_ENVIRONMENT}")
endif()

list(APPEND OC_UNITTESTS ${OC_PACKAGE_ADD_TEST_TARGET})
endmacro()

file(GLOB COMMONTEST_SRC tests/gtest/*.cpp tests/gtest/tls/*.cpp)

# Unit tests
file(GLOB APITEST_SRC api/unittest/*.cpp api/client/unittest/*.cpp)
package_add_test(apitest ${COMMONTEST_SRC} ${APITEST_SRC})
oc_package_add_test(TARGET apitest SOURCES ${COMMONTEST_SRC} ${APITEST_SRC})

file(GLOB TIMESTAMPTEST_SRC api/c-timestamp/unittest/*.cpp)
package_add_test(timestamptest ${TIMESTAMPTEST_SRC})
oc_package_add_test(TARGET timestamptest SOURCES ${TIMESTAMPTEST_SRC})

file(GLOB PLATFORMTEST_SRC port/unittest/*.cpp)
file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/storage_test)
package_add_test(platformtest ${COMMONTEST_SRC} ${PLATFORMTEST_SRC})
oc_package_add_test(TARGET platformtest SOURCES ${COMMONTEST_SRC} ${PLATFORMTEST_SRC})

file(GLOB MESSAGINGTEST_SRC messaging/coap/unittest/*.cpp)
package_add_test(messagingtest ${MESSAGINGTEST_SRC})
oc_package_add_test(TARGET messagingtest SOURCES ${MESSAGINGTEST_SRC})

if(OC_SECURITY_ENABLED)
file(GLOB SECURITYTEST_SRC security/unittest/*.cpp)
package_add_test(securitytest ${COMMONTEST_SRC} ${SECURITYTEST_SRC})
oc_package_add_test(TARGET securitytest SOURCES ${COMMONTEST_SRC} ${SECURITYTEST_SRC})

file(COPY ${PROJECT_SOURCE_DIR}/apps/pki_certs
DESTINATION ${CMAKE_CURRENT_BINARY_DIR}
Expand All @@ -896,7 +905,39 @@ if(BUILD_TESTING AND(UNIX OR MINGW))
if(OC_CLOUD_ENABLED)
file(GLOB CLOUDTEST_SRC api/cloud/unittest/*.cpp)
file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/storage_cloud)
package_add_test(cloudtest ${COMMONTEST_SRC} ${CLOUDTEST_SRC})
oc_package_add_test(TARGET cloudtest SOURCES ${COMMONTEST_SRC} ${CLOUDTEST_SRC})
endif()

if(UNIX)
# install https://github.com/wolfcw/libfaketime for this test suit to run
find_library(FAKETIME_LIBRARY
NAMES libfaketimeMT.so.1
PATH_SUFFIXES faketime
)
if (FAKETIME_LIBRARY)
file(GLOB FAKETIMETEST_SRC tests/libfaketime/unittest/*.cpp)
oc_package_add_test(
TARGET faketimetest
SOURCES ${COMMONTEST_SRC} ${FAKETIMETEST_SRC}
ENVIRONMENT "ASAN_OPTIONS=verify_asan_link_order=0"
"LD_PRELOAD=/usr/local/lib/faketime/libfaketimeMT.so.1"
"FAKETIME_DONT_FAKE_MONOTONIC=1"
"FAKETIME_TIMESTAMP_FILE="
"FAKETIME_UPDATE_TIMESTAMP_FILE="
"FAKETIME_DONT_RESET="
"FAKETIME_NO_CACHE="
"FAKETIME_CACHE_DURATION="
)
target_link_libraries(faketimetest PRIVATE ${FAKETIME_LIBRARY})
endif()
endif()

if(OC_FAKETIMETEST_FORCED)
file(GLOB FAKETIMETEST_SRC tests/libfaketime/unittest/*.cpp)
oc_package_add_test(
TARGET faketimetest
SOURCES ${COMMONTEST_SRC} ${FAKETIMETEST_SRC}
)
endif()

add_custom_target(
Expand Down
10 changes: 5 additions & 5 deletions api/oc_endpoint.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,10 @@

#define OC_IPV6_ADDRLEN (16)
#define OC_IPV4_ADDRLEN (4)
// IPv6 address + 3 ('[',']' and ':') + 5 (uint16_t for port)
#define OC_IPV6_MINSTRLEN (OC_IPV6_ADDRSTRLEN + 8)
// IPv4 address + 1 (':') + 5 (uint16_t for port)
#define OC_IPV4_MINSTRLEN (OC_IPV4_ADDRSTRLEN + 6)
// Max. IPv6 address + 3 ('[',']' and ':') + 5 (uint16_t for port)
#define OC_IPV6_MAXSTRLEN (OC_IPV6_MAXADDRSTRLEN + 8)
// Max. IPv4 address + 1 (':') + 5 (uint16_t for port)
#define OC_IPV4_MAXSTRLEN (OC_IPV4_MAXADDRSTRLEN + 6)

OC_MEMB(oc_endpoints_s, oc_endpoint_t, OC_MAX_NUM_ENDPOINTS);

Expand Down Expand Up @@ -121,7 +121,7 @@ oc_endpoint_to_string(const oc_endpoint_t *endpoint, oc_string_t *endpoint_str)
return -1;
}

char ip[OC_IPV6_MINSTRLEN] = { 0 };
char ip[OC_IPV6_MAXSTRLEN] = { 0 };
if (oc_endpoint_to_cstring(endpoint, ip, OC_ARRAY_SIZE(ip)) != 0) {
return -1;
}
Expand Down
6 changes: 4 additions & 2 deletions api/oc_endpoint_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,10 @@
extern "C" {
#endif

#define OC_IPV6_ADDRSTRLEN (46)
#define OC_IPV4_ADDRSTRLEN (16)
// maximal length of a valid IPv6 address
#define OC_IPV6_MAXADDRSTRLEN (46)
// maximal length of a valid IPv4 address
#define OC_IPV4_MAXADDRSTRLEN (16)

#define OC_SCHEME_COAP "coap://"
#define OC_SCHEME_COAPS "coaps://"
Expand Down
19 changes: 11 additions & 8 deletions api/oc_uuid.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

#include "oc_uuid.h"
#include "port/oc_random.h"
#include "util/oc_macros.h"
#include <ctype.h>
#include <stdint.h>
#include <stdio.h>
Expand Down Expand Up @@ -71,33 +72,35 @@ oc_str_to_uuid(const char *str, oc_uuid_t *uuid)
c |= 0x0f;
break;
}
} else
} else {
c |= str[i] - 48;
}
if ((j + 1) * 2 == k) {
uuid->id[j++] = c;
c = 0;
} else
} else {
c = c << 4;
}
k++;
}
}

void
oc_uuid_to_str(const oc_uuid_t *uuid, char *buffer, size_t buflen)
{
int i, j = 0;
if (buflen < OC_UUID_LEN || !uuid)
if (buflen < OC_UUID_LEN || !uuid) {
return;
}
if (uuid->id[0] == '*') {
uint8_t zeros[15] = { 0 };
if (memcmp(&uuid->id[1], zeros, 15) == 0) {
uint8_t zeros[OC_ARRAY_SIZE(uuid->id) - 1] = { 0 };
if (memcmp(&uuid->id[1], zeros, OC_ARRAY_SIZE(zeros)) == 0) {
memset(buffer, 0, buflen);
buffer[0] = '*';
buffer[1] = '\0';
return;
}
}
for (i = 0; i < 16; i++) {
for (size_t i = 0, j = 0; i < OC_ARRAY_SIZE(uuid->id); ++i) {
switch (i) {
case 4:
case 6:
Expand All @@ -119,7 +122,7 @@ oc_gen_uuid(oc_uuid_t *uuid)

for (unsigned i = 0; i < 4; i++) {
r = oc_random_value();
memcpy((uint8_t *)&uuid->id[i * 4UL], (uint8_t *)&r, sizeof(r));
memcpy(&uuid->id[i * 4UL], (uint8_t *)&r, sizeof(r));
}

/* From RFC 4122
Expand Down
5 changes: 5 additions & 0 deletions api/unittest/buffertest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
#include "api/oc_ri_internal.h"
#include "oc_buffer.h"
#include "oc_config.h"
#include "port/oc_network_event_handler_internal.h"
#include "util/oc_features.h"
#include "util/oc_memb.h"
#include "util/oc_process_internal.h"

Expand All @@ -39,8 +41,11 @@ class TestMessage : public testing::Test {
oc_memb_init(&oc_test_messages);
oc_set_buffers_avail_cb(onIncomingBufferAvailable);
oc_memb_set_buffers_avail_cb(&oc_test_messages, onTestBufferAvailable);
oc_network_event_handler_mutex_init();
}

static void TearDownTestCase() { oc_network_event_handler_mutex_destroy(); }

void SetUp() override
{
incomingBufferAvailableCount_ = -1;
Expand Down
Loading

0 comments on commit 051b52c

Please sign in to comment.