From 2a9d523ec542ea346d290a6ddaaebb28e116b350 Mon Sep 17 00:00:00 2001 From: sp-milos Date: Mon, 20 May 2024 08:04:51 +0000 Subject: [PATCH 01/35] Issue 626: Implement Message Queue Limit to Prevent Memory Exhaustion in Embedded Devices. --- api/oc_network_events.c | 9 ++++++ api/oc_network_events_internal.h | 5 +++ port/linux/ipadapter.c | 53 ++++++++++++++++++++++++++++++-- port/linux/oc_config.h | 7 +++-- 4 files changed, 70 insertions(+), 4 deletions(-) diff --git a/api/oc_network_events.c b/api/oc_network_events.c index 9509126c37..85ffcd7550 100644 --- a/api/oc_network_events.c +++ b/api/oc_network_events.c @@ -204,3 +204,12 @@ oc_network_interface_event(oc_interface_event_t event) _oc_signal_event_loop(); } #endif /* OC_NETWORK_MONITOR */ + +int +oc_get_network_events_queue_length(void) +{ + oc_network_event_handler_mutex_lock(); + int length = oc_list_length(g_network_events); + oc_network_event_handler_mutex_unlock(); + return length; +} diff --git a/api/oc_network_events_internal.h b/api/oc_network_events_internal.h index 9f5eef3b4f..dbb7b9ca0a 100644 --- a/api/oc_network_events_internal.h +++ b/api/oc_network_events_internal.h @@ -78,6 +78,11 @@ typedef struct oc_network_interface_cb void oc_network_interface_event(oc_interface_event_t event); #endif /* OC_NETWORK_MONITOR */ +/** + * @brief returns the length of network events queue + */ +int oc_get_network_events_queue_length(void); + #ifdef __cplusplus } #endif diff --git a/port/linux/ipadapter.c b/port/linux/ipadapter.c index 646fdec057..54a5fbdd5a 100644 --- a/port/linux/ipadapter.c +++ b/port/linux/ipadapter.c @@ -36,6 +36,7 @@ #include "port/oc_fcntl_internal.h" #include "port/oc_log_internal.h" #include "port/oc_network_event_handler_internal.h" +#include "port/oc_random.h" #include "util/oc_atomic.h" #include "util/oc_features.h" #include "util/oc_macros_internal.h" @@ -868,6 +869,8 @@ process_event(ip_context_t *dev, fd_set *rdfds, fd_set *wfds) if (ret != 0) { return ret; } + + // TODO: No return value here?! } if (wfds != NULL) { @@ -933,11 +936,52 @@ to_timeval(oc_clock_time_t ticks) } #endif /* OC_HAS_FEATURE_TCP_ASYNC_CONNECT */ +#ifdef OC_DYNAMIC_ALLOCATION +static bool +optimize_rfds(fd_set *output_set, const fd_set *rfd_set, int rfd_count) +{ + if (oc_get_network_events_queue_length() >= OC_MAX_NUM_CONCURRENT_REQUESTS) { + for (int i = 0; i < FD_SETSIZE; i++) { + if (FD_ISSET(i, rfd_set)) { + FD_CLR(i, output_set); + } + } + return true; + } + + int random_rfd = oc_random_value() % rfd_count; + for (int i = 0; i < FD_SETSIZE; i++) { + if (FD_ISSET(i, rfd_set)) { + if (rfd_count != random_rfd) { + FD_CLR(i, output_set); + } + } + } + return false; +} +#endif /* OC_DYNAMIC_ALLOCATION */ + static void * network_event_thread(void *data) { ip_context_t *dev = (ip_context_t *)data; FD_ZERO(&dev->rfds); + udp_add_socks_to_rfd_set(dev); + +#ifdef OC_DYNAMIC_ALLOCATION + struct timeval queue_timeout; + queue_timeout.tv_sec = 0; + queue_timeout.tv_usec = 1000; + + fd_set rfd_set = ip_context_rfds_fd_copy(dev); + int rfd_count = 0; + for (int i = 0; i < FD_SETSIZE; i++) { + if (FD_ISSET(i, &rfd_set)) { + rfd_count++; + } + } +#endif /* OC_DYNAMIC_ALLOCATION */ + /* Monitor network interface changes on the platform from only the 0th * logical device */ @@ -946,7 +990,6 @@ network_event_thread(void *data) } FD_SET(dev->shutdown_pipe[0], &dev->rfds); - udp_add_socks_to_rfd_set(dev); #ifdef OC_TCP tcp_add_socks_to_rfd_set(dev); #endif /* OC_TCP */ @@ -957,6 +1000,12 @@ network_event_thread(void *data) while (OC_ATOMIC_LOAD8(dev->terminate) != 1) { struct timeval *timeout = NULL; fd_set rdfds = ip_context_rfds_fd_copy(dev); +#ifdef OC_DYNAMIC_ALLOCATION + bool use_timeout = optimize_rfds(&rdfds, &rfd_set, rfd_count); +#else + bool use_timeout = false; +#endif /* OC_DYNAMIC_ALLOCATION */ + fd_set *wfds = NULL; #ifdef OC_HAS_FEATURE_TCP_ASYNC_CONNECT fd_set write_fds = tcp_context_cfds_fd_copy(&dev->tcp); @@ -969,7 +1018,7 @@ network_event_thread(void *data) (unsigned)tv.tv_usec); } #endif /* OC_HAS_FEATURE_TCP_ASYNC_CONNECT */ - int n = select(FD_SETSIZE, &rdfds, wfds, NULL, timeout); + int n = select(FD_SETSIZE, &rdfds, wfds, NULL, use_timeout ? &queue_timeout : timeout); if (FD_ISSET(dev->shutdown_pipe[0], &rdfds)) { process_shutdown(dev); diff --git a/port/linux/oc_config.h b/port/linux/oc_config.h index f9e495fcf8..441109d596 100644 --- a/port/linux/oc_config.h +++ b/port/linux/oc_config.h @@ -69,6 +69,9 @@ typedef uint64_t oc_clock_time_t; * with REP_ENCODING_REALLOC=1 */ // #define OC_REP_ENCODING_REALLOC +/* Maximum number of messages in the network event queue */ +#define OC_MAX_NUM_CONCURRENT_REQUESTS (32) + #else /* OC_DYNAMIC_ALLOCATION */ /* List of constraints below for a build that does not employ dynamic memory allocation @@ -123,10 +126,10 @@ typedef uint64_t oc_clock_time_t; /* Maximum number of callbacks for connection of session */ #define OC_MAX_SESSION_EVENT_CBS (2) -/* Maximal number of callbacks for ownership status changes */ +/* Maximum number of callbacks for ownership status changes */ #define OC_MAX_DOXM_OWNED_CBS (2) -/* Maximal number of callbacks invoked before a dynamic resource is deleted */ +/* Maximum number of callbacks invoked before a dynamic resource is deleted */ #define OC_MAX_ON_DELETE_RESOURCE_CBS (2) #endif /* !OC_DYNAMIC_ALLOCATION */ From 00bcf013f92167ab275ff08dd69ec2ca06360878 Mon Sep 17 00:00:00 2001 From: sp-martin Date: Tue, 28 May 2024 20:56:12 +0000 Subject: [PATCH 02/35] - block event processing when the network event queue is full - signal when the event queue is ready to process events again. - separate processing of control flow and read file desriptors - random pick slection and processing of network event --- api/oc_network_events.c | 18 ++- port/linux/ipadapter.c | 217 ++++++++++++++++++++------------ port/oc_connectivity_internal.h | 21 ++++ 3 files changed, 172 insertions(+), 84 deletions(-) diff --git a/api/oc_network_events.c b/api/oc_network_events.c index 85ffcd7550..8195b7af12 100644 --- a/api/oc_network_events.c +++ b/api/oc_network_events.c @@ -57,14 +57,21 @@ oc_process_network_event(void) OC_LIST_LOCAL(network_events); oc_list_copy(network_events, g_network_events); oc_list_init(g_network_events); -#ifdef OC_NETWORK_MONITOR + #ifdef OC_NETWORK_MONITOR bool interface_up = g_interface_up; - g_interface_up = false; + g_interface_up = false; bool interface_down = g_interface_down; g_interface_down = false; #endif /* OC_NETWORK_MONITOR */ oc_network_event_handler_mutex_unlock(); + #ifdef OC_DYNAMIC_ALLOCATION + if(oc_list_length(network_events) >= OC_MAX_NUM_CONCURRENT_REQUESTS) { + // if the queue was full -> send a signal to start consuming network events + oc_connectivity_wakeup(); + } + #endif /* OC_DYNAMIC_ALLOCATION */ + #ifdef OC_HAS_FEATURE_TCP_ASYNC_CONNECT oc_tcp_on_connect_event_t *event = (oc_tcp_on_connect_event_t *)oc_list_pop(network_tcp_connect_events); @@ -179,6 +186,13 @@ oc_network_drop_receive_events(const oc_endpoint_t *endpoint) message = next; } oc_network_event_handler_mutex_unlock(); + + #ifdef OC_DYNAMIC_ALLOCATION + if(oc_list_length(g_network_events) + dropped >= OC_MAX_NUM_CONCURRENT_REQUESTS) { + // if the queue was full -> send a signal to start consuming network events + oc_connectivity_wakeup(); + } +#endif /* OC_DYNAMIC_ALLOCATION */ return dropped; } diff --git a/port/linux/ipadapter.c b/port/linux/ipadapter.c index 54a5fbdd5a..7827a58449 100644 --- a/port/linux/ipadapter.c +++ b/port/linux/ipadapter.c @@ -678,15 +678,20 @@ udp_add_socks_to_rfd_set(ip_context_t *dev) #endif /* OC_IPV4 */ } -static void -process_shutdown(const ip_context_t *dev) +static bool +process_wakeup_signal(ip_context_t *dev, fd_set *fds) { - ssize_t len; - do { - char buf; - // write to pipe shall not block - so read the byte we wrote - len = read(dev->shutdown_pipe[0], &buf, 1); - } while (len < 0 && errno == EINTR); + if (FD_ISSET(dev->shutdown_pipe[0], fds)) { + FD_CLR(dev->shutdown_pipe[0], fds); + ssize_t len; + do { + char buf; + // write to pipe shall not block - so read the byte we wrote + len = read(dev->shutdown_pipe[0], &buf, 1); + } while (len < 0 && errno == EINTR); + return true; + } + return false; } static adapter_receive_state_t @@ -852,25 +857,10 @@ static int process_event(ip_context_t *dev, fd_set *rdfds, fd_set *wfds) { if (rdfds != NULL) { - if ((dev->device == 0) && (FD_ISSET(g_ifchange_sock, rdfds))) { - OC_DBG("interface change processed on (fd=%d)", g_ifchange_sock); - FD_CLR(g_ifchange_sock, rdfds); - if (process_interface_change_event() < 0) { - OC_WRN("caught errors while handling a network interface change"); - } - return 1; - } - - if (process_socket_signal_event(dev, rdfds)) { - return 1; - } - int ret = process_socket_read_event(dev, rdfds); if (ret != 0) { return ret; } - - // TODO: No return value here?! } if (wfds != NULL) { @@ -902,6 +892,44 @@ process_event(ip_context_t *dev, fd_set *rdfds, fd_set *wfds) return 0; } +#ifdef OC_DYNAMIC_ALLOCATION +static int fds_count(const fd_set *sourcefds) { + int rfd_count = 0; + for (int i = 0; i < FD_SETSIZE; i++) { + if (FD_ISSET(i, sourcefds)) { + rfd_count++; + } + } + return rfd_count; +} + +static bool +pick_random_event(fd_set *eventfd, fd_set *sourcefds, int fd_count) { + FD_ZERO(eventfd); + + if (oc_get_network_events_queue_length() >= OC_MAX_NUM_CONCURRENT_REQUESTS) { + return false; + } + + if (fd_count == 0) { + return false; + } + + int random_rfd = oc_random_value() % fd_count; + for (int i = 0; i < FD_SETSIZE; i++) { + if (FD_ISSET(i, sourcefds)) { + if (--fd_count == random_rfd) { + FD_SET(i, eventfd); + FD_CLR(i, sourcefds); + break; + } + } + } + + return true; +} +#endif /* OC_DYNAMIC_ALLOCATION */ + static void process_events(ip_context_t *dev, fd_set *rdfds, fd_set *wfds, int fd_count) { @@ -911,6 +939,40 @@ process_events(ip_context_t *dev, fd_set *rdfds, fd_set *wfds, int fd_count) } OC_DBG("processing %d events", fd_count); + + // process control flow events + if (process_wakeup_signal(dev, rdfds)) { + fd_count--; + } + + if ((dev->device == 0) && (FD_ISSET(g_ifchange_sock, rdfds))) { + OC_DBG("interface change processed on (fd=%d)", g_ifchange_sock); + FD_CLR(g_ifchange_sock, rdfds); + if (process_interface_change_event() < 0) { + OC_WRN("caught errors while handling a network interface change"); + } + fd_count--; + } + + if (process_socket_signal_event(dev, rdfds)) { + fd_count--; + } + +#ifdef OC_DYNAMIC_ALLOCATION + // process read events + int rfds_count = fds_count(rdfds); // TODO: optimize + fd_set eventfd; + while (pick_random_event(&eventfd, rdfds, rfds_count)) { + int ret = process_socket_read_event(dev, &eventfd); + if (ret < 0) { + break; + } + fd_count--; + rfds_count--; + } +#endif /* OC_DYNAMIC_ALLOCATION */ + + //OC_DBG("processing %d events", fd_count); for (int i = 0; i < fd_count; i++) { if (process_event(dev, rdfds, wfds) < 0) { break; @@ -936,30 +998,15 @@ to_timeval(oc_clock_time_t ticks) } #endif /* OC_HAS_FEATURE_TCP_ASYNC_CONNECT */ -#ifdef OC_DYNAMIC_ALLOCATION -static bool -optimize_rfds(fd_set *output_set, const fd_set *rfd_set, int rfd_count) -{ - if (oc_get_network_events_queue_length() >= OC_MAX_NUM_CONCURRENT_REQUESTS) { - for (int i = 0; i < FD_SETSIZE; i++) { - if (FD_ISSET(i, rfd_set)) { - FD_CLR(i, output_set); - } - } - return true; - } - - int random_rfd = oc_random_value() % rfd_count; - for (int i = 0; i < FD_SETSIZE; i++) { - if (FD_ISSET(i, rfd_set)) { - if (rfd_count != random_rfd) { - FD_CLR(i, output_set); - } - } +static void add_control_flow_rfds(fd_set *output_set, const ip_context_t *dev){ + /* Monitor network interface changes on the platform from only the 0th + * logical device + */ + if (dev->device == 0) { + FD_SET(g_ifchange_sock, output_set); } - return false; + FD_SET(dev->shutdown_pipe[0], output_set); } -#endif /* OC_DYNAMIC_ALLOCATION */ static void * network_event_thread(void *data) @@ -968,27 +1015,9 @@ network_event_thread(void *data) FD_ZERO(&dev->rfds); udp_add_socks_to_rfd_set(dev); -#ifdef OC_DYNAMIC_ALLOCATION - struct timeval queue_timeout; - queue_timeout.tv_sec = 0; - queue_timeout.tv_usec = 1000; - fd_set rfd_set = ip_context_rfds_fd_copy(dev); - int rfd_count = 0; - for (int i = 0; i < FD_SETSIZE; i++) { - if (FD_ISSET(i, &rfd_set)) { - rfd_count++; - } - } -#endif /* OC_DYNAMIC_ALLOCATION */ - /* Monitor network interface changes on the platform from only the 0th - * logical device - */ - if (dev->device == 0) { - FD_SET(g_ifchange_sock, &dev->rfds); - } - FD_SET(dev->shutdown_pipe[0], &dev->rfds); + add_control_flow_rfds(&dev->rfds, dev); #ifdef OC_TCP tcp_add_socks_to_rfd_set(dev); @@ -1000,12 +1029,6 @@ network_event_thread(void *data) while (OC_ATOMIC_LOAD8(dev->terminate) != 1) { struct timeval *timeout = NULL; fd_set rdfds = ip_context_rfds_fd_copy(dev); -#ifdef OC_DYNAMIC_ALLOCATION - bool use_timeout = optimize_rfds(&rdfds, &rfd_set, rfd_count); -#else - bool use_timeout = false; -#endif /* OC_DYNAMIC_ALLOCATION */ - fd_set *wfds = NULL; #ifdef OC_HAS_FEATURE_TCP_ASYNC_CONNECT fd_set write_fds = tcp_context_cfds_fd_copy(&dev->tcp); @@ -1018,11 +1041,18 @@ network_event_thread(void *data) (unsigned)tv.tv_usec); } #endif /* OC_HAS_FEATURE_TCP_ASYNC_CONNECT */ - int n = select(FD_SETSIZE, &rdfds, wfds, NULL, use_timeout ? &queue_timeout : timeout); - if (FD_ISSET(dev->shutdown_pipe[0], &rdfds)) { - process_shutdown(dev); +#ifdef OC_DYNAMIC_ALLOCATION + if (oc_get_network_events_queue_length() >= OC_MAX_NUM_CONCURRENT_REQUESTS) { + // the queue is full -> add only control flow rfds + FD_ZERO(&rdfds); + add_control_flow_rfds(&rdfds, dev); +#ifdef OC_TCP + // TODO: add handling of tcp control flow rfds here +#endif /* OC_TCP */ } +#endif /* OC_DYNAMIC_ALLOCATION */ + int n = select(FD_SETSIZE, &rdfds, wfds, NULL, timeout); if (OC_ATOMIC_LOAD8(dev->terminate)) { break; @@ -1542,6 +1572,19 @@ initialize_ip_context(ip_context_t *dev, size_t device, return true; } +static void signal_event_thread(ip_context_t *dev) +{ + do { + if (write(dev->shutdown_pipe[1], "\n", 1) < 0) { + if (errno == EINTR) { + continue; + } + OC_WRN("cannot wakeup network thread (error: %d)", (int)errno); + } + break; + } while (true); +} + int oc_connectivity_init(size_t device, oc_connectivity_ports_t ports) { @@ -1565,6 +1608,24 @@ oc_connectivity_init(size_t device, oc_connectivity_ports_t ports) return 0; } +#ifdef OC_DYNAMIC_ALLOCATION +void +oc_connectivity_wakeup(void) +{ + pthread_mutex_lock(&g_mutex); + OC_LIST_LOCAL(ip_contexts); + oc_list_copy(ip_contexts, g_ip_contexts); + pthread_mutex_unlock(&g_mutex); + + // signal the event thread for all devices + ip_context_t *dev = oc_list_head(ip_contexts); + while (dev != NULL) { + signal_event_thread(dev); + dev = dev->next; + } +} +#endif /* OC_DYNAMIC_ALLOCATION */ + void oc_connectivity_shutdown(size_t device) { @@ -1575,15 +1636,7 @@ oc_connectivity_shutdown(size_t device) } OC_ATOMIC_STORE8(dev->terminate, 1); - do { - if (write(dev->shutdown_pipe[1], "\n", 1) < 0) { - if (errno == EINTR) { - continue; - } - OC_WRN("cannot wakeup network thread (error: %d)", (int)errno); - } - break; - } while (true); + signal_event_thread(dev); pthread_join(dev->event_thread, NULL); diff --git a/port/oc_connectivity_internal.h b/port/oc_connectivity_internal.h index 413cab1b0c..2618390b19 100644 --- a/port/oc_connectivity_internal.h +++ b/port/oc_connectivity_internal.h @@ -65,6 +65,27 @@ void oc_connectivity_shutdown(size_t device); */ int oc_send_buffer2(oc_message_t *message, bool queue); + #ifdef OC_DYNAMIC_ALLOCATION +/** + * @brief send a signal to start consuming network events + */ +void oc_connectivity_wakeup(void); +#endif /* OC_DYNAMIC_ALLOCATION */ + +#ifdef OC_HAS_FEATURE_TCP_ASYNC_CONNECT +typedef struct +{ + uint8_t max_count; ///< maximal number of retries for opening a single TCP + /// connection (default: 5) + uint16_t timeout; ///< timeout of a single retry in seconds (default: 5) +} oc_tcp_connect_retry_t; + +#define OC_TCP_CONNECT_RETRY_MAX_COUNT 5 +#define OC_TCP_CONNECT_RETRY_TIMEOUT 5 + +void oc_tcp_set_connect_retry(uint8_t max_count, uint16_t timeout); +#endif /* OC_HAS_FEATURE_TCP_ASYNC_CONNECT */ + #ifdef OC_NETWORK_MONITOR /** * @brief the callback function for an network change From 9c9d562e84ecc31aef9cf7f920b28a44b809f88c Mon Sep 17 00:00:00 2001 From: sp-martin Date: Wed, 29 May 2024 12:05:38 +0000 Subject: [PATCH 03/35] - separete control-flow (signal) socket handling --- port/linux/ipadapter.c | 8 +++----- port/linux/tcpadapter.c | 7 ++++++- port/linux/tcpadapter.h | 9 ++++++++- 3 files changed, 17 insertions(+), 7 deletions(-) diff --git a/port/linux/ipadapter.c b/port/linux/ipadapter.c index 7827a58449..f4d101540f 100644 --- a/port/linux/ipadapter.c +++ b/port/linux/ipadapter.c @@ -1013,14 +1013,12 @@ network_event_thread(void *data) { ip_context_t *dev = (ip_context_t *)data; FD_ZERO(&dev->rfds); + udp_add_socks_to_rfd_set(dev); - - - add_control_flow_rfds(&dev->rfds, dev); - #ifdef OC_TCP tcp_add_socks_to_rfd_set(dev); + tcp_add_controlflow_socks_to_rfd_set(&dev->rfds, dev); #endif /* OC_TCP */ #ifdef OC_HAS_FEATURE_TCP_ASYNC_CONNECT @@ -1048,7 +1046,7 @@ network_event_thread(void *data) FD_ZERO(&rdfds); add_control_flow_rfds(&rdfds, dev); #ifdef OC_TCP - // TODO: add handling of tcp control flow rfds here + tcp_add_controlflow_socks_to_rfd_set(&rdfds, dev); #endif /* OC_TCP */ } #endif /* OC_DYNAMIC_ALLOCATION */ diff --git a/port/linux/tcpadapter.c b/port/linux/tcpadapter.c index a66bcfcea8..517398920f 100644 --- a/port/linux/tcpadapter.c +++ b/port/linux/tcpadapter.c @@ -268,7 +268,12 @@ tcp_add_socks_to_rfd_set(ip_context_t *dev) oc_sock_listener_fd_set(&dev->tcp.secure4, &dev->rfds); #endif /* OC_SECURITY */ #endif /* OC_IPV4 */ - FD_SET(dev->tcp.connect_pipe[0], &dev->rfds); +} + +void +tcp_add_controlflow_socks_to_rfd_set(fd_set *rfd_set, const ip_context_t *dev) +{ + FD_SET(dev->tcp.connect_pipe[0], rfd_set); } static adapter_receive_state_t diff --git a/port/linux/tcpadapter.h b/port/linux/tcpadapter.h index 15a278609a..dbf10037d8 100644 --- a/port/linux/tcpadapter.h +++ b/port/linux/tcpadapter.h @@ -47,12 +47,19 @@ bool tcp_connectivity_init(ip_context_t *dev, oc_connectivity_ports_t ports); void tcp_connectivity_shutdown(ip_context_t *dev); /** - * @brief Add all TCP sockets and signal pipe to read fd set. + * @brief Add TCP sockets to read fd set. * * @param dev the device network context (cannot be NULL) */ void tcp_add_socks_to_rfd_set(ip_context_t *dev); +/** + * @brief Add signal pipe to read fd set. + * + * @param dev the device network context (cannot be NULL) + */ +void tcp_add_controlflow_socks_to_rfd_set(fd_set *rfd_set, const ip_context_t *dev); + /** * @brief Handle data available on the signal pipe (dev->connect_pipe). * From 544f82e59c3c2b6012bbd486fef9995f0d486152 Mon Sep 17 00:00:00 2001 From: sp-martin Date: Thu, 30 May 2024 16:34:01 +0000 Subject: [PATCH 04/35] - per device queue limit handling --- api/oc_network_events.c | 17 +++++--- api/oc_network_events_internal.h | 7 +++- port/linux/ipadapter.c | 66 ++++++++++++++++---------------- 3 files changed, 50 insertions(+), 40 deletions(-) diff --git a/api/oc_network_events.c b/api/oc_network_events.c index 8195b7af12..d670f10a40 100644 --- a/api/oc_network_events.c +++ b/api/oc_network_events.c @@ -67,7 +67,7 @@ oc_process_network_event(void) #ifdef OC_DYNAMIC_ALLOCATION if(oc_list_length(network_events) >= OC_MAX_NUM_CONCURRENT_REQUESTS) { - // if the queue was full -> send a signal to start consuming network events + // send a wake-up signal in case the queue might reach the limit for a device oc_connectivity_wakeup(); } #endif /* OC_DYNAMIC_ALLOCATION */ @@ -188,8 +188,8 @@ oc_network_drop_receive_events(const oc_endpoint_t *endpoint) oc_network_event_handler_mutex_unlock(); #ifdef OC_DYNAMIC_ALLOCATION - if(oc_list_length(g_network_events) + dropped >= OC_MAX_NUM_CONCURRENT_REQUESTS) { - // if the queue was full -> send a signal to start consuming network events + if(oc_get_network_events_queue_length(endpoint->device) + dropped >= OC_MAX_NUM_CONCURRENT_REQUESTS) { + // send a wake-up signal in case the queue for the device was full oc_connectivity_wakeup(); } #endif /* OC_DYNAMIC_ALLOCATION */ @@ -220,10 +220,15 @@ oc_network_interface_event(oc_interface_event_t event) #endif /* OC_NETWORK_MONITOR */ int -oc_get_network_events_queue_length(void) +oc_get_network_events_queue_length(size_t device) { oc_network_event_handler_mutex_lock(); - int length = oc_list_length(g_network_events); + int message_count = 0; + for (oc_message_t *message = (oc_message_t *)oc_list_head(g_network_events); message != NULL; message = message->next) { + if (message->endpoint.device == device) { + ++message_count; + } + } oc_network_event_handler_mutex_unlock(); - return length; + return message_count; } diff --git a/api/oc_network_events_internal.h b/api/oc_network_events_internal.h index dbb7b9ca0a..e0d1cd7834 100644 --- a/api/oc_network_events_internal.h +++ b/api/oc_network_events_internal.h @@ -79,9 +79,12 @@ void oc_network_interface_event(oc_interface_event_t event); #endif /* OC_NETWORK_MONITOR */ /** - * @brief returns the length of network events queue + * @brief Returns the network event queue length for the device + * + * @param device valid device index + * @return number of events in the queue */ -int oc_get_network_events_queue_length(void); +int oc_get_network_events_queue_length(size_t device); #ifdef __cplusplus } diff --git a/port/linux/ipadapter.c b/port/linux/ipadapter.c index f4d101540f..82139bc3d8 100644 --- a/port/linux/ipadapter.c +++ b/port/linux/ipadapter.c @@ -893,9 +893,10 @@ process_event(ip_context_t *dev, fd_set *rdfds, fd_set *wfds) } #ifdef OC_DYNAMIC_ALLOCATION -static int fds_count(const fd_set *sourcefds) { +static int +fds_count(const fd_set *sourcefds) { int rfd_count = 0; - for (int i = 0; i < FD_SETSIZE; i++) { + for (int i = 0; i < FD_SETSIZE; i++) { //// TODO: optimize if (FD_ISSET(i, sourcefds)) { rfd_count++; } @@ -903,31 +904,36 @@ static int fds_count(const fd_set *sourcefds) { return rfd_count; } -static bool -pick_random_event(fd_set *eventfd, fd_set *sourcefds, int fd_count) { - FD_ZERO(eventfd); - - if (oc_get_network_events_queue_length() >= OC_MAX_NUM_CONCURRENT_REQUESTS) { - return false; - } - - if (fd_count == 0) { - return false; - } - +static int +pick_random_fd(const fd_set *sourcefds, int fd_count) { int random_rfd = oc_random_value() % fd_count; - for (int i = 0; i < FD_SETSIZE; i++) { + for (int i = 0; i < FD_SETSIZE; i++) { // TODO: optimize FD_SETSIZE if (FD_ISSET(i, sourcefds)) { if (--fd_count == random_rfd) { - FD_SET(i, eventfd); - FD_CLR(i, sourcefds); - break; + return i; } - } + } } + return -1; +} + +static int +remove_random_fds(fd_set *rdfds, int rfds_count, int remove_count) { - return true; + int removed = 0; + while (removed < remove_count) { + int fd = pick_random_fd(rdfds, rfds_count); + if (fd < 0) { + break; + } + // remove file descriptor from the set + FD_CLR(fd, rdfds); + --rfds_count; + ++removed; + } + return removed; } + #endif /* OC_DYNAMIC_ALLOCATION */ static void @@ -959,20 +965,16 @@ process_events(ip_context_t *dev, fd_set *rdfds, fd_set *wfds, int fd_count) } #ifdef OC_DYNAMIC_ALLOCATION - // process read events - int rfds_count = fds_count(rdfds); // TODO: optimize - fd_set eventfd; - while (pick_random_event(&eventfd, rdfds, rfds_count)) { - int ret = process_socket_read_event(dev, &eventfd); - if (ret < 0) { - break; - } - fd_count--; - rfds_count--; + // check if network queue can consume all 'ready' events + int available_count = OC_MAX_NUM_CONCURRENT_REQUESTS - oc_get_network_events_queue_length(dev->device); + if (available_count < fd_count) { + // get the number of read file descriptors + int rfds_count = fds_count(rdfds); + int removed = remove_random_fds(rdfds, rfds_count, rfds_count - available_count); + fd_count-= removed; } #endif /* OC_DYNAMIC_ALLOCATION */ - //OC_DBG("processing %d events", fd_count); for (int i = 0; i < fd_count; i++) { if (process_event(dev, rdfds, wfds) < 0) { break; @@ -1041,7 +1043,7 @@ network_event_thread(void *data) #endif /* OC_HAS_FEATURE_TCP_ASYNC_CONNECT */ #ifdef OC_DYNAMIC_ALLOCATION - if (oc_get_network_events_queue_length() >= OC_MAX_NUM_CONCURRENT_REQUESTS) { + if (oc_get_network_events_queue_length(dev->device) >= OC_MAX_NUM_CONCURRENT_REQUESTS) { // the queue is full -> add only control flow rfds FD_ZERO(&rdfds); add_control_flow_rfds(&rdfds, dev); From da7188373de5ce193bbe660e907c98b3bbf362b8 Mon Sep 17 00:00:00 2001 From: sp-martin Date: Fri, 31 May 2024 12:04:13 +0000 Subject: [PATCH 05/35] - fixed formatting and static analysis --- api/oc_network_events.c | 21 ++++++----- api/oc_network_events_internal.h | 2 +- port/linux/ipadapter.c | 65 ++++++++++++++++++-------------- port/linux/tcpadapter.c | 4 +- port/linux/tcpadapter.h | 3 +- port/oc_connectivity_internal.h | 2 +- 6 files changed, 55 insertions(+), 42 deletions(-) diff --git a/api/oc_network_events.c b/api/oc_network_events.c index d670f10a40..b651c2ca89 100644 --- a/api/oc_network_events.c +++ b/api/oc_network_events.c @@ -57,20 +57,21 @@ oc_process_network_event(void) OC_LIST_LOCAL(network_events); oc_list_copy(network_events, g_network_events); oc_list_init(g_network_events); - #ifdef OC_NETWORK_MONITOR +#ifdef OC_NETWORK_MONITOR bool interface_up = g_interface_up; - g_interface_up = false; + g_interface_up = false; bool interface_down = g_interface_down; g_interface_down = false; #endif /* OC_NETWORK_MONITOR */ oc_network_event_handler_mutex_unlock(); - #ifdef OC_DYNAMIC_ALLOCATION - if(oc_list_length(network_events) >= OC_MAX_NUM_CONCURRENT_REQUESTS) { - // send a wake-up signal in case the queue might reach the limit for a device +#ifdef OC_DYNAMIC_ALLOCATION + if (oc_list_length(network_events) >= OC_MAX_NUM_CONCURRENT_REQUESTS) { + // send a wake-up signal in case the queue might reach the limit for a + // device oc_connectivity_wakeup(); } - #endif /* OC_DYNAMIC_ALLOCATION */ +#endif /* OC_DYNAMIC_ALLOCATION */ #ifdef OC_HAS_FEATURE_TCP_ASYNC_CONNECT oc_tcp_on_connect_event_t *event = @@ -187,8 +188,9 @@ oc_network_drop_receive_events(const oc_endpoint_t *endpoint) } oc_network_event_handler_mutex_unlock(); - #ifdef OC_DYNAMIC_ALLOCATION - if(oc_get_network_events_queue_length(endpoint->device) + dropped >= OC_MAX_NUM_CONCURRENT_REQUESTS) { +#ifdef OC_DYNAMIC_ALLOCATION + if (oc_get_network_events_queue_length(endpoint->device) + dropped >= + OC_MAX_NUM_CONCURRENT_REQUESTS) { // send a wake-up signal in case the queue for the device was full oc_connectivity_wakeup(); } @@ -224,7 +226,8 @@ oc_get_network_events_queue_length(size_t device) { oc_network_event_handler_mutex_lock(); int message_count = 0; - for (oc_message_t *message = (oc_message_t *)oc_list_head(g_network_events); message != NULL; message = message->next) { + for (oc_message_t *message = (oc_message_t *)oc_list_head(g_network_events); + message != NULL; message = message->next) { if (message->endpoint.device == device) { ++message_count; } diff --git a/api/oc_network_events_internal.h b/api/oc_network_events_internal.h index e0d1cd7834..9212e57f73 100644 --- a/api/oc_network_events_internal.h +++ b/api/oc_network_events_internal.h @@ -80,7 +80,7 @@ void oc_network_interface_event(oc_interface_event_t event); /** * @brief Returns the network event queue length for the device - * + * * @param device valid device index * @return number of events in the queue */ diff --git a/port/linux/ipadapter.c b/port/linux/ipadapter.c index 82139bc3d8..858b223f0f 100644 --- a/port/linux/ipadapter.c +++ b/port/linux/ipadapter.c @@ -893,8 +893,9 @@ process_event(ip_context_t *dev, fd_set *rdfds, fd_set *wfds) } #ifdef OC_DYNAMIC_ALLOCATION -static int -fds_count(const fd_set *sourcefds) { +static int +fds_count(const fd_set *sourcefds) +{ int rfd_count = 0; for (int i = 0; i < FD_SETSIZE; i++) { //// TODO: optimize if (FD_ISSET(i, sourcefds)) { @@ -904,9 +905,10 @@ fds_count(const fd_set *sourcefds) { return rfd_count; } -static int -pick_random_fd(const fd_set *sourcefds, int fd_count) { - int random_rfd = oc_random_value() % fd_count; +static int +pick_random_fd(const fd_set *sourcefds, int fd_count) +{ + int random_rfd = (int)oc_random_value() % fd_count; for (int i = 0; i < FD_SETSIZE; i++) { // TODO: optimize FD_SETSIZE if (FD_ISSET(i, sourcefds)) { if (--fd_count == random_rfd) { @@ -917,9 +919,10 @@ pick_random_fd(const fd_set *sourcefds, int fd_count) { return -1; } -static int -remove_random_fds(fd_set *rdfds, int rfds_count, int remove_count) { - +static int +remove_random_fds(fd_set *rdfds, int rfds_count, int remove_count) +{ + int removed = 0; while (removed < remove_count) { int fd = pick_random_fd(rdfds, rfds_count); @@ -927,7 +930,7 @@ remove_random_fds(fd_set *rdfds, int rfds_count, int remove_count) { break; } // remove file descriptor from the set - FD_CLR(fd, rdfds); + FD_CLR(fd, rdfds); --rfds_count; ++removed; } @@ -959,19 +962,21 @@ process_events(ip_context_t *dev, fd_set *rdfds, fd_set *wfds, int fd_count) } fd_count--; } - + if (process_socket_signal_event(dev, rdfds)) { fd_count--; } #ifdef OC_DYNAMIC_ALLOCATION // check if network queue can consume all 'ready' events - int available_count = OC_MAX_NUM_CONCURRENT_REQUESTS - oc_get_network_events_queue_length(dev->device); - if (available_count < fd_count) { + int available_count = OC_MAX_NUM_CONCURRENT_REQUESTS - + oc_get_network_events_queue_length(dev->device); + if (available_count < fd_count) { // get the number of read file descriptors - int rfds_count = fds_count(rdfds); - int removed = remove_random_fds(rdfds, rfds_count, rfds_count - available_count); - fd_count-= removed; + int rfds_count = fds_count(rdfds); + int removed = + remove_random_fds(rdfds, rfds_count, rfds_count - available_count); + fd_count -= removed; } #endif /* OC_DYNAMIC_ALLOCATION */ @@ -1000,7 +1005,9 @@ to_timeval(oc_clock_time_t ticks) } #endif /* OC_HAS_FEATURE_TCP_ASYNC_CONNECT */ -static void add_control_flow_rfds(fd_set *output_set, const ip_context_t *dev){ +static void +add_control_flow_rfds(fd_set *output_set, const ip_context_t *dev) +{ /* Monitor network interface changes on the platform from only the 0th * logical device */ @@ -1015,7 +1022,7 @@ network_event_thread(void *data) { ip_context_t *dev = (ip_context_t *)data; FD_ZERO(&dev->rfds); - + udp_add_socks_to_rfd_set(dev); add_control_flow_rfds(&dev->rfds, dev); #ifdef OC_TCP @@ -1042,14 +1049,15 @@ network_event_thread(void *data) } #endif /* OC_HAS_FEATURE_TCP_ASYNC_CONNECT */ -#ifdef OC_DYNAMIC_ALLOCATION - if (oc_get_network_events_queue_length(dev->device) >= OC_MAX_NUM_CONCURRENT_REQUESTS) { +#ifdef OC_DYNAMIC_ALLOCATION + if (oc_get_network_events_queue_length(dev->device) >= + OC_MAX_NUM_CONCURRENT_REQUESTS) { // the queue is full -> add only control flow rfds FD_ZERO(&rdfds); add_control_flow_rfds(&rdfds, dev); -#ifdef OC_TCP +#ifdef OC_TCP tcp_add_controlflow_socks_to_rfd_set(&rdfds, dev); -#endif /* OC_TCP */ +#endif /* OC_TCP */ } #endif /* OC_DYNAMIC_ALLOCATION */ int n = select(FD_SETSIZE, &rdfds, wfds, NULL, timeout); @@ -1572,16 +1580,17 @@ initialize_ip_context(ip_context_t *dev, size_t device, return true; } -static void signal_event_thread(ip_context_t *dev) +static void +signal_event_thread(ip_context_t *dev) { do { - if (write(dev->shutdown_pipe[1], "\n", 1) < 0) { - if (errno == EINTR) { - continue; - } - OC_WRN("cannot wakeup network thread (error: %d)", (int)errno); + if (write(dev->shutdown_pipe[1], "\n", 1) < 0) { + if (errno == EINTR) { + continue; } - break; + OC_WRN("cannot wakeup network thread (error: %d)", (int)errno); + } + break; } while (true); } diff --git a/port/linux/tcpadapter.c b/port/linux/tcpadapter.c index 517398920f..49fad96ef2 100644 --- a/port/linux/tcpadapter.c +++ b/port/linux/tcpadapter.c @@ -270,10 +270,10 @@ tcp_add_socks_to_rfd_set(ip_context_t *dev) #endif /* OC_IPV4 */ } -void +void tcp_add_controlflow_socks_to_rfd_set(fd_set *rfd_set, const ip_context_t *dev) { - FD_SET(dev->tcp.connect_pipe[0], rfd_set); + FD_SET(dev->tcp.connect_pipe[0], rfd_set); } static adapter_receive_state_t diff --git a/port/linux/tcpadapter.h b/port/linux/tcpadapter.h index dbf10037d8..41f64973d4 100644 --- a/port/linux/tcpadapter.h +++ b/port/linux/tcpadapter.h @@ -58,7 +58,8 @@ void tcp_add_socks_to_rfd_set(ip_context_t *dev); * * @param dev the device network context (cannot be NULL) */ -void tcp_add_controlflow_socks_to_rfd_set(fd_set *rfd_set, const ip_context_t *dev); +void tcp_add_controlflow_socks_to_rfd_set(fd_set *rfd_set, + const ip_context_t *dev); /** * @brief Handle data available on the signal pipe (dev->connect_pipe). diff --git a/port/oc_connectivity_internal.h b/port/oc_connectivity_internal.h index 2618390b19..fc78c3bd7f 100644 --- a/port/oc_connectivity_internal.h +++ b/port/oc_connectivity_internal.h @@ -65,7 +65,7 @@ void oc_connectivity_shutdown(size_t device); */ int oc_send_buffer2(oc_message_t *message, bool queue); - #ifdef OC_DYNAMIC_ALLOCATION +#ifdef OC_DYNAMIC_ALLOCATION /** * @brief send a signal to start consuming network events */ From 4eec493dbd61d4d9b5d8f488602228724a775667 Mon Sep 17 00:00:00 2001 From: sp-martin Date: Fri, 31 May 2024 17:58:49 +0000 Subject: [PATCH 06/35] - separate define for device concurent requests --- api/oc_network_events.c | 4 ++-- port/android/oc_config.h | 5 +++++ port/esp32/adapter/include/oc_config.h | 5 +++++ port/linux/ipadapter.c | 4 ++-- port/linux/oc_config.h | 6 ++++-- 5 files changed, 18 insertions(+), 6 deletions(-) diff --git a/api/oc_network_events.c b/api/oc_network_events.c index b651c2ca89..6e56524835 100644 --- a/api/oc_network_events.c +++ b/api/oc_network_events.c @@ -66,7 +66,7 @@ oc_process_network_event(void) oc_network_event_handler_mutex_unlock(); #ifdef OC_DYNAMIC_ALLOCATION - if (oc_list_length(network_events) >= OC_MAX_NUM_CONCURRENT_REQUESTS) { + if (oc_list_length(network_events) >= OC_DEVICE_MAX_NUM_CONCURRENT_REQUESTS) { // send a wake-up signal in case the queue might reach the limit for a // device oc_connectivity_wakeup(); @@ -190,7 +190,7 @@ oc_network_drop_receive_events(const oc_endpoint_t *endpoint) #ifdef OC_DYNAMIC_ALLOCATION if (oc_get_network_events_queue_length(endpoint->device) + dropped >= - OC_MAX_NUM_CONCURRENT_REQUESTS) { + OC_DEVICE_MAX_NUM_CONCURRENT_REQUESTS) { // send a wake-up signal in case the queue for the device was full oc_connectivity_wakeup(); } diff --git a/port/android/oc_config.h b/port/android/oc_config.h index d887e2e09c..76370430b4 100644 --- a/port/android/oc_config.h +++ b/port/android/oc_config.h @@ -62,6 +62,11 @@ typedef uint64_t oc_clock_time_t; /* Enable reallocation during encoding the representation to cbor */ // #define OC_REP_ENCODING_REALLOC +/* Maximum number of messages in the network event queue for a device */ +#ifndef OC_DEVICE_MAX_NUM_CONCURRENT_REQUESTS +#define OC_DEVICE_MAX_NUM_CONCURRENT_REQUESTS (32) +#endif /* OC_DEVICE_MAX_NUM_CONCURRENT_REQUESTS */ + #else /* OC_DYNAMIC_ALLOCATION */ /* List of constraints below for a build that does not employ dynamic memory allocation diff --git a/port/esp32/adapter/include/oc_config.h b/port/esp32/adapter/include/oc_config.h index 0f43db347e..1891c85ce2 100644 --- a/port/esp32/adapter/include/oc_config.h +++ b/port/esp32/adapter/include/oc_config.h @@ -62,6 +62,11 @@ typedef uint64_t oc_clock_time_t; /* Enable reallocation during encoding the representation to cbor */ #define OC_REP_ENCODING_REALLOC +/* Maximum number of messages in the network event queue for a device */ +#ifndef OC_DEVICE_MAX_NUM_CONCURRENT_REQUESTS +#define OC_DEVICE_MAX_NUM_CONCURRENT_REQUESTS (32) +#endif /* OC_DEVICE_MAX_NUM_CONCURRENT_REQUESTS */ + #else /* OC_DYNAMIC_ALLOCATION */ /* List of constraints below for a build that does not employ dynamic memory allocation diff --git a/port/linux/ipadapter.c b/port/linux/ipadapter.c index 858b223f0f..b9812ca83b 100644 --- a/port/linux/ipadapter.c +++ b/port/linux/ipadapter.c @@ -969,7 +969,7 @@ process_events(ip_context_t *dev, fd_set *rdfds, fd_set *wfds, int fd_count) #ifdef OC_DYNAMIC_ALLOCATION // check if network queue can consume all 'ready' events - int available_count = OC_MAX_NUM_CONCURRENT_REQUESTS - + int available_count = OC_DEVICE_MAX_NUM_CONCURRENT_REQUESTS - oc_get_network_events_queue_length(dev->device); if (available_count < fd_count) { // get the number of read file descriptors @@ -1051,7 +1051,7 @@ network_event_thread(void *data) #ifdef OC_DYNAMIC_ALLOCATION if (oc_get_network_events_queue_length(dev->device) >= - OC_MAX_NUM_CONCURRENT_REQUESTS) { + OC_DEVICE_MAX_NUM_CONCURRENT_REQUESTS) { // the queue is full -> add only control flow rfds FD_ZERO(&rdfds); add_control_flow_rfds(&rdfds, dev); diff --git a/port/linux/oc_config.h b/port/linux/oc_config.h index 441109d596..80d3f21191 100644 --- a/port/linux/oc_config.h +++ b/port/linux/oc_config.h @@ -69,8 +69,10 @@ typedef uint64_t oc_clock_time_t; * with REP_ENCODING_REALLOC=1 */ // #define OC_REP_ENCODING_REALLOC -/* Maximum number of messages in the network event queue */ -#define OC_MAX_NUM_CONCURRENT_REQUESTS (32) +/* Maximum number of messages in the network event queue for a device */ +#ifndef OC_DEVICE_MAX_NUM_CONCURRENT_REQUESTS +#define OC_DEVICE_MAX_NUM_CONCURRENT_REQUESTS (32) +#endif /* OC_DEVICE_MAX_NUM_CONCURRENT_REQUESTS */ #else /* OC_DYNAMIC_ALLOCATION */ /* List of constraints below for a build that does not employ dynamic From 7877fd4029be04515f96cc15a6f1a025f097111f Mon Sep 17 00:00:00 2001 From: sp-martin Date: Mon, 3 Jun 2024 13:24:22 +0000 Subject: [PATCH 07/35] -send wakeup only to certain device network thread --- api/oc_network_events.c | 61 +++++++++++++++++++++----------- api/oc_network_events_internal.h | 5 +-- port/linux/ipadapter.c | 24 +++++-------- port/oc_connectivity_internal.h | 6 ++-- 4 files changed, 57 insertions(+), 39 deletions(-) diff --git a/api/oc_network_events.c b/api/oc_network_events.c index 6e56524835..eb67823e82 100644 --- a/api/oc_network_events.c +++ b/api/oc_network_events.c @@ -45,6 +45,35 @@ static bool g_interface_up; static bool g_interface_down; #endif /* OC_NETWORK_MONITOR */ +static size_t +get_events_queue_length(size_t device, oc_list_t events) +{ + size_t msg_count = 0; + for (oc_message_t *msg = (oc_message_t *)oc_list_head(events); msg != NULL; + msg = msg->next) { + if (msg->endpoint.device == device) { + ++msg_count; + } + } + return msg_count; +} + +static void +send_wakeup_signal(oc_list_t events) +{ + size_t msg_total = oc_list_length(events); + + int deviceId = 0; + while (msg_total >= OC_DEVICE_MAX_NUM_CONCURRENT_REQUESTS) { + size_t msg_device_count = get_events_queue_length(deviceId, events); + if (msg_device_count >= OC_DEVICE_MAX_NUM_CONCURRENT_REQUESTS) { + oc_connectivity_wakeup(deviceId); + } + msg_total -= msg_device_count; + ++deviceId; // advance to the next device + } +} + static void oc_process_network_event(void) { @@ -66,11 +95,8 @@ oc_process_network_event(void) oc_network_event_handler_mutex_unlock(); #ifdef OC_DYNAMIC_ALLOCATION - if (oc_list_length(network_events) >= OC_DEVICE_MAX_NUM_CONCURRENT_REQUESTS) { - // send a wake-up signal in case the queue might reach the limit for a - // device - oc_connectivity_wakeup(); - } + // send a wake-up signal in case the queue might reach the limit for a device + send_wakeup_signal(network_events); #endif /* OC_DYNAMIC_ALLOCATION */ #ifdef OC_HAS_FEATURE_TCP_ASYNC_CONNECT @@ -161,10 +187,10 @@ oc_network_tcp_connect_event(oc_tcp_on_connect_event_t *event) } #endif /* OC_HAS_FEATURE_TCP_ASYNC_CONNECT */ -int +size_t oc_network_drop_receive_events(const oc_endpoint_t *endpoint) { - int dropped = 0; + size_t dropped = 0; oc_network_event_handler_mutex_lock(); for (oc_message_t *message = (oc_message_t *)oc_list_head(g_network_events); message != NULL;) { @@ -186,15 +212,16 @@ oc_network_drop_receive_events(const oc_endpoint_t *endpoint) } message = next; } - oc_network_event_handler_mutex_unlock(); #ifdef OC_DYNAMIC_ALLOCATION - if (oc_get_network_events_queue_length(endpoint->device) + dropped >= + if (get_events_queue_length(endpoint->device, g_network_events) + dropped >= OC_DEVICE_MAX_NUM_CONCURRENT_REQUESTS) { // send a wake-up signal in case the queue for the device was full - oc_connectivity_wakeup(); + oc_connectivity_wakeup(endpoint->device); } #endif /* OC_DYNAMIC_ALLOCATION */ + + oc_network_event_handler_mutex_unlock(); return dropped; } @@ -221,17 +248,11 @@ oc_network_interface_event(oc_interface_event_t event) } #endif /* OC_NETWORK_MONITOR */ -int -oc_get_network_events_queue_length(size_t device) +size_t +oc_network_get_event_queue_length(size_t device) { oc_network_event_handler_mutex_lock(); - int message_count = 0; - for (oc_message_t *message = (oc_message_t *)oc_list_head(g_network_events); - message != NULL; message = message->next) { - if (message->endpoint.device == device) { - ++message_count; - } - } + size_t msg_count = get_events_queue_length(device, g_network_events); oc_network_event_handler_mutex_unlock(); - return message_count; + return msg_count; } diff --git a/api/oc_network_events_internal.h b/api/oc_network_events_internal.h index 9212e57f73..2a6ef9ec7f 100644 --- a/api/oc_network_events_internal.h +++ b/api/oc_network_events_internal.h @@ -58,7 +58,8 @@ void oc_network_tcp_connect_event(oc_tcp_on_connect_event_t *event) * @param endpoint the endpoint (cannot be NULL) * @return number of events dropped */ -int oc_network_drop_receive_events(const oc_endpoint_t *endpoint) OC_NONNULL(); +size_t oc_network_drop_receive_events(const oc_endpoint_t *endpoint) + OC_NONNULL(); #ifdef OC_NETWORK_MONITOR /** @@ -84,7 +85,7 @@ void oc_network_interface_event(oc_interface_event_t event); * @param device valid device index * @return number of events in the queue */ -int oc_get_network_events_queue_length(size_t device); +size_t oc_network_get_event_queue_length(size_t device); #ifdef __cplusplus } diff --git a/port/linux/ipadapter.c b/port/linux/ipadapter.c index b9812ca83b..0cb7843703 100644 --- a/port/linux/ipadapter.c +++ b/port/linux/ipadapter.c @@ -970,7 +970,7 @@ process_events(ip_context_t *dev, fd_set *rdfds, fd_set *wfds, int fd_count) #ifdef OC_DYNAMIC_ALLOCATION // check if network queue can consume all 'ready' events int available_count = OC_DEVICE_MAX_NUM_CONCURRENT_REQUESTS - - oc_get_network_events_queue_length(dev->device); + oc_network_get_event_queue_length(dev->device); if (available_count < fd_count) { // get the number of read file descriptors int rfds_count = fds_count(rdfds); @@ -1050,7 +1050,7 @@ network_event_thread(void *data) #endif /* OC_HAS_FEATURE_TCP_ASYNC_CONNECT */ #ifdef OC_DYNAMIC_ALLOCATION - if (oc_get_network_events_queue_length(dev->device) >= + if (oc_network_get_event_queue_length(dev->device) >= OC_DEVICE_MAX_NUM_CONCURRENT_REQUESTS) { // the queue is full -> add only control flow rfds FD_ZERO(&rdfds); @@ -1617,23 +1617,17 @@ oc_connectivity_init(size_t device, oc_connectivity_ports_t ports) return 0; } -#ifdef OC_DYNAMIC_ALLOCATION void -oc_connectivity_wakeup(void) +oc_connectivity_wakeup(size_t device) { - pthread_mutex_lock(&g_mutex); - OC_LIST_LOCAL(ip_contexts); - oc_list_copy(ip_contexts, g_ip_contexts); - pthread_mutex_unlock(&g_mutex); - - // signal the event thread for all devices - ip_context_t *dev = oc_list_head(ip_contexts); - while (dev != NULL) { - signal_event_thread(dev); - dev = dev->next; + ip_context_t *dev = oc_get_ip_context_for_device(device); + if (dev == NULL) { + OC_WRN("no ip-context found for device(%zu)", device); + return; } + + signal_event_thread(dev); } -#endif /* OC_DYNAMIC_ALLOCATION */ void oc_connectivity_shutdown(size_t device) diff --git a/port/oc_connectivity_internal.h b/port/oc_connectivity_internal.h index fc78c3bd7f..2ca5741975 100644 --- a/port/oc_connectivity_internal.h +++ b/port/oc_connectivity_internal.h @@ -67,9 +67,11 @@ int oc_send_buffer2(oc_message_t *message, bool queue); #ifdef OC_DYNAMIC_ALLOCATION /** - * @brief send a signal to start consuming network events + * @brief send a wakeup signal to the device to start consuming network events + * + * @param device the device index */ -void oc_connectivity_wakeup(void); +void oc_connectivity_wakeup(size_t device); #endif /* OC_DYNAMIC_ALLOCATION */ #ifdef OC_HAS_FEATURE_TCP_ASYNC_CONNECT From cbfcc011945531fb77d658dcc6ee813126abbc08 Mon Sep 17 00:00:00 2001 From: sp-martin Date: Mon, 3 Jun 2024 14:02:08 +0000 Subject: [PATCH 08/35] - fixed android and esp32 builds --- port/android/ipadapter.c | 24 +++++++++++++++++++++--- port/esp32/adapter/src/ipadapter.c | 24 +++++++++++++++++++++--- 2 files changed, 42 insertions(+), 6 deletions(-) diff --git a/port/android/ipadapter.c b/port/android/ipadapter.c index 9a769fef83..c487cf1697 100644 --- a/port/android/ipadapter.c +++ b/port/android/ipadapter.c @@ -1580,6 +1580,26 @@ oc_connectivity_init(size_t device, oc_connectivity_ports_t ports) return 0; } +static void +signal_event_thread(ip_context_t *dev) +{ + if (write(dev->shutdown_pipe[1], "\n", 1) < 0) { + OC_WRN("cannot wakeup network thread"); + } +} + +void +oc_connectivity_wakeup(size_t device) +{ + ip_context_t *dev = oc_get_ip_context_for_device(device); + if (dev == NULL) { + OC_WRN("no ip-context found for device(%zu)", device); + return; + } + + signal_event_thread(dev); +} + void oc_connectivity_shutdown(size_t device) { @@ -1590,9 +1610,7 @@ oc_connectivity_shutdown(size_t device) } dev->terminate = 1; - if (write(dev->shutdown_pipe[1], "\n", 1) < 0) { - OC_WRN("cannot wakeup network thread"); - } + signal_event_thread(dev); pthread_join(dev->event_thread, NULL); diff --git a/port/esp32/adapter/src/ipadapter.c b/port/esp32/adapter/src/ipadapter.c index 3946e1cd12..58d6a1f0a5 100644 --- a/port/esp32/adapter/src/ipadapter.c +++ b/port/esp32/adapter/src/ipadapter.c @@ -1568,6 +1568,26 @@ oc_connectivity_init(size_t device, oc_connectivity_ports_t ports) return 0; } +static void +signal_event_thread(ip_context_t *dev) +{ + if (write(dev->shutdown_pipe[1], "\n", 1) < 0) { + OC_WRN("cannot wakeup network thread"); + } +} + +void +oc_connectivity_wakeup(size_t device) +{ + ip_context_t *dev = oc_get_ip_context_for_device(device); + if (dev == NULL) { + OC_WRN("no ip-context found for device(%zu)", device); + return; + } + + signal_event_thread(dev); +} + void oc_connectivity_shutdown(size_t device) { @@ -1578,9 +1598,7 @@ oc_connectivity_shutdown(size_t device) } dev->terminate = 1; - if (write(dev->shutdown_pipe[1], "\n", 1) < 0) { - OC_WRN("cannot wakeup network thread"); - } + signal_event_thread(dev); pthread_join(dev->event_thread, NULL); From eba31db540d7f841fb424cdb25a06be8dbd0dc44 Mon Sep 17 00:00:00 2001 From: sp-martin Date: Mon, 3 Jun 2024 14:17:07 +0000 Subject: [PATCH 09/35] - renamed shutdown_pipe to wakeup_pipe --- port/android/ipadapter.c | 16 ++++++++-------- port/android/ipcontext.h | 2 +- port/esp32/adapter/src/ipadapter.c | 18 +++++++++--------- port/esp32/adapter/src/ipcontext.h | 2 +- port/linux/ipadapter.c | 22 +++++++++++----------- port/linux/ipcontext.h | 2 +- 6 files changed, 31 insertions(+), 31 deletions(-) diff --git a/port/android/ipadapter.c b/port/android/ipadapter.c index c487cf1697..d4e5b40377 100644 --- a/port/android/ipadapter.c +++ b/port/android/ipadapter.c @@ -795,7 +795,7 @@ network_event_thread(void *data) FD_SET(g_ifchange_sock, &dev->rfds); } #endif /* OC_NETLINK_IF_CHANGE_NOTIFICATIONS_AVAILABLE */ - FD_SET(dev->shutdown_pipe[0], &dev->rfds); + FD_SET(dev->wakeup_pipe[0], &dev->rfds); FD_SET(dev->server_sock, &dev->rfds); FD_SET(dev->mcast_sock, &dev->rfds); #ifdef OC_SECURITY @@ -820,10 +820,10 @@ network_event_thread(void *data) setfds = dev->rfds; n = select(FD_SETSIZE, &setfds, NULL, NULL, NULL); - if (FD_ISSET(dev->shutdown_pipe[0], &setfds)) { + if (FD_ISSET(dev->wakeup_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) { + if (read(dev->wakeup_pipe[0], &buf, 1) < 0) { // intentionally left blank } } @@ -1372,8 +1372,8 @@ oc_connectivity_init(size_t device, oc_connectivity_ports_t ports) dev->device = device; OC_LIST_STRUCT_INIT(dev, eps); - if (pipe(dev->shutdown_pipe) < 0) { - OC_ERR("shutdown pipe: %d", errno); + if (pipe(dev->wakeup_pipe) < 0) { + OC_ERR("wakeup pipe: %d", errno); return -1; } @@ -1583,7 +1583,7 @@ oc_connectivity_init(size_t device, oc_connectivity_ports_t ports) static void signal_event_thread(ip_context_t *dev) { - if (write(dev->shutdown_pipe[1], "\n", 1) < 0) { + if (write(dev->wakeup_pipe[1], "\n", 1) < 0) { OC_WRN("cannot wakeup network thread"); } } @@ -1633,8 +1633,8 @@ oc_connectivity_shutdown(size_t device) oc_tcp_connectivity_shutdown(dev); #endif /* OC_TCP */ - close(dev->shutdown_pipe[1]); - close(dev->shutdown_pipe[0]); + close(dev->wakeup_pipe[1]); + close(dev->wakeup_pipe[0]); free_endpoints_list(dev); diff --git a/port/android/ipcontext.h b/port/android/ipcontext.h index 6e96e2b2af..6f7edd46ca 100644 --- a/port/android/ipcontext.h +++ b/port/android/ipcontext.h @@ -95,7 +95,7 @@ typedef struct ip_context_t int terminate; size_t device; fd_set rfds; - int shutdown_pipe[2]; + int wakeup_pipe[2]; } ip_context_t; #ifdef __cplusplus diff --git a/port/esp32/adapter/src/ipadapter.c b/port/esp32/adapter/src/ipadapter.c index 58d6a1f0a5..cae6af1232 100644 --- a/port/esp32/adapter/src/ipadapter.c +++ b/port/esp32/adapter/src/ipadapter.c @@ -817,7 +817,7 @@ network_event_thread(void *data) FD_SET(ifchange_sock, &dev->rfds); } */ - FD_SET(dev->shutdown_pipe[0], &dev->rfds); + FD_SET(dev->wakeup_pipe[0], &dev->rfds); oc_udp_add_socks_to_fd_set(dev); #ifdef OC_TCP @@ -830,11 +830,11 @@ network_event_thread(void *data) setfds = dev->rfds; n = select(FD_SETSIZE, &setfds, NULL, NULL, NULL); - if (FD_ISSET(dev->shutdown_pipe[0], &setfds)) { - OC_DBG("network_event_thread select: dev->shutdown_pipe[0]"); + if (FD_ISSET(dev->wakeup_pipe[0], &setfds)) { + OC_DBG("network_event_thread select: dev->wakeup_pipe[0]"); char buf; // write to pipe shall not block - so read the byte we wrote - if (read(dev->shutdown_pipe[0], &buf, 1) < 0) { + if (read(dev->wakeup_pipe[0], &buf, 1) < 0) { // intentionally left blank } } @@ -1343,8 +1343,8 @@ oc_connectivity_init(size_t device, oc_connectivity_ports_t ports) esp_vfs_dev_pipe_register(); - if (vfs_pipe(dev->shutdown_pipe) < 0) { - OC_ERR("shutdown pipe: %d", errno); + if (vfs_pipe(dev->wakeup_pipe) < 0) { + OC_ERR("wakeup pipe: %d", errno); return -1; } @@ -1571,7 +1571,7 @@ oc_connectivity_init(size_t device, oc_connectivity_ports_t ports) static void signal_event_thread(ip_context_t *dev) { - if (write(dev->shutdown_pipe[1], "\n", 1) < 0) { + if (write(dev->wakeup_pipe[1], "\n", 1) < 0) { OC_WRN("cannot wakeup network thread"); } } @@ -1621,8 +1621,8 @@ oc_connectivity_shutdown(size_t device) oc_tcp_connectivity_shutdown(dev); #endif /* OC_TCP */ - close(dev->shutdown_pipe[1]); - close(dev->shutdown_pipe[0]); + close(dev->wakeup_pipe[1]); + close(dev->wakeup_pipe[0]); free_endpoints_list(dev); diff --git a/port/esp32/adapter/src/ipcontext.h b/port/esp32/adapter/src/ipcontext.h index bf54c48a8f..6844f10813 100644 --- a/port/esp32/adapter/src/ipcontext.h +++ b/port/esp32/adapter/src/ipcontext.h @@ -96,7 +96,7 @@ typedef struct ip_context_t int terminate; size_t device; fd_set rfds; - int shutdown_pipe[2]; + int wakeup_pipe[2]; } ip_context_t; #ifdef __cplusplus diff --git a/port/linux/ipadapter.c b/port/linux/ipadapter.c index 0cb7843703..db17109836 100644 --- a/port/linux/ipadapter.c +++ b/port/linux/ipadapter.c @@ -681,13 +681,13 @@ udp_add_socks_to_rfd_set(ip_context_t *dev) static bool process_wakeup_signal(ip_context_t *dev, fd_set *fds) { - if (FD_ISSET(dev->shutdown_pipe[0], fds)) { - FD_CLR(dev->shutdown_pipe[0], fds); + if (FD_ISSET(dev->wakeup_pipe[0], fds)) { + FD_CLR(dev->wakeup_pipe[0], fds); ssize_t len; do { char buf; // write to pipe shall not block - so read the byte we wrote - len = read(dev->shutdown_pipe[0], &buf, 1); + len = read(dev->wakeup_pipe[0], &buf, 1); } while (len < 0 && errno == EINTR); return true; } @@ -1014,7 +1014,7 @@ add_control_flow_rfds(fd_set *output_set, const ip_context_t *dev) if (dev->device == 0) { FD_SET(g_ifchange_sock, output_set); } - FD_SET(dev->shutdown_pipe[0], output_set); + FD_SET(dev->wakeup_pipe[0], output_set); } static void * @@ -1489,12 +1489,12 @@ initialize_ip_context(ip_context_t *dev, size_t device, oc_abort("error initializing TCP adapter mutex"); } - if (pipe(dev->shutdown_pipe) < 0) { - OC_ERR("shutdown pipe: %d", errno); + if (pipe(dev->wakeup_pipe) < 0) { + OC_ERR("wakeup pipe: %d", errno); return false; } - if (!oc_fcntl_set_nonblocking(dev->shutdown_pipe[0])) { - OC_ERR("Could not set non-block shutdown_pipe[0]"); + if (!oc_fcntl_set_nonblocking(dev->wakeup_pipe[0])) { + OC_ERR("Could not set non-block wakeup_pipe[0]"); return false; } @@ -1584,7 +1584,7 @@ static void signal_event_thread(ip_context_t *dev) { do { - if (write(dev->shutdown_pipe[1], "\n", 1) < 0) { + if (write(dev->wakeup_pipe[1], "\n", 1) < 0) { if (errno == EINTR) { continue; } @@ -1666,8 +1666,8 @@ oc_connectivity_shutdown(size_t device) tcp_connectivity_shutdown(dev); #endif /* OC_TCP */ - close(dev->shutdown_pipe[1]); - close(dev->shutdown_pipe[0]); + close(dev->wakeup_pipe[1]); + close(dev->wakeup_pipe[0]); pthread_mutex_destroy(&dev->rfds_mutex); diff --git a/port/linux/ipcontext.h b/port/linux/ipcontext.h index a1e4123ed9..cd6cc5ec03 100644 --- a/port/linux/ipcontext.h +++ b/port/linux/ipcontext.h @@ -70,7 +70,7 @@ typedef struct ip_context_t size_t device; pthread_mutex_t rfds_mutex; fd_set rfds; - int shutdown_pipe[2]; + int wakeup_pipe[2]; OC_ATOMIC_INT8_T flags; } ip_context_t; From cf6bac9821edcda8c0b4a5cff759f50bc57fc96d Mon Sep 17 00:00:00 2001 From: sp-martin Date: Mon, 3 Jun 2024 15:08:24 +0000 Subject: [PATCH 10/35] - optimized traversal of file descriptors --- port/linux/ipadapter.c | 43 +++++++++++++++++++++++++++--------------- 1 file changed, 28 insertions(+), 15 deletions(-) diff --git a/port/linux/ipadapter.c b/port/linux/ipadapter.c index db17109836..b18af29d2c 100644 --- a/port/linux/ipadapter.c +++ b/port/linux/ipadapter.c @@ -892,12 +892,23 @@ process_event(ip_context_t *dev, fd_set *rdfds, fd_set *wfds) return 0; } -#ifdef OC_DYNAMIC_ALLOCATION static int -fds_count(const fd_set *sourcefds) +fds_max(const fd_set *sourcefds) +{ + int max_fd = 0; + for (int i = 0; i < FD_SETSIZE; i++) { + if (FD_ISSET(i, sourcefds)) { + max_fd = i; + } + } + return max_fd; +} + +static int +fds_count(const fd_set *sourcefds, int max_fd) { int rfd_count = 0; - for (int i = 0; i < FD_SETSIZE; i++) { //// TODO: optimize + for (int i = 0; i <= max_fd; i++) { if (FD_ISSET(i, sourcefds)) { rfd_count++; } @@ -906,10 +917,11 @@ fds_count(const fd_set *sourcefds) } static int -pick_random_fd(const fd_set *sourcefds, int fd_count) +pick_random_fd(const fd_set *sourcefds, int fd_count, int max_fd) { + assert(fd_count > 0); int random_rfd = (int)oc_random_value() % fd_count; - for (int i = 0; i < FD_SETSIZE; i++) { // TODO: optimize FD_SETSIZE + for (int i = 0; i <= max_fd; i++) { if (FD_ISSET(i, sourcefds)) { if (--fd_count == random_rfd) { return i; @@ -920,12 +932,11 @@ pick_random_fd(const fd_set *sourcefds, int fd_count) } static int -remove_random_fds(fd_set *rdfds, int rfds_count, int remove_count) +remove_random_fds(fd_set *rdfds, int rfds_count, int max_fd, int remove_count) { - int removed = 0; while (removed < remove_count) { - int fd = pick_random_fd(rdfds, rfds_count); + int fd = pick_random_fd(rdfds, rfds_count, max_fd); if (fd < 0) { break; } @@ -937,10 +948,9 @@ remove_random_fds(fd_set *rdfds, int rfds_count, int remove_count) return removed; } -#endif /* OC_DYNAMIC_ALLOCATION */ - static void -process_events(ip_context_t *dev, fd_set *rdfds, fd_set *wfds, int fd_count) +process_events(ip_context_t *dev, fd_set *rdfds, fd_set *wfds, int fd_count, + int max_read_fd) { if (fd_count == 0) { OC_DBG("process_events: timeout"); @@ -973,11 +983,13 @@ process_events(ip_context_t *dev, fd_set *rdfds, fd_set *wfds, int fd_count) oc_network_get_event_queue_length(dev->device); if (available_count < fd_count) { // get the number of read file descriptors - int rfds_count = fds_count(rdfds); - int removed = - remove_random_fds(rdfds, rfds_count, rfds_count - available_count); + int rfds_count = fds_count(rdfds, max_read_fd); + int removed = remove_random_fds(rdfds, rfds_count, max_read_fd, + rfds_count - available_count); fd_count -= removed; } +#else /* !OC_DYNAMIC_ALLOCATION */ + (void)max_read_fd; #endif /* OC_DYNAMIC_ALLOCATION */ for (int i = 0; i < fd_count; i++) { @@ -1029,6 +1041,7 @@ network_event_thread(void *data) tcp_add_socks_to_rfd_set(dev); tcp_add_controlflow_socks_to_rfd_set(&dev->rfds, dev); #endif /* OC_TCP */ + int max_read_fd = fds_max(&dev->rfds); #ifdef OC_HAS_FEATURE_TCP_ASYNC_CONNECT oc_clock_time_t expires_in = 0; @@ -1066,7 +1079,7 @@ network_event_thread(void *data) break; } - process_events(dev, &rdfds, wfds, n); + process_events(dev, &rdfds, wfds, n, max_read_fd); #ifdef OC_HAS_FEATURE_TCP_ASYNC_CONNECT expires_in = tcp_check_expiring_sessions(oc_clock_time_monotonic()); From a82dc4ae1edabfe9f34dcc9a1945e04a16274474 Mon Sep 17 00:00:00 2001 From: sp-martin Date: Tue, 4 Jun 2024 06:52:33 +0000 Subject: [PATCH 11/35] - fixed android and esp32 build breaks --- port/android/ipadapter.c | 2 +- port/esp32/adapter/src/ipadapter.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/port/android/ipadapter.c b/port/android/ipadapter.c index d4e5b40377..e2eb097972 100644 --- a/port/android/ipadapter.c +++ b/port/android/ipadapter.c @@ -1591,7 +1591,7 @@ signal_event_thread(ip_context_t *dev) void oc_connectivity_wakeup(size_t device) { - ip_context_t *dev = oc_get_ip_context_for_device(device); + ip_context_t *dev = get_ip_context_for_device(device); if (dev == NULL) { OC_WRN("no ip-context found for device(%zu)", device); return; diff --git a/port/esp32/adapter/src/ipadapter.c b/port/esp32/adapter/src/ipadapter.c index cae6af1232..4f7ee45801 100644 --- a/port/esp32/adapter/src/ipadapter.c +++ b/port/esp32/adapter/src/ipadapter.c @@ -1579,7 +1579,7 @@ signal_event_thread(ip_context_t *dev) void oc_connectivity_wakeup(size_t device) { - ip_context_t *dev = oc_get_ip_context_for_device(device); + ip_context_t *dev = get_ip_context_for_device(device); if (dev == NULL) { OC_WRN("no ip-context found for device(%zu)", device); return; From 8170cad458ff122cbd03be2239813898ca89f038 Mon Sep 17 00:00:00 2001 From: sp-martin Date: Tue, 4 Jun 2024 20:55:22 +0000 Subject: [PATCH 12/35] - calculate max fd value from the recent device file descriptor set --- port/linux/ipadapter.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/port/linux/ipadapter.c b/port/linux/ipadapter.c index b18af29d2c..8137d6c112 100644 --- a/port/linux/ipadapter.c +++ b/port/linux/ipadapter.c @@ -892,6 +892,13 @@ process_event(ip_context_t *dev, fd_set *rdfds, fd_set *wfds) return 0; } +static bool +fd_sets_are_equal(const fd_set *fd1, const fd_set *fd2) +{ + return (memcmp(__FDS_BITS(fd1), __FDS_BITS(fd2), sizeof(__FDS_BITS(fd1))) == + 0); +} + static int fds_max(const fd_set *sourcefds) { @@ -1041,7 +1048,10 @@ network_event_thread(void *data) tcp_add_socks_to_rfd_set(dev); tcp_add_controlflow_socks_to_rfd_set(&dev->rfds, dev); #endif /* OC_TCP */ - int max_read_fd = fds_max(&dev->rfds); + + int max_read_fd = FD_SETSIZE; + fd_set last_rdfds; + FD_ZERO(&last_rdfds); #ifdef OC_HAS_FEATURE_TCP_ASYNC_CONNECT oc_clock_time_t expires_in = 0; @@ -1063,6 +1073,12 @@ network_event_thread(void *data) #endif /* OC_HAS_FEATURE_TCP_ASYNC_CONNECT */ #ifdef OC_DYNAMIC_ALLOCATION + if (!fd_sets_are_equal(&rdfds, &last_rdfds)) { + // fd set has changed -> recalculate max fd + max_read_fd = fds_max(&rdfds); + last_rdfds = rdfds; + } + if (oc_network_get_event_queue_length(dev->device) >= OC_DEVICE_MAX_NUM_CONCURRENT_REQUESTS) { // the queue is full -> add only control flow rfds From 0607c59e71cef3c820772cf00ade124c50b934e3 Mon Sep 17 00:00:00 2001 From: sp-martin Date: Wed, 5 Jun 2024 06:44:02 +0000 Subject: [PATCH 13/35] - improved error handling and logging for signal_event_thread --- port/android/ipadapter.c | 14 ++++++++++++-- port/esp32/adapter/src/ipadapter.c | 14 ++++++++++++-- port/linux/ipadapter.c | 18 +++++++++++------- 3 files changed, 35 insertions(+), 11 deletions(-) diff --git a/port/android/ipadapter.c b/port/android/ipadapter.c index e2eb097972..bac0126ccc 100644 --- a/port/android/ipadapter.c +++ b/port/android/ipadapter.c @@ -1583,8 +1583,18 @@ oc_connectivity_init(size_t device, oc_connectivity_ports_t ports) static void signal_event_thread(ip_context_t *dev) { - if (write(dev->wakeup_pipe[1], "\n", 1) < 0) { - OC_WRN("cannot wakeup network thread"); + ssize_t result; + do { + result = write(dev->wakeup_pipe[1], "\n", 1); + } while (result == -1 && errno == EINTR); + + if (result == -1) { + if (errno != ENOSPC) { + OC_WRN("Failed to write to wakeup pipe: %s", strerror(errno)); + } + // ENOSPC is ignored as the pipe is already signaled + } else if (result != 1) { + OC_WRN("Unexpected number of bytes written to wakeup pipe: %zd", result); } } diff --git a/port/esp32/adapter/src/ipadapter.c b/port/esp32/adapter/src/ipadapter.c index 4f7ee45801..08c64a0a1d 100644 --- a/port/esp32/adapter/src/ipadapter.c +++ b/port/esp32/adapter/src/ipadapter.c @@ -1571,8 +1571,18 @@ oc_connectivity_init(size_t device, oc_connectivity_ports_t ports) static void signal_event_thread(ip_context_t *dev) { - if (write(dev->wakeup_pipe[1], "\n", 1) < 0) { - OC_WRN("cannot wakeup network thread"); + ssize_t result; + do { + result = write(dev->wakeup_pipe[1], "\n", 1); + } while (result == -1 && errno == EINTR); + + if (result == -1) { + if (errno != ENOSPC) { + OC_WRN("Failed to write to wakeup pipe: %s", strerror(errno)); + } + // ENOSPC is ignored as the pipe is already signaled + } else if (result != 1) { + OC_WRN("Unexpected number of bytes written to wakeup pipe: %zd", result); } } diff --git a/port/linux/ipadapter.c b/port/linux/ipadapter.c index 8137d6c112..3a80d94897 100644 --- a/port/linux/ipadapter.c +++ b/port/linux/ipadapter.c @@ -1612,15 +1612,19 @@ initialize_ip_context(ip_context_t *dev, size_t device, static void signal_event_thread(ip_context_t *dev) { + ssize_t result; do { - if (write(dev->wakeup_pipe[1], "\n", 1) < 0) { - if (errno == EINTR) { - continue; - } - OC_WRN("cannot wakeup network thread (error: %d)", (int)errno); + result = write(dev->wakeup_pipe[1], "\n", 1); + } while (result == -1 && errno == EINTR); + + if (result == -1) { + if (errno != ENOSPC) { + OC_WRN("Failed to write to wakeup pipe: %s", strerror(errno)); } - break; - } while (true); + // ENOSPC is ignored as the pipe is already signaled + } else if (result != 1) { + OC_WRN("Unexpected number of bytes written to wakeup pipe: %zd", result); + } } int From 5419e5b41572768c4def697da940e32f0b1cbb63 Mon Sep 17 00:00:00 2001 From: sp-martin Date: Wed, 5 Jun 2024 13:08:18 +0000 Subject: [PATCH 14/35] - logging the error code instead of a string using strerror() --- port/android/ipadapter.c | 2 +- port/esp32/adapter/src/ipadapter.c | 2 +- port/linux/ipadapter.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/port/android/ipadapter.c b/port/android/ipadapter.c index bac0126ccc..b821caa324 100644 --- a/port/android/ipadapter.c +++ b/port/android/ipadapter.c @@ -1590,7 +1590,7 @@ signal_event_thread(ip_context_t *dev) if (result == -1) { if (errno != ENOSPC) { - OC_WRN("Failed to write to wakeup pipe: %s", strerror(errno)); + OC_WRN("Failed to wakeup the network thread. Error %d", errno); } // ENOSPC is ignored as the pipe is already signaled } else if (result != 1) { diff --git a/port/esp32/adapter/src/ipadapter.c b/port/esp32/adapter/src/ipadapter.c index 08c64a0a1d..fa214aeae9 100644 --- a/port/esp32/adapter/src/ipadapter.c +++ b/port/esp32/adapter/src/ipadapter.c @@ -1578,7 +1578,7 @@ signal_event_thread(ip_context_t *dev) if (result == -1) { if (errno != ENOSPC) { - OC_WRN("Failed to write to wakeup pipe: %s", strerror(errno)); + OC_WRN("Failed to wakeup the network thread. Error %d", errno); } // ENOSPC is ignored as the pipe is already signaled } else if (result != 1) { diff --git a/port/linux/ipadapter.c b/port/linux/ipadapter.c index 3a80d94897..42bdce2bf2 100644 --- a/port/linux/ipadapter.c +++ b/port/linux/ipadapter.c @@ -1619,7 +1619,7 @@ signal_event_thread(ip_context_t *dev) if (result == -1) { if (errno != ENOSPC) { - OC_WRN("Failed to write to wakeup pipe: %s", strerror(errno)); + OC_WRN("Failed to wakeup the network thread. Error %d", errno); } // ENOSPC is ignored as the pipe is already signaled } else if (result != 1) { From 4747dee0d5db725efafaf08108852fedbd3f1dfd Mon Sep 17 00:00:00 2001 From: sp-martin Date: Wed, 5 Jun 2024 14:56:38 +0000 Subject: [PATCH 15/35] - android port of Message Queue Limit --- port/android/ipadapter.c | 330 ++++++++++++++++++++++++++++++--------- 1 file changed, 255 insertions(+), 75 deletions(-) diff --git a/port/android/ipadapter.c b/port/android/ipadapter.c index b821caa324..c8f66a0720 100644 --- a/port/android/ipadapter.c +++ b/port/android/ipadapter.c @@ -779,23 +779,87 @@ recv_msg(int sock, uint8_t *recv_buf, int recv_buf_size, return ret; } -static void * -network_event_thread(void *data) + +static bool +fd_sets_are_equal(const fd_set *fd1, const fd_set *fd2) { - ip_context_t *dev = (ip_context_t *)data; + return (memcmp(__FDS_BITS(fd1), __FDS_BITS(fd2), sizeof(__FDS_BITS(fd1))) == + 0); +} - fd_set setfds; - FD_ZERO(&dev->rfds); +static int +fds_max(const fd_set *sourcefds) +{ + int max_fd = 0; + for (int i = 0; i < FD_SETSIZE; i++) { + if (FD_ISSET(i, sourcefds)) { + max_fd = i; + } + } + return max_fd; +} + +static int +fds_count(const fd_set *sourcefds, int max_fd) +{ + int rfd_count = 0; + for (int i = 0; i <= max_fd; i++) { + if (FD_ISSET(i, sourcefds)) { + rfd_count++; + } + } + return rfd_count; +} + +static int +pick_random_fd(const fd_set *sourcefds, int fd_count, int max_fd) +{ + assert(fd_count > 0); + int random_rfd = (int)oc_random_value() % fd_count; + for (int i = 0; i <= max_fd; i++) { + if (FD_ISSET(i, sourcefds)) { + if (--fd_count == random_rfd) { + return i; + } + } + } + return -1; +} + +static int +remove_random_fds(fd_set *rdfds, int rfds_count, int max_fd, int remove_count) +{ + int removed = 0; + while (removed < remove_count) { + int fd = pick_random_fd(rdfds, rfds_count, max_fd); + if (fd < 0) { + break; + } + // remove file descriptor from the set + FD_CLR(fd, rdfds); + --rfds_count; + ++removed; + } + return removed; +} +static void +add_control_flow_rfds(fd_set *output_set, const ip_context_t *dev) +{ #ifdef OC_NETLINK_IF_CHANGE_NOTIFICATIONS_AVAILABLE - /* Monitor network interface changes on the platform from only the 0th logical - * device + /* Monitor network interface changes on the platform from only the 0th + * logical device */ if (dev->device == 0) { - FD_SET(g_ifchange_sock, &dev->rfds); + FD_SET(g_ifchange_sock, output_set); } #endif /* OC_NETLINK_IF_CHANGE_NOTIFICATIONS_AVAILABLE */ - FD_SET(dev->wakeup_pipe[0], &dev->rfds); + FD_SET(dev->wakeup_pipe[0], output_set); +} + +static void +udp_add_socks_to_rfd_set(ip_context_t *dev) +{ FD_SET(dev->server_sock, &dev->rfds); FD_SET(dev->mcast_sock, &dev->rfds); #ifdef OC_SECURITY @@ -809,152 +873,268 @@ network_event_thread(void *data) FD_SET(dev->secure4_sock, &dev->rfds); #endif /* OC_SECURITY */ #endif /* OC_IPV4 */ +} -#ifdef OC_TCP - oc_tcp_add_socks_to_fd_set(dev); -#endif /* OC_TCP */ - - int i, n; - - while (dev->terminate != 1) { - setfds = dev->rfds; - n = select(FD_SETSIZE, &setfds, NULL, NULL, NULL); - - if (FD_ISSET(dev->wakeup_pipe[0], &setfds)) { +static bool +process_wakeup_signal(ip_context_t *dev, fd_set *fds) +{ + if (FD_ISSET(dev->wakeup_pipe[0], fds)) { + FD_CLR(dev->wakeup_pipe[0], fds); + ssize_t len; + do { char buf; // write to pipe shall not block - so read the byte we wrote - if (read(dev->wakeup_pipe[0], &buf, 1) < 0) { - // intentionally left blank - } - } + len = read(dev->wakeup_pipe[0], &buf, 1); + } while (len < 0 && errno == EINTR); + return true; + } + return false; +} - if (dev->terminate) { - break; +static int +process_socket_read_event(ip_context_t *dev, fd_set *rdfds) +{ + oc_message_t *message = oc_allocate_message(); + if (message == NULL) { + return -1; } + message->endpoint.device = dev->device; - for (i = 0; i < n; i++) { -#ifdef OC_NETLINK_IF_CHANGE_NOTIFICATIONS_AVAILABLE - if (dev->device == 0) { - if (FD_ISSET(g_ifchange_sock, &setfds)) { - if (process_interface_change_event() < 0) { - OC_WRN("caught errors while handling a network interface change"); - } - FD_CLR(g_ifchange_sock, &setfds); - continue; - } - } -#endif /* OC_NETLINK_IF_CHANGE_NOTIFICATIONS_AVAILABLE */ - - oc_message_t *message = oc_allocate_message(); - - if (!message) { - break; - } - - message->endpoint.device = dev->device; - - if (FD_ISSET(dev->server_sock, &setfds)) { + if (FD_ISSET(dev->server_sock, rdfds)) { + FD_CLR(dev->server_sock, rdfds); int count = recv_msg(dev->server_sock, message->data, OC_PDU_SIZE, &message->endpoint, false); if (count < 0) { oc_message_unref(message); - continue; + return 0; } message->length = (size_t)count; message->endpoint.flags = IPV6; - FD_CLR(dev->server_sock, &setfds); - goto common; + goto receive; } - if (FD_ISSET(dev->mcast_sock, &setfds)) { + if (FD_ISSET(dev->mcast_sock, rdfds)) { + FD_CLR(dev->mcast_sock, rdfds); int count = recv_msg(dev->mcast_sock, message->data, OC_PDU_SIZE, &message->endpoint, true); if (count < 0) { oc_message_unref(message); - continue; + return 0; } message->length = (size_t)count; message->endpoint.flags = IPV6 | MULTICAST; - FD_CLR(dev->mcast_sock, &setfds); - goto common; + goto receive; } #ifdef OC_IPV4 - if (FD_ISSET(dev->server4_sock, &setfds)) { + if (FD_ISSET(dev->server4_sock, rdfds)) { + FD_CLR(dev->server4_sock, rdfds); int count = recv_msg(dev->server4_sock, message->data, OC_PDU_SIZE, &message->endpoint, false); if (count < 0) { oc_message_unref(message); - continue; + return 0; } message->length = (size_t)count; message->endpoint.flags = IPV4; - FD_CLR(dev->server4_sock, &setfds); - goto common; + goto receive; } - if (FD_ISSET(dev->mcast4_sock, &setfds)) { + if (FD_ISSET(dev->mcast4_sock, rdfds)) { + FD_CLR(dev->mcast4_sock, rdfds); int count = recv_msg(dev->mcast4_sock, message->data, OC_PDU_SIZE, &message->endpoint, true); if (count < 0) { oc_message_unref(message); - continue; + return 0; } message->length = (size_t)count; message->endpoint.flags = IPV4 | MULTICAST; - FD_CLR(dev->mcast4_sock, &setfds); - goto common; + goto receive; } #endif /* OC_IPV4 */ #ifdef OC_SECURITY - if (FD_ISSET(dev->secure_sock, &setfds)) { + if (FD_ISSET(dev->secure_sock, rdfds)) { + FD_CLR(dev->secure_sock, rdfds); int count = recv_msg(dev->secure_sock, message->data, OC_PDU_SIZE, &message->endpoint, false); if (count < 0) { oc_message_unref(message); - continue; + return 0; } message->length = (size_t)count; message->endpoint.flags = IPV6 | SECURED; message->encrypted = 1; - FD_CLR(dev->secure_sock, &setfds); - goto common; + goto receive; } #ifdef OC_IPV4 - if (FD_ISSET(dev->secure4_sock, &setfds)) { + if (FD_ISSET(dev->secure4_sock, rdfds)) { + FD_CLR(dev->secure4_sock, rdfds); int count = recv_msg(dev->secure4_sock, message->data, OC_PDU_SIZE, &message->endpoint, false); if (count < 0) { oc_message_unref(message); - continue; + return 0; } message->length = (size_t)count; message->endpoint.flags = IPV4 | SECURED; message->encrypted = 1; - FD_CLR(dev->secure4_sock, &setfds); - goto common; + goto receive; } #endif /* OC_IPV4 */ #endif /* OC_SECURITY */ #ifdef OC_TCP adapter_receive_state_t tcp_status = - oc_tcp_receive_message(dev, &setfds, message); + oc_tcp_receive_message(dev, rdfds, message); if (tcp_status == ADAPTER_STATUS_RECEIVE) { - goto common; + goto receive; } #endif /* OC_TCP */ oc_message_unref(message); - continue; + return 0; - common: + receive: OC_DBG("Incoming message of size %zd bytes from", message->length); OC_LOGipaddr(message->endpoint); OC_DBG("%s", ""); oc_network_receive_event(message); + return 1; +} + +static int +process_event(ip_context_t *dev, fd_set *rdfds, fd_set *wfds) +{ + if (rdfds != NULL) { + int ret = process_socket_read_event(dev, rdfds); + if (ret != 0) { + return ret; + } + } + +#if OC_DBG_IS_ENABLED + // GCOVR_EXCL_START + if (rdfds != NULL) { + for (int i = 0; i < FD_SETSIZE; ++i) { + if (FD_ISSET(i, rdfds)) { + OC_DBG("no handler found for read event (fd=%d)", i); + } + } + } + if (wfds != NULL) { + for (int i = 0; i < FD_SETSIZE; ++i) { + if (FD_ISSET(i, wfds)) { + OC_DBG("no handler found for write event (fd=%d)", i); + } + } + } + // GCOVR_EXCL_STOP +#else /* !OC_DBG_IS_ENABLED */ + (void)wfds; +#endif /* OC_DBG_IS_ENABLED */ +} + +static void +process_events(ip_context_t *dev, fd_set *rdfds, fd_set *wfds, int fd_count, + int max_read_fd) +{ + if (fd_count == 0) { + OC_DBG("process_events: timeout"); + return; + } + + OC_DBG("processing %d events", fd_count); + + // process control flow events + if (process_wakeup_signal(dev, rdfds)) { + fd_count--; + } + +#ifdef OC_NETLINK_IF_CHANGE_NOTIFICATIONS_AVAILABLE + if ((dev->device == 0) && (FD_ISSET(g_ifchange_sock, rdfds))) { + OC_DBG("interface change processed on (fd=%d)", g_ifchange_sock); + FD_CLR(g_ifchange_sock, rdfds); + if (process_interface_change_event() < 0) { + OC_WRN("caught errors while handling a network interface change"); } + fd_count--; + } +#endif /* OC_NETLINK_IF_CHANGE_NOTIFICATIONS_AVAILABLE */ + + //if (process_socket_signal_event(dev, rdfds)) { + // fd_count--; + //} + +#ifdef OC_DYNAMIC_ALLOCATION + // check if network queue can consume all 'ready' events + int available_count = OC_DEVICE_MAX_NUM_CONCURRENT_REQUESTS - + oc_network_get_event_queue_length(dev->device); + if (available_count < fd_count) { + // get the number of read file descriptors + int rfds_count = fds_count(rdfds, max_read_fd); + int removed = remove_random_fds(rdfds, rfds_count, max_read_fd, + rfds_count - available_count); + fd_count -= removed; + } +#else /* !OC_DYNAMIC_ALLOCATION */ + (void)max_read_fd; +#endif /* OC_DYNAMIC_ALLOCATION */ + + for (int i = 0; i < fd_count; i++) { + if (process_event(dev, rdfds, wfds) < 0) { + break; + } + } +} + +static void * +network_event_thread(void *data) +{ + ip_context_t *dev = (ip_context_t *)data; + FD_ZERO(&dev->rfds); + + udp_add_socks_to_rfd_set(dev); + add_control_flow_rfds(&dev->rfds, dev); +#ifdef OC_TCP + oc_tcp_add_socks_to_fd_set(dev); + tcp_add_controlflow_socks_to_rfd_set(&dev->rfds, dev); +#endif /* OC_TCP */ + + int max_read_fd = FD_SETSIZE; + fd_set last_rdfds; + FD_ZERO(&last_rdfds); + + while (dev->terminate != 1) { + fd_set rdfds = dev->rfds; + + #ifdef OC_DYNAMIC_ALLOCATION + if (!fd_sets_are_equal(&rdfds, &last_rdfds)) { + // fd set has changed -> recalculate max fd + max_read_fd = fds_max(&rdfds); + last_rdfds = rdfds; + } + + if (oc_network_get_event_queue_length(dev->device) >= + OC_DEVICE_MAX_NUM_CONCURRENT_REQUESTS) { + // the queue is full -> add only control flow rfds + FD_ZERO(&rdfds); + add_control_flow_rfds(&rdfds, dev); +#ifdef OC_TCP + tcp_add_controlflow_socks_to_rfd_set(&rdfds, dev); +#endif /* OC_TCP */ + } +#endif /* OC_DYNAMIC_ALLOCATION */ + + int n = select(FD_SETSIZE, &rdfds, NULL, NULL, NULL); + + if (dev->terminate) { + break; + } + + process_events(dev, &rdfds, NULL, n, max_read_fd); + } pthread_exit(NULL); return NULL; From 6a25e74c20aa3a50678d20c894611d91ff90271d Mon Sep 17 00:00:00 2001 From: sp-martin Date: Wed, 5 Jun 2024 15:25:45 +0000 Subject: [PATCH 16/35] - formatting --- port/android/ipadapter.c | 198 +++++++++++++++++++-------------------- 1 file changed, 98 insertions(+), 100 deletions(-) diff --git a/port/android/ipadapter.c b/port/android/ipadapter.c index c8f66a0720..2cc9eee014 100644 --- a/port/android/ipadapter.c +++ b/port/android/ipadapter.c @@ -779,7 +779,6 @@ recv_msg(int sock, uint8_t *recv_buf, int recv_buf_size, return ret; } - static bool fd_sets_are_equal(const fd_set *fd1, const fd_set *fd2) { @@ -894,114 +893,114 @@ process_wakeup_signal(ip_context_t *dev, fd_set *fds) static int process_socket_read_event(ip_context_t *dev, fd_set *rdfds) { - oc_message_t *message = oc_allocate_message(); - if (message == NULL) { - return -1; + oc_message_t *message = oc_allocate_message(); + if (message == NULL) { + return -1; + } + message->endpoint.device = dev->device; + + if (FD_ISSET(dev->server_sock, rdfds)) { + FD_CLR(dev->server_sock, rdfds); + int count = recv_msg(dev->server_sock, message->data, OC_PDU_SIZE, + &message->endpoint, false); + if (count < 0) { + oc_message_unref(message); + return 0; } - message->endpoint.device = dev->device; - - if (FD_ISSET(dev->server_sock, rdfds)) { - FD_CLR(dev->server_sock, rdfds); - int count = recv_msg(dev->server_sock, message->data, OC_PDU_SIZE, - &message->endpoint, false); - if (count < 0) { - oc_message_unref(message); - return 0; - } - message->length = (size_t)count; - message->endpoint.flags = IPV6; - goto receive; - } + message->length = (size_t)count; + message->endpoint.flags = IPV6; + goto receive; + } - if (FD_ISSET(dev->mcast_sock, rdfds)) { - FD_CLR(dev->mcast_sock, rdfds); - int count = recv_msg(dev->mcast_sock, message->data, OC_PDU_SIZE, - &message->endpoint, true); - if (count < 0) { - oc_message_unref(message); - return 0; - } - message->length = (size_t)count; - message->endpoint.flags = IPV6 | MULTICAST; - goto receive; - } + if (FD_ISSET(dev->mcast_sock, rdfds)) { + FD_CLR(dev->mcast_sock, rdfds); + int count = recv_msg(dev->mcast_sock, message->data, OC_PDU_SIZE, + &message->endpoint, true); + if (count < 0) { + oc_message_unref(message); + return 0; + } + message->length = (size_t)count; + message->endpoint.flags = IPV6 | MULTICAST; + goto receive; + } #ifdef OC_IPV4 - if (FD_ISSET(dev->server4_sock, rdfds)) { - FD_CLR(dev->server4_sock, rdfds); - int count = recv_msg(dev->server4_sock, message->data, OC_PDU_SIZE, - &message->endpoint, false); - if (count < 0) { - oc_message_unref(message); - return 0; - } - message->length = (size_t)count; - message->endpoint.flags = IPV4; - goto receive; - } + if (FD_ISSET(dev->server4_sock, rdfds)) { + FD_CLR(dev->server4_sock, rdfds); + int count = recv_msg(dev->server4_sock, message->data, OC_PDU_SIZE, + &message->endpoint, false); + if (count < 0) { + oc_message_unref(message); + return 0; + } + message->length = (size_t)count; + message->endpoint.flags = IPV4; + goto receive; + } - if (FD_ISSET(dev->mcast4_sock, rdfds)) { - FD_CLR(dev->mcast4_sock, rdfds); - int count = recv_msg(dev->mcast4_sock, message->data, OC_PDU_SIZE, - &message->endpoint, true); - if (count < 0) { - oc_message_unref(message); - return 0; - } - message->length = (size_t)count; - message->endpoint.flags = IPV4 | MULTICAST; - goto receive; - } + if (FD_ISSET(dev->mcast4_sock, rdfds)) { + FD_CLR(dev->mcast4_sock, rdfds); + int count = recv_msg(dev->mcast4_sock, message->data, OC_PDU_SIZE, + &message->endpoint, true); + if (count < 0) { + oc_message_unref(message); + return 0; + } + message->length = (size_t)count; + message->endpoint.flags = IPV4 | MULTICAST; + goto receive; + } #endif /* OC_IPV4 */ #ifdef OC_SECURITY - if (FD_ISSET(dev->secure_sock, rdfds)) { - FD_CLR(dev->secure_sock, rdfds); - int count = recv_msg(dev->secure_sock, message->data, OC_PDU_SIZE, - &message->endpoint, false); - if (count < 0) { - oc_message_unref(message); - return 0; - } - message->length = (size_t)count; - message->endpoint.flags = IPV6 | SECURED; - message->encrypted = 1; - goto receive; - } + if (FD_ISSET(dev->secure_sock, rdfds)) { + FD_CLR(dev->secure_sock, rdfds); + int count = recv_msg(dev->secure_sock, message->data, OC_PDU_SIZE, + &message->endpoint, false); + if (count < 0) { + oc_message_unref(message); + return 0; + } + message->length = (size_t)count; + message->endpoint.flags = IPV6 | SECURED; + message->encrypted = 1; + goto receive; + } #ifdef OC_IPV4 - if (FD_ISSET(dev->secure4_sock, rdfds)) { - FD_CLR(dev->secure4_sock, rdfds); - int count = recv_msg(dev->secure4_sock, message->data, OC_PDU_SIZE, - &message->endpoint, false); - if (count < 0) { - oc_message_unref(message); - return 0; - } - message->length = (size_t)count; - message->endpoint.flags = IPV4 | SECURED; - message->encrypted = 1; - goto receive; - } + if (FD_ISSET(dev->secure4_sock, rdfds)) { + FD_CLR(dev->secure4_sock, rdfds); + int count = recv_msg(dev->secure4_sock, message->data, OC_PDU_SIZE, + &message->endpoint, false); + if (count < 0) { + oc_message_unref(message); + return 0; + } + message->length = (size_t)count; + message->endpoint.flags = IPV4 | SECURED; + message->encrypted = 1; + goto receive; + } #endif /* OC_IPV4 */ #endif /* OC_SECURITY */ #ifdef OC_TCP - adapter_receive_state_t tcp_status = - oc_tcp_receive_message(dev, rdfds, message); - if (tcp_status == ADAPTER_STATUS_RECEIVE) { - goto receive; - } + adapter_receive_state_t tcp_status = + oc_tcp_receive_message(dev, rdfds, message); + if (tcp_status == ADAPTER_STATUS_RECEIVE) { + goto receive; + } #endif /* OC_TCP */ - oc_message_unref(message); - return 0; + oc_message_unref(message); + return 0; - receive: - OC_DBG("Incoming message of size %zd bytes from", message->length); - OC_LOGipaddr(message->endpoint); - OC_DBG("%s", ""); - oc_network_receive_event(message); - return 1; +receive: + OC_DBG("Incoming message of size %zd bytes from", message->length); + OC_LOGipaddr(message->endpoint); + OC_DBG("%s", ""); + oc_network_receive_event(message); + return 1; } static int @@ -1031,8 +1030,8 @@ process_event(ip_context_t *dev, fd_set *rdfds, fd_set *wfds) } } // GCOVR_EXCL_STOP -#else /* !OC_DBG_IS_ENABLED */ - (void)wfds; +#else /* !OC_DBG_IS_ENABLED */ + (void)wfds; #endif /* OC_DBG_IS_ENABLED */ } @@ -1063,9 +1062,9 @@ process_events(ip_context_t *dev, fd_set *rdfds, fd_set *wfds, int fd_count, } #endif /* OC_NETLINK_IF_CHANGE_NOTIFICATIONS_AVAILABLE */ - //if (process_socket_signal_event(dev, rdfds)) { - // fd_count--; - //} + // if (process_socket_signal_event(dev, rdfds)) { + // fd_count--; + // } #ifdef OC_DYNAMIC_ALLOCATION // check if network queue can consume all 'ready' events @@ -1109,7 +1108,7 @@ network_event_thread(void *data) while (dev->terminate != 1) { fd_set rdfds = dev->rfds; - #ifdef OC_DYNAMIC_ALLOCATION +#ifdef OC_DYNAMIC_ALLOCATION if (!fd_sets_are_equal(&rdfds, &last_rdfds)) { // fd set has changed -> recalculate max fd max_read_fd = fds_max(&rdfds); @@ -1134,7 +1133,6 @@ network_event_thread(void *data) } process_events(dev, &rdfds, NULL, n, max_read_fd); - } pthread_exit(NULL); return NULL; From fcc53523b0894e814668b2c1e404b01b6834a3ba Mon Sep 17 00:00:00 2001 From: sp-martin Date: Wed, 5 Jun 2024 20:54:29 +0000 Subject: [PATCH 17/35] - fixed build break after automerge --- port/oc_connectivity_internal.h | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/port/oc_connectivity_internal.h b/port/oc_connectivity_internal.h index 2ca5741975..cd5ac30d71 100644 --- a/port/oc_connectivity_internal.h +++ b/port/oc_connectivity_internal.h @@ -74,20 +74,6 @@ int oc_send_buffer2(oc_message_t *message, bool queue); void oc_connectivity_wakeup(size_t device); #endif /* OC_DYNAMIC_ALLOCATION */ -#ifdef OC_HAS_FEATURE_TCP_ASYNC_CONNECT -typedef struct -{ - uint8_t max_count; ///< maximal number of retries for opening a single TCP - /// connection (default: 5) - uint16_t timeout; ///< timeout of a single retry in seconds (default: 5) -} oc_tcp_connect_retry_t; - -#define OC_TCP_CONNECT_RETRY_MAX_COUNT 5 -#define OC_TCP_CONNECT_RETRY_TIMEOUT 5 - -void oc_tcp_set_connect_retry(uint8_t max_count, uint16_t timeout); -#endif /* OC_HAS_FEATURE_TCP_ASYNC_CONNECT */ - #ifdef OC_NETWORK_MONITOR /** * @brief the callback function for an network change From 2b2f467908d3f304c7a4024e453c50468e673861 Mon Sep 17 00:00:00 2001 From: sp-martin Date: Thu, 6 Jun 2024 06:15:40 +0000 Subject: [PATCH 18/35] - fixed build break when DOC_DYNAMIC_ALLOCATION_ENABLED=OFF --- api/oc_network_events.c | 4 ++++ port/android/ipadapter.c | 5 +++++ port/linux/ipadapter.c | 4 ++++ 3 files changed, 13 insertions(+) diff --git a/api/oc_network_events.c b/api/oc_network_events.c index eb67823e82..d10e1349d1 100644 --- a/api/oc_network_events.c +++ b/api/oc_network_events.c @@ -45,6 +45,7 @@ static bool g_interface_up; static bool g_interface_down; #endif /* OC_NETWORK_MONITOR */ +#ifdef OC_DYNAMIC_ALLOCATION static size_t get_events_queue_length(size_t device, oc_list_t events) { @@ -73,6 +74,7 @@ send_wakeup_signal(oc_list_t events) ++deviceId; // advance to the next device } } +#endif /* OC_DYNAMIC_ALLOCATION */ static void oc_process_network_event(void) @@ -248,6 +250,7 @@ oc_network_interface_event(oc_interface_event_t event) } #endif /* OC_NETWORK_MONITOR */ +#ifdef OC_DYNAMIC_ALLOCATION size_t oc_network_get_event_queue_length(size_t device) { @@ -256,3 +259,4 @@ oc_network_get_event_queue_length(size_t device) oc_network_event_handler_mutex_unlock(); return msg_count; } +#endif /* OC_DYNAMIC_ALLOCATION */ diff --git a/port/android/ipadapter.c b/port/android/ipadapter.c index 2cc9eee014..6cba087279 100644 --- a/port/android/ipadapter.c +++ b/port/android/ipadapter.c @@ -38,6 +38,7 @@ #include "port/oc_connectivity_internal.h" #include "port/oc_log_internal.h" #include "port/oc_network_event_handler_internal.h" +#include "port/oc_random.h" #include "util/oc_macros_internal.h" #ifdef OC_SESSION_EVENTS @@ -779,6 +780,7 @@ recv_msg(int sock, uint8_t *recv_buf, int recv_buf_size, return ret; } +#ifdef OC_DYNAMIC_ALLOCATION static bool fd_sets_are_equal(const fd_set *fd1, const fd_set *fd2) { @@ -841,6 +843,7 @@ remove_random_fds(fd_set *rdfds, int rfds_count, int max_fd, int remove_count) } return removed; } +#endif /* OC_DYNAMIC_ALLOCATION */ static void add_control_flow_rfds(fd_set *output_set, const ip_context_t *dev) @@ -1776,6 +1779,7 @@ signal_event_thread(ip_context_t *dev) } } +#ifdef OC_DYNAMIC_ALLOCATION void oc_connectivity_wakeup(size_t device) { @@ -1787,6 +1791,7 @@ oc_connectivity_wakeup(size_t device) signal_event_thread(dev); } +#endif /* OC_DYNAMIC_ALLOCATION */ void oc_connectivity_shutdown(size_t device) diff --git a/port/linux/ipadapter.c b/port/linux/ipadapter.c index 42bdce2bf2..38990e1f77 100644 --- a/port/linux/ipadapter.c +++ b/port/linux/ipadapter.c @@ -892,6 +892,7 @@ process_event(ip_context_t *dev, fd_set *rdfds, fd_set *wfds) return 0; } +#ifdef OC_DYNAMIC_ALLOCATION static bool fd_sets_are_equal(const fd_set *fd1, const fd_set *fd2) { @@ -954,6 +955,7 @@ remove_random_fds(fd_set *rdfds, int rfds_count, int max_fd, int remove_count) } return removed; } +#endif /* OC_DYNAMIC_ALLOCATION */ static void process_events(ip_context_t *dev, fd_set *rdfds, fd_set *wfds, int fd_count, @@ -1650,6 +1652,7 @@ oc_connectivity_init(size_t device, oc_connectivity_ports_t ports) return 0; } +#ifdef OC_DYNAMIC_ALLOCATION void oc_connectivity_wakeup(size_t device) { @@ -1661,6 +1664,7 @@ oc_connectivity_wakeup(size_t device) signal_event_thread(dev); } +#endif /* OC_DYNAMIC_ALLOCATION */ void oc_connectivity_shutdown(size_t device) From e3199dcba3f2ff2f844df600cec7aa36013be1c2 Mon Sep 17 00:00:00 2001 From: sp-martin Date: Thu, 6 Jun 2024 06:33:08 +0000 Subject: [PATCH 19/35] - fixed android builds --- port/android/ipadapter.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/port/android/ipadapter.c b/port/android/ipadapter.c index 6cba087279..ab30f13c96 100644 --- a/port/android/ipadapter.c +++ b/port/android/ipadapter.c @@ -784,7 +784,7 @@ recv_msg(int sock, uint8_t *recv_buf, int recv_buf_size, static bool fd_sets_are_equal(const fd_set *fd1, const fd_set *fd2) { - return (memcmp(__FDS_BITS(fd1), __FDS_BITS(fd2), sizeof(__FDS_BITS(fd1))) == +return memcmp(fd1->fds_bits, fd2->fds_bits , sizeof(fd1->fds_bits)) == 0); } From 497f5031adfd28fb769243a7083d3ba0fcc2ac40 Mon Sep 17 00:00:00 2001 From: sp-martin Date: Thu, 6 Jun 2024 07:04:55 +0000 Subject: [PATCH 20/35] - fixed handling of tcp controlflow sockets on android --- port/android/ipadapter.c | 6 +++--- port/android/tcpadapter.c | 7 ++++++- port/android/tcpadapter.h | 2 ++ 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/port/android/ipadapter.c b/port/android/ipadapter.c index ab30f13c96..bb69895076 100644 --- a/port/android/ipadapter.c +++ b/port/android/ipadapter.c @@ -784,7 +784,7 @@ recv_msg(int sock, uint8_t *recv_buf, int recv_buf_size, static bool fd_sets_are_equal(const fd_set *fd1, const fd_set *fd2) { -return memcmp(fd1->fds_bits, fd2->fds_bits , sizeof(fd1->fds_bits)) == +return (memcmp(fd1->fds_bits, fd2->fds_bits , sizeof(fd1->fds_bits)) == 0); } @@ -1101,7 +1101,7 @@ network_event_thread(void *data) add_control_flow_rfds(&dev->rfds, dev); #ifdef OC_TCP oc_tcp_add_socks_to_fd_set(dev); - tcp_add_controlflow_socks_to_rfd_set(&dev->rfds, dev); + oc_tcp_add_controlflow_socks_to_rfd_set(&dev->rfds, dev); #endif /* OC_TCP */ int max_read_fd = FD_SETSIZE; @@ -1124,7 +1124,7 @@ network_event_thread(void *data) FD_ZERO(&rdfds); add_control_flow_rfds(&rdfds, dev); #ifdef OC_TCP - tcp_add_controlflow_socks_to_rfd_set(&rdfds, dev); + oc_tcp_add_controlflow_socks_to_rfd_set(&rdfds, dev); #endif /* OC_TCP */ } #endif /* OC_DYNAMIC_ALLOCATION */ diff --git a/port/android/tcpadapter.c b/port/android/tcpadapter.c index ccb81ec61b..0e05e99f62 100644 --- a/port/android/tcpadapter.c +++ b/port/android/tcpadapter.c @@ -186,7 +186,12 @@ oc_tcp_add_socks_to_fd_set(ip_context_t *dev) FD_SET(dev->tcp.secure4_sock, &dev->rfds); #endif /* OC_SECURITY */ #endif /* OC_IPV4 */ - FD_SET(dev->tcp.connect_pipe[0], &dev->rfds); +} + +void +oc_tcp_add_controlflow_socks_to_rfd_set(fd_set *rfd_set, const ip_context_t *dev) +{ + FD_SET(dev->tcp.connect_pipe[0], rfd_set); } static void diff --git a/port/android/tcpadapter.h b/port/android/tcpadapter.h index a48c870b6c..4838bc430e 100644 --- a/port/android/tcpadapter.h +++ b/port/android/tcpadapter.h @@ -36,6 +36,8 @@ int oc_tcp_send_buffer(ip_context_t *dev, oc_message_t *message, void oc_tcp_add_socks_to_fd_set(ip_context_t *dev); +void oc_tcp_add_controlflow_socks_to_rfd_set(fd_set *rfd_set, const ip_context_t *dev); + adapter_receive_state_t oc_tcp_receive_message(ip_context_t *dev, fd_set *fds, oc_message_t *message); From 129c20688e91f6bbc662ed955526aae5756bdcfb Mon Sep 17 00:00:00 2001 From: sp-martin Date: Thu, 6 Jun 2024 07:15:08 +0000 Subject: [PATCH 21/35] - formatting, android build break fix --- port/android/ipadapter.c | 4 ++-- port/android/tcpadapter.c | 3 ++- port/android/tcpadapter.h | 3 ++- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/port/android/ipadapter.c b/port/android/ipadapter.c index bb69895076..e47c176a10 100644 --- a/port/android/ipadapter.c +++ b/port/android/ipadapter.c @@ -784,8 +784,7 @@ recv_msg(int sock, uint8_t *recv_buf, int recv_buf_size, static bool fd_sets_are_equal(const fd_set *fd1, const fd_set *fd2) { -return (memcmp(fd1->fds_bits, fd2->fds_bits , sizeof(fd1->fds_bits)) == - 0); + return (memcmp(fd1->fds_bits, fd2->fds_bits, sizeof(fd1->fds_bits)) == 0); } static int @@ -1036,6 +1035,7 @@ process_event(ip_context_t *dev, fd_set *rdfds, fd_set *wfds) #else /* !OC_DBG_IS_ENABLED */ (void)wfds; #endif /* OC_DBG_IS_ENABLED */ + return 0; } static void diff --git a/port/android/tcpadapter.c b/port/android/tcpadapter.c index 0e05e99f62..b3296b5780 100644 --- a/port/android/tcpadapter.c +++ b/port/android/tcpadapter.c @@ -189,7 +189,8 @@ oc_tcp_add_socks_to_fd_set(ip_context_t *dev) } void -oc_tcp_add_controlflow_socks_to_rfd_set(fd_set *rfd_set, const ip_context_t *dev) +oc_tcp_add_controlflow_socks_to_rfd_set(fd_set *rfd_set, + const ip_context_t *dev) { FD_SET(dev->tcp.connect_pipe[0], rfd_set); } diff --git a/port/android/tcpadapter.h b/port/android/tcpadapter.h index 4838bc430e..8f1f8deccc 100644 --- a/port/android/tcpadapter.h +++ b/port/android/tcpadapter.h @@ -36,7 +36,8 @@ int oc_tcp_send_buffer(ip_context_t *dev, oc_message_t *message, void oc_tcp_add_socks_to_fd_set(ip_context_t *dev); -void oc_tcp_add_controlflow_socks_to_rfd_set(fd_set *rfd_set, const ip_context_t *dev); +void oc_tcp_add_controlflow_socks_to_rfd_set(fd_set *rfd_set, + const ip_context_t *dev); adapter_receive_state_t oc_tcp_receive_message(ip_context_t *dev, fd_set *fds, oc_message_t *message); From 65ffb5da633b8a1382c90c7c4f8a71d69f2c4aca Mon Sep 17 00:00:00 2001 From: sp-martin Date: Thu, 6 Jun 2024 13:07:47 +0000 Subject: [PATCH 22/35] - linux build break fix --- port/linux/ipadapter.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/port/linux/ipadapter.c b/port/linux/ipadapter.c index 38990e1f77..49b4f57c98 100644 --- a/port/linux/ipadapter.c +++ b/port/linux/ipadapter.c @@ -896,8 +896,7 @@ process_event(ip_context_t *dev, fd_set *rdfds, fd_set *wfds) static bool fd_sets_are_equal(const fd_set *fd1, const fd_set *fd2) { - return (memcmp(__FDS_BITS(fd1), __FDS_BITS(fd2), sizeof(__FDS_BITS(fd1))) == - 0); + return (memcmp(fd1->fds_bits, fd2->fds_bits, sizeof(fd1->fds_bits)) == 0); } static int From ec4dac248d1907882aecd39745fae7945f87b75f Mon Sep 17 00:00:00 2001 From: sp-martin Date: Thu, 6 Jun 2024 15:20:55 +0000 Subject: [PATCH 23/35] - unix amd64/arm64 build break fix --- port/linux/ipadapter.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/port/linux/ipadapter.c b/port/linux/ipadapter.c index 49b4f57c98..2126c9467a 100644 --- a/port/linux/ipadapter.c +++ b/port/linux/ipadapter.c @@ -896,7 +896,12 @@ process_event(ip_context_t *dev, fd_set *rdfds, fd_set *wfds) static bool fd_sets_are_equal(const fd_set *fd1, const fd_set *fd2) { +#ifdef __FDS_BITS + return (memcmp(__FDS_BITS(fd1), __FDS_BITS(fd2), sizeof(__FDS_BITS(fd1))) == + 0); +#else //!__FDS_BITS return (memcmp(fd1->fds_bits, fd2->fds_bits, sizeof(fd1->fds_bits)) == 0); +#endif //__FDS_BITS } static int From 0b456a5e95bdb941baf65fae2ce8aa679282f0d1 Mon Sep 17 00:00:00 2001 From: sp-martin Date: Fri, 7 Jun 2024 07:05:30 +0000 Subject: [PATCH 24/35] - esp32 port of Message Queue Limit --- port/esp32/adapter/src/ipadapter.c | 271 +++++++++++++++++++++++----- port/esp32/adapter/src/tcpadapter.c | 8 +- port/esp32/adapter/src/tcpadapter.h | 3 + 3 files changed, 233 insertions(+), 49 deletions(-) diff --git a/port/esp32/adapter/src/ipadapter.c b/port/esp32/adapter/src/ipadapter.c index fa214aeae9..40cb2a4633 100644 --- a/port/esp32/adapter/src/ipadapter.c +++ b/port/esp32/adapter/src/ipadapter.c @@ -27,6 +27,7 @@ #include "port/oc_connectivity_internal.h" #include "port/oc_log_internal.h" #include "port/oc_network_event_handler_internal.h" +#include "port/oc_random.h" #include "ipcontext.h" #include "oc_buffer.h" #include "oc_core_res.h" @@ -804,78 +805,250 @@ oc_udp_receive_message(ip_context_t *dev, fd_set *fds, oc_message_t *message) return ADAPTER_STATUS_NONE; } -static void * -network_event_thread(void *data) +#ifdef OC_DYNAMIC_ALLOCATION +static bool +fd_sets_are_equal(const fd_set *fd1, const fd_set *fd2) { - ip_context_t *dev = (ip_context_t *)data; + return (memcmp(fd1, fd2, sizeof(fd_set)) == 0); +} + +static int +fds_max(const fd_set *sourcefds) +{ + int max_fd = 0; + for (int i = 0; i < FD_SETSIZE; i++) { + if (FD_ISSET(i, sourcefds)) { + max_fd = i; + } + } + return max_fd; +} + +static int +fds_count(const fd_set *sourcefds, int max_fd) +{ + int rfd_count = 0; + for (int i = 0; i <= max_fd; i++) { + if (FD_ISSET(i, sourcefds)) { + rfd_count++; + } + } + return rfd_count; +} + +static int +pick_random_fd(const fd_set *sourcefds, int fd_count, int max_fd) +{ + assert(fd_count > 0); + int random_rfd = (int)oc_random_value() % fd_count; + for (int i = 0; i <= max_fd; i++) { + if (FD_ISSET(i, sourcefds)) { + if (--fd_count == random_rfd) { + return i; + } + } + } + return -1; +} + +static int +remove_random_fds(fd_set *rdfds, int rfds_count, int max_fd, int remove_count) +{ + int removed = 0; + while (removed < remove_count) { + int fd = pick_random_fd(rdfds, rfds_count, max_fd); + if (fd < 0) { + break; + } + // remove file descriptor from the set + FD_CLR(fd, rdfds); + --rfds_count; + ++removed; + } + return removed; +} +#endif /* OC_DYNAMIC_ALLOCATION */ + +static bool +process_wakeup_signal(ip_context_t *dev, fd_set *fds) +{ + if (FD_ISSET(dev->wakeup_pipe[0], fds)) { + FD_CLR(dev->wakeup_pipe[0], fds); + ssize_t len; + do { + char buf; + // write to pipe shall not block - so read the byte we wrote + len = read(dev->wakeup_pipe[0], &buf, 1); + } while (len < 0 && errno == EINTR); + return true; + } + return false; +} + +static void +add_control_flow_rfds(fd_set *output_set, const ip_context_t *dev) +{ + /* Monitor network interface changes on the platform from only the 0th + * logical device - fd_set setfds; - FD_ZERO(&dev->rfds); - /* Monitor network interface changes on the platform from only the 0th logical - * device if (dev->device == 0) { - FD_SET(ifchange_sock, &dev->rfds); + FD_SET(ifchange_sock, output_set); } - */ - FD_SET(dev->wakeup_pipe[0], &dev->rfds); + */ + FD_SET(dev->wakeup_pipe[0], output_set); +} - oc_udp_add_socks_to_fd_set(dev); +static int +process_socket_read_event(ip_context_t *dev, fd_set *rdfds) +{ + oc_message_t *message = oc_allocate_message(); + if (message == NULL) { + return -1; + } + message->endpoint.device = dev->device; + + if (oc_udp_receive_message(dev, rdfds, message) == ADAPTER_STATUS_RECEIVE) { + OC_DBG("network_event_thread oc_udp_receive_message"); + goto receive; + } #ifdef OC_TCP - oc_tcp_add_socks_to_fd_set(dev); + if (oc_tcp_receive_message(dev, rdfds, message) == ADAPTER_STATUS_RECEIVE) { + OC_DBG("network_event_thread oc_tcp_receive_message"); + goto receive; + } #endif /* OC_TCP */ - int i, n; + oc_message_unref(message); + return 0; - while (dev->terminate != 1) { - setfds = dev->rfds; - n = select(FD_SETSIZE, &setfds, NULL, NULL, NULL); +receive: + OC_DBG("Incoming message of size %zd bytes from", message->length); + OC_LOGipaddr(message->endpoint); + OC_DBG("interface index %d", message->endpoint.interface_index); + OC_DBG("%s", ""); - if (FD_ISSET(dev->wakeup_pipe[0], &setfds)) { - OC_DBG("network_event_thread select: dev->wakeup_pipe[0]"); - char buf; - // write to pipe shall not block - so read the byte we wrote - if (read(dev->wakeup_pipe[0], &buf, 1) < 0) { - // intentionally left blank + oc_network_receive_event(message); + return 1; +} + +static int +process_event(ip_context_t *dev, fd_set *rdfds, fd_set *wfds) +{ + if (rdfds != NULL) { + int ret = process_socket_read_event(dev, rdfds); + if (ret != 0) { + return ret; + } + } + +#if OC_DBG_IS_ENABLED + // GCOVR_EXCL_START + if (rdfds != NULL) { + for (int i = 0; i < FD_SETSIZE; ++i) { + if (FD_ISSET(i, rdfds)) { + OC_DBG("no handler found for read event (fd=%d)", i); } } + } + if (wfds != NULL) { + for (int i = 0; i < FD_SETSIZE; ++i) { + if (FD_ISSET(i, wfds)) { + OC_DBG("no handler found for write event (fd=%d)", i); + } + } + } + // GCOVR_EXCL_STOP +#else /* !OC_DBG_IS_ENABLED */ + (void)wfds; +#endif /* OC_DBG_IS_ENABLED */ + return 0; +} - if (dev->terminate) { +static void +process_events(ip_context_t *dev, fd_set *rdfds, fd_set *wfds, int fd_count, + int max_read_fd) +{ + if (fd_count == 0) { + OC_DBG("process_events: timeout"); + return; + } + + OC_DBG("processing %d events", fd_count); + + // process control flow events + if (process_wakeup_signal(dev, rdfds)) { + fd_count--; + } + +#ifdef OC_DYNAMIC_ALLOCATION + // check if network queue can consume all 'ready' events + int available_count = OC_DEVICE_MAX_NUM_CONCURRENT_REQUESTS - + oc_network_get_event_queue_length(dev->device); + if (available_count < fd_count) { + // get the number of read file descriptors + int rfds_count = fds_count(rdfds, max_read_fd); + int removed = remove_random_fds(rdfds, rfds_count, max_read_fd, + rfds_count - available_count); + fd_count -= removed; + } +#else /* !OC_DYNAMIC_ALLOCATION */ + (void)max_read_fd; +#endif /* OC_DYNAMIC_ALLOCATION */ + + for (int i = 0; i < fd_count; i++) { + if (process_event(dev, rdfds, wfds) < 0) { break; } + } +} - for (i = 0; i < n; i++) { - oc_message_t *message = oc_allocate_message(); +static void * +network_event_thread(void *data) +{ + ip_context_t *dev = (ip_context_t *)data; + FD_ZERO(&dev->rfds); - if (!message) { - break; - } + oc_udp_add_socks_to_fd_set(dev); + add_control_flow_rfds(&dev->rfds, dev); +#ifdef OC_TCP + oc_tcp_add_socks_to_fd_set(dev); + oc_tcp_add_controlflow_socks_to_rfd_set(&dev->rfds, dev); +#endif /* OC_TCP */ - message->endpoint.device = dev->device; + // int i, n; + int max_read_fd = FD_SETSIZE; + fd_set last_rdfds; + FD_ZERO(&last_rdfds); - if (oc_udp_receive_message(dev, &setfds, message) == - ADAPTER_STATUS_RECEIVE) { - OC_DBG("network_event_thread oc_udp_receive_message"); - goto common; - } + while (dev->terminate != 1) { + // setfds = dev->rfds; + fd_set rdfds = dev->rfds; + +#ifdef OC_DYNAMIC_ALLOCATION + if (!fd_sets_are_equal(&rdfds, &last_rdfds)) { + // fd set has changed -> recalculate max fd + max_read_fd = fds_max(&rdfds); + last_rdfds = rdfds; + } + + if (oc_network_get_event_queue_length(dev->device) >= + OC_DEVICE_MAX_NUM_CONCURRENT_REQUESTS) { + // the queue is full -> add only control flow rfds + FD_ZERO(&rdfds); + add_control_flow_rfds(&rdfds, dev); #ifdef OC_TCP - if (oc_tcp_receive_message(dev, &setfds, message) == - ADAPTER_STATUS_RECEIVE) { - OC_DBG("network_event_thread oc_tcp_receive_message"); - goto common; - } + oc_tcp_add_controlflow_socks_to_rfd_set(&rdfds, dev); #endif /* OC_TCP */ + } +#endif /* OC_DYNAMIC_ALLOCATION */ - oc_message_unref(message); - continue; - - common: - OC_DBG("Incoming message of size %zd bytes from", message->length); - OC_LOGipaddr(message->endpoint); - OC_DBG("interface index %d", message->endpoint.interface_index); - OC_DBG("%s", ""); + int n = select(FD_SETSIZE, &rdfds, NULL, NULL, NULL); - oc_network_receive_event(message); + if (dev->terminate) { + break; } + + process_events(dev, &rdfds, NULL, n, max_read_fd); } return NULL; } @@ -1586,6 +1759,7 @@ signal_event_thread(ip_context_t *dev) } } +#ifdef OC_DYNAMIC_ALLOCATION void oc_connectivity_wakeup(size_t device) { @@ -1597,6 +1771,7 @@ oc_connectivity_wakeup(size_t device) signal_event_thread(dev); } +#endif /* OC_DYNAMIC_ALLOCATION */ void oc_connectivity_shutdown(size_t device) diff --git a/port/esp32/adapter/src/tcpadapter.c b/port/esp32/adapter/src/tcpadapter.c index b07c29e2ca..a3cc31726b 100644 --- a/port/esp32/adapter/src/tcpadapter.c +++ b/port/esp32/adapter/src/tcpadapter.c @@ -156,7 +156,13 @@ oc_tcp_add_socks_to_fd_set(ip_context_t *dev) FD_SET(dev->tcp.secure4_sock, &dev->rfds); #endif /* OC_SECURITY */ #endif /* OC_IPV4 */ - FD_SET(dev->tcp.connect_pipe[0], &dev->rfds); +} + +void +oc_tcp_add_controlflow_socks_to_rfd_set(fd_set *rfd_set, + const ip_context_t *dev) +{ + FD_SET(dev->tcp.connect_pipe[0], rfd_set); } static void diff --git a/port/esp32/adapter/src/tcpadapter.h b/port/esp32/adapter/src/tcpadapter.h index a48c870b6c..8f1f8deccc 100644 --- a/port/esp32/adapter/src/tcpadapter.h +++ b/port/esp32/adapter/src/tcpadapter.h @@ -36,6 +36,9 @@ int oc_tcp_send_buffer(ip_context_t *dev, oc_message_t *message, void oc_tcp_add_socks_to_fd_set(ip_context_t *dev); +void oc_tcp_add_controlflow_socks_to_rfd_set(fd_set *rfd_set, + const ip_context_t *dev); + adapter_receive_state_t oc_tcp_receive_message(ip_context_t *dev, fd_set *fds, oc_message_t *message); From 95e6cdaa11e1858610ec82590a687a386dc1de68 Mon Sep 17 00:00:00 2001 From: Milos Bazelides Date: Mon, 10 Jun 2024 14:50:52 +0200 Subject: [PATCH 25/35] Added Windows port of message queue limit. --- port/windows/ipadapter.c | 186 ++++++++++++++++++++++++++------------- port/windows/ipcontext.h | 3 + port/windows/oc_config.h | 5 ++ 3 files changed, 131 insertions(+), 63 deletions(-) diff --git a/port/windows/ipadapter.c b/port/windows/ipadapter.c index 4bb322ef38..cbfea1f432 100644 --- a/port/windows/ipadapter.c +++ b/port/windows/ipadapter.c @@ -53,6 +53,9 @@ #include #endif /* OC_DYNAMIC_ALLOCATION */ +/* Maximum possible number of WSAEVENTs to be waited on. */ +#define MAX_WSAEVENT_ARRAY_SIZE 8 + #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 @@ -723,80 +726,118 @@ network_event_thread(void *data) #endif /* OC_IPV4 */ #undef OC_WSAEVENTSELECT - DWORD events_list_size = 0; - WSAEVENT events_list[7]; - DWORD IFCHANGE = 0; + WSAEVENT event_list[MAX_WSAEVENT_ARRAY_SIZE]; + DWORD event_list_size = 0; + + // Add control flow events. if (dev->device == 0) { - events_list[0] = ifchange_event.hEvent; - events_list_size++; + event_list[event_list_size++] = ifchange_event.hEvent; process_interface_change_event(); } - DWORD MCAST6 = events_list_size; - events_list[events_list_size] = mcast6_event; - events_list_size++; - DWORD SERVER6 = events_list_size; - events_list[events_list_size] = server6_event; - events_list_size++; -#if defined(OC_SECURITY) - DWORD SECURE6 = events_list_size; - events_list[events_list_size] = secure6_event; - events_list_size++; -#if defined(OC_IPV4) - DWORD MCAST4 = events_list_size; - events_list[events_list_size] = mcast4_event; - events_list_size++; - DWORD SERVER4 = events_list_size; - events_list[events_list_size] = server4_event; - events_list_size++; - DWORD SECURE4 = events_list_size; - events_list[events_list_size] = secure4_event; - events_list_size++; -#endif /* OC_IPV4 */ -#elif defined(OC_IPV4) /* OC_SECURITY */ - DWORD MCAST4 = events_list_size; - events_list[events_list_size] = mcast4_event; - events_list_size++; - DWORD SERVER4 = events_list_size; - events_list[events_list_size] = server4_event; - events_list_size++; -#endif /* !OC_SECURITY */ - - DWORD i, index; +#ifdef OC_DYNAMIC_ALLOCATION + event_list[event_list_size++] = dev->wake_up_event; +#endif // OC_DYNAMIC_ALLOCATION + DWORD control_flow_event_count = event_list_size; + + // Add remaining message events. + event_list[event_list_size++] = mcast6_event; + event_list[event_list_size++] = server6_event; +#ifdef OC_SECURITY + event_list[event_list_size++] = secure6_event; +#ifdef OC_IPV4 + event_list[event_list_size++] = mcast4_event; + event_list[event_list_size++] = server4_event; + event_list[event_list_size++] = secure4_event; +#endif /* OC_IPV4 */ +#else /* OC_SECURITY */ + event_list[event_list_size++] = mcast4_event; + event_list[event_list_size++] = server4_event; +#endif /* !OC_SECURITY */ while (!dev->terminate) { - index = WSAWaitForMultipleEvents(events_list_size, events_list, FALSE, - INFINITE, FALSE); - index -= WSA_WAIT_EVENT_0; - for (i = index; !dev->terminate && i < events_list_size; i++) { - index = WSAWaitForMultipleEvents(1, &events_list[i], TRUE, 0, FALSE); - if (index != WSA_WAIT_TIMEOUT && index != WSA_WAIT_FAILED) { - if (WSAResetEvent(events_list[i]) == FALSE) { + DWORD event_count = event_list_size; + +#ifdef OC_DYNAMIC_ALLOCATION + DWORD queue_length = (DWORD)oc_network_get_event_queue_length(dev->device); + if (queue_length >= OC_DEVICE_MAX_NUM_CONCURRENT_REQUESTS) { + // Network event queue is full, wait only for control flow events. + event_count = control_flow_event_count; + } +#endif /* OC_DYNAMIC_ALLOCATION */ + + DWORD i = + WSAWaitForMultipleEvents(event_count, event_list, FALSE, INFINITE, FALSE); + i -= WSA_WAIT_EVENT_0; + + // Process control flow events. + for (; i < control_flow_event_count; i++) { + + WSAEVENT cf_event = event_list[i]; + DWORD ret = WSAWaitForMultipleEvents(1, &cf_event, TRUE, 0, FALSE); + + if (ret != WSA_WAIT_TIMEOUT && ret != WSA_WAIT_FAILED) { + if (WSAResetEvent(cf_event) == FALSE) { OC_WRN("WSAResetEvent returned error: %d", WSAGetLastError()); } - if (dev->device == 0 && i == IFCHANGE) { + if (dev->device == 0 && cf_event == ifchange_event.hEvent) { process_interface_change_event(); DWORD bytes_returned = 0; if (WSAIoctl(ifchange_sock, SIO_ADDRESS_LIST_CHANGE, NULL, 0, NULL, 0, &bytes_returned, &ifchange_event, NULL) == SOCKET_ERROR) { - DWORD err = GetLastError(); - if (err != ERROR_IO_PENDING) { + if (GetLastError() != ERROR_IO_PENDING) { OC_ERR("could not reset SIO_ADDRESS_LIST_CHANGE on network " "interface change socket"); } } - continue; } + } + } - oc_message_t *message = oc_allocate_message(); + // Collect signalled message events. + WSAEVENT msg_events[MAX_WSAEVENT_ARRAY_SIZE]; + DWORD msg_event_count = 0; + + for (; i < event_count; i++) { + DWORD ret = WSAWaitForMultipleEvents(1, event_list + i, TRUE, 0, FALSE); + if (ret != WSA_WAIT_TIMEOUT && ret != WSA_WAIT_FAILED) { + msg_events[msg_event_count++] = event_list[i]; + } + } + +#ifdef OC_DYNAMIC_ALLOCATION + // Randomly remove events from list if the queue is about to fill. + DWORD available_items = + OC_DEVICE_MAX_NUM_CONCURRENT_REQUESTS - queue_length; + DWORD items_to_remove = + msg_event_count - min(msg_event_count, available_items); + + while (items_to_remove--) { + DWORD rnd = (DWORD)rand() % msg_event_count; + msg_event_count--; + msg_events[rnd] = msg_events[msg_event_count]; + } +#endif /* OC_DYNAMIC_ALLOCATION */ - if (!message) { + // Process message events. + for (i = 0; !dev->terminate && i < msg_event_count; i++) { + + WSAEVENT msg_event = msg_events[i]; + DWORD ret = WSAWaitForMultipleEvents(1, &msg_event, TRUE, 0, FALSE); + + if (ret != WSA_WAIT_TIMEOUT && ret != WSA_WAIT_FAILED) { + if (WSAResetEvent(msg_event) == FALSE) { + OC_WRN("WSAResetEvent returned error: %d", WSAGetLastError()); + } + + oc_message_t *message = oc_allocate_message(); + if (message == NULL) { break; } message->endpoint.device = dev->device; - if (i == SERVER6) { + if (msg_event == server6_event) { int count = recv_msg(dev->server_sock, message->data, OC_PDU_SIZE, &message->endpoint, false); if (count < 0) { @@ -805,10 +846,9 @@ network_event_thread(void *data) } message->length = count; message->endpoint.flags = IPV6; - goto common; } - if (i == MCAST6) { + if (msg_event == mcast6_event) { int count = recv_msg(dev->mcast_sock, message->data, OC_PDU_SIZE, &message->endpoint, true); if (count < 0) { @@ -817,11 +857,10 @@ network_event_thread(void *data) } message->length = count; message->endpoint.flags = IPV6 | MULTICAST; - goto common; } #ifdef OC_IPV4 - if (i == SERVER4) { + if (msg_event == server4_event) { int count = recv_msg(dev->server4_sock, message->data, OC_PDU_SIZE, &message->endpoint, false); if (count < 0) { @@ -830,10 +869,9 @@ network_event_thread(void *data) } message->length = count; message->endpoint.flags = IPV4; - goto common; } - if (i == MCAST4) { + if (msg_event == mcast4_event) { int count = recv_msg(dev->mcast4_sock, message->data, OC_PDU_SIZE, &message->endpoint, true); if (count < 0) { @@ -842,12 +880,11 @@ network_event_thread(void *data) } message->length = count; message->endpoint.flags = IPV4 | MULTICAST; - goto common; } #endif /* OC_IPV4 */ #ifdef OC_SECURITY - if (i == SECURE6) { + if (msg_event == secure6_event) { int count = recv_msg(dev->secure_sock, message->data, OC_PDU_SIZE, &message->endpoint, false); if (count < 0) { @@ -857,10 +894,9 @@ network_event_thread(void *data) message->length = count; message->endpoint.flags = IPV6 | SECURED; message->encrypted = 1; - goto common; } #ifdef OC_IPV4 - if (i == SECURE4) { + if (msg_event == secure4_event) { int count = recv_msg(dev->secure4_sock, message->data, OC_PDU_SIZE, &message->endpoint, false); if (count < 0) { @@ -873,7 +909,7 @@ network_event_thread(void *data) } #endif /* OC_IPV4 */ #endif /* OC_SECURITY */ - common: + OC_DBG("Incoming message of size %zd bytes from", message->length); OC_LOGipaddr(message->endpoint); OC_DBG("%s", ""); @@ -882,8 +918,8 @@ network_event_thread(void *data) } } - for (i = 0; i < events_list_size; ++i) { - WSACloseEvent(events_list[i]); + for (DWORD i = 0; i < event_list_size; ++i) { + WSACloseEvent(event_list[i]); } return 0; @@ -1434,6 +1470,15 @@ oc_connectivity_init(size_t device, oc_connectivity_ports_t ports) oc_abort("Insufficient memory"); } +#ifdef OC_DYNAMIC_ALLOCATION + dev->wake_up_event = WSACreateEvent(); + if (dev->wake_up_event == WSA_INVALID_EVENT) { + OC_ERR("Creating wake up event for network event thread"); + oc_memb_free(&g_ip_context_s, dev); + return -1; + } +#endif /* OC_DYNAMIC_ALLOCATION */ + dev->device = device; OC_LIST_STRUCT_INIT(dev, eps); memset(&dev->mcast, 0, sizeof(dev->mcast)); @@ -1636,6 +1681,21 @@ oc_connectivity_init(size_t device, oc_connectivity_ports_t ports) return 0; } +void +oc_connectivity_wakeup(size_t device) +{ + ip_context_t *dev = get_ip_context_for_device(device); + if (dev == NULL) { + OC_WRN("no ip-context found for device(%zu)", device); + return; + } + + if (WSASetEvent(dev->wake_up_event) == FALSE) { + OC_WRN("cannot wake up network event thread (error: %d)", + WSAGetLastError()); + } +} + void oc_connectivity_shutdown(size_t device) { diff --git a/port/windows/ipcontext.h b/port/windows/ipcontext.h index 29b1fae39b..4fc9df003c 100644 --- a/port/windows/ipcontext.h +++ b/port/windows/ipcontext.h @@ -114,6 +114,9 @@ typedef struct ip_context_t BOOL terminate; size_t device; OC_ATOMIC_INT8_T flags; +#ifdef OC_DYNAMIC_ALLOCATION + WSAEVENT wake_up_event; +#endif /* OC_DYNAMIC_ALLOCATION */ } ip_context_t; #ifdef __cplusplus diff --git a/port/windows/oc_config.h b/port/windows/oc_config.h index 212997cb2c..45fd1c1710 100644 --- a/port/windows/oc_config.h +++ b/port/windows/oc_config.h @@ -50,6 +50,11 @@ typedef uint64_t oc_clock_time_t; /* Enable reallocation during encoding the representation to cbor */ // #define OC_REP_ENCODING_REALLOC +/* Maximum number of messages in the network event queue for a device */ +#ifndef OC_DEVICE_MAX_NUM_CONCURRENT_REQUESTS +#define OC_DEVICE_MAX_NUM_CONCURRENT_REQUESTS (32) +#endif /* OC_DEVICE_MAX_NUM_CONCURRENT_REQUESTS */ + /* Maximum size of uri for a collection resource */ // #define OC_MAX_COLLECTIONS_INSTANCE_URI_SIZE (64) From 315380992873ddcede10774bf2f205d292a5e801 Mon Sep 17 00:00:00 2001 From: Daniel Adam Date: Wed, 12 Jun 2024 10:42:50 +0200 Subject: [PATCH 26/35] Allow to set OC_DEVICE_MAX_NUM_CONCURRENT_REQUESTS in CMake --- .github/workflows/sonar-cloud-analysis.yml | 4 +- CMakeLists.txt | 85 ++++++++++++---------- 2 files changed, 49 insertions(+), 40 deletions(-) diff --git a/.github/workflows/sonar-cloud-analysis.yml b/.github/workflows/sonar-cloud-analysis.yml index f9578bb8f0..ee0407830f 100644 --- a/.github/workflows/sonar-cloud-analysis.yml +++ b/.github/workflows/sonar-cloud-analysis.yml @@ -27,8 +27,8 @@ jobs: 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" - # security off, ipv4 on, collection create on, push on - - build_args: "-DOC_SECURITY_ENABLED=OFF -DOC_IPV4_ENABLED=ON -DOC_COLLECTIONS_IF_CREATE_ENABLED=ON -DOC_PUSH_ENABLED=ON" + # security off, ipv4 on, collection create on, push on, max num concurrent requests=1 + - build_args: "-DOC_SECURITY_ENABLED=OFF -DOC_IPV4_ENABLED=ON -DOC_COLLECTIONS_IF_CREATE_ENABLED=ON -DOC_PUSH_ENABLED=ON -DOC_DEVICE_MAX_NUM_CONCURRENT_REQUESTS=1" # ipv6 dns on, oscore off, rep realloc on, json encoder on, introspection IDD off - build_args: "-DOC_DNS_LOOKUP_IPV6_ENABLED=ON -DOC_OSCORE_ENABLED=OFF -DOC_REPRESENTATION_REALLOC_ENCODING_ENABLED=ON -DOC_JSON_ENCODER_ENABLED=ON -DOC_IDD_API_ENABLED=OFF" # cloud (ipv4+tcp) on, dynamic allocation off, rfotm on, push off (because it forces dynamic allocation) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1d74677016..30f08b40c1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -19,6 +19,8 @@ if(BUILD_TESTING AND UNIX AND (OC_COMPILER_IS_GCC OR OC_COMPILER_IS_CLANG)) endif() ######## Build configuration options ######## +set(CMAKE_POSITION_INDEPENDENT_CODE ON) + set(BUILD_EXAMPLE_APPLICATIONS ON CACHE BOOL "Build example applications.") set(BUILD_MBEDTLS ON CACHE BOOL "Build Mbed TLS library. When set to OFF, the Mbed TLS library with the OCF patches has to be provided.") set(BUILD_MBEDTLS_FORCE_3_5_0 OFF CACHE BOOL "Force v3.5.0 of the MbedTLS library to be used (by default v3.1.0 is used by master)") @@ -57,15 +59,6 @@ set(OC_PUSH_ENABLED OFF CACHE BOOL "Enable Push Notification.") set(OC_PUSHDEBUG_ENABLED OFF CACHE BOOL "Enable debug messages for Push Notification.") set(OC_RESOURCE_ACCESS_IN_RFOTM_ENABLED OFF CACHE BOOL "Enable resource access in RFOTM.") set(OC_MEMORY_TRACE_ENABLED OFF CACHE BOOL "Enable memory tracing.") -if (OC_DEBUG_ENABLED) - set(OC_LOG_MAXIMUM_LOG_LEVEL "TRACE" CACHE STRING "Maximum supported log level in compile time.") -else() - set(OC_LOG_MAXIMUM_LOG_LEVEL "DISABLED" CACHE STRING "Maximum supported log level in compile time.") -endif() -set(OC_INOUT_BUFFER_SIZE "" CACHE STRING "Custom static buffer size for network messages.") -set(OC_INOUT_BUFFER_POOL "" CACHE STRING "Custom static pool size of network messages.") -set(OC_APP_DATA_BUFFER_SIZE "" CACHE STRING "Custom static buffer size for application messages.") -set(OC_APP_DATA_BUFFER_POOL "" CACHE STRING "Custom static size of application messages.") set(OC_VERSION_1_1_0_ENABLED OFF CACHE BOOL "Enable OCF version 1.1") set(OC_ETAG_ENABLED OFF CACHE BOOL "Enable Entity Tag (ETag) support.") set(OC_JSON_ENCODER_ENABLED OFF CACHE BOOL "Enable JSON encoder/decoder support.") @@ -75,7 +68,16 @@ if (BUILD_EXAMPLE_APPLICATIONS OR BUILD_TESTING) endif() set(PLGD_DEV_TIME_ENABLED OFF CACHE BOOL "Enable plgd time feature.") -set(CMAKE_POSITION_INDEPENDENT_CODE ON) +if (OC_DEBUG_ENABLED) + set(OC_LOG_MAXIMUM_LOG_LEVEL "TRACE" CACHE STRING "Maximum supported log level in compile time.") +else() + set(OC_LOG_MAXIMUM_LOG_LEVEL "DISABLED" CACHE STRING "Maximum supported log level in compile time.") +endif() +set(OC_INOUT_BUFFER_SIZE "" CACHE STRING "Custom static buffer size for network messages.") +set(OC_INOUT_BUFFER_POOL "" CACHE STRING "Custom static pool size of network messages.") +set(OC_APP_DATA_BUFFER_SIZE "" CACHE STRING "Custom static buffer size for application messages.") +set(OC_APP_DATA_BUFFER_POOL "" CACHE STRING "Custom static size of application messages.") +set(OC_DEVICE_MAX_NUM_CONCURRENT_REQUESTS "" CACHE STRING "Maximum number of messages in the network event queue for a device.") set(OC_ASAN_ENABLED OFF CACHE BOOL "Enable address sanitizer build.") set(OC_LSAN_ENABLED OFF CACHE BOOL "Enable leak sanitizer build.") @@ -399,59 +401,66 @@ if(OC_MEMORY_TRACE_ENABLED) list(APPEND TEST_COMPILE_DEFINITIONS "OC_MEMORY_TRACE") endif() -if (NOT("${OC_INOUT_BUFFER_SIZE}" STREQUAL "")) +if(OC_VERSION_1_1_0_ENABLED) + list(APPEND PUBLIC_COMPILE_DEFINITIONS "OC_SPEC_VER_OIC") +endif() + +if(OC_ETAG_ENABLED) + list(APPEND PUBLIC_COMPILE_DEFINITIONS "OC_ETAG") +endif() + +if(OC_JSON_ENCODER_ENABLED) + list(APPEND PUBLIC_COMPILE_DEFINITIONS "OC_JSON_ENCODER") +endif() + +if(OC_SIMPLE_MAIN_LOOP_ENABLED) + list(APPEND PUBLIC_COMPILE_DEFINITIONS "OC_SIMPLE_MAIN_LOOP") +endif() + +if(PLGD_DEV_TIME_ENABLED) + list(APPEND PUBLIC_COMPILE_DEFINITIONS "PLGD_DEV_TIME") + if(BUILD_MBEDTLS) + list(APPEND MBEDTLS_COMPILE_DEFINITIONS "PLGD_DEV_TIME") + endif() +endif() + +if(NOT("${OC_INOUT_BUFFER_SIZE}" STREQUAL "")) if(NOT OC_DYNAMIC_ALLOCATION_ENABLED) - message(FATAL_ERROR "Cannot set custom static buffer size for network messages without dynamic allocation") + message(FATAL_ERROR "Cannot OC_INOUT_BUFFER_SIZE without dynamic allocation") endif() list(APPEND PUBLIC_COMPILE_DEFINITIONS "OC_INOUT_BUFFER_SIZE=(${OC_INOUT_BUFFER_SIZE})") list(APPEND MBEDTLS_COMPILE_DEFINITIONS "OC_INOUT_BUFFER_SIZE=(${OC_INOUT_BUFFER_SIZE})") endif() -if (NOT("${OC_INOUT_BUFFER_POOL}" STREQUAL "")) +if(NOT("${OC_INOUT_BUFFER_POOL}" STREQUAL "")) if(NOT OC_DYNAMIC_ALLOCATION_ENABLED) - message(FATAL_ERROR "Cannot set custom static pool size for network messages without dynamic allocation") + message(FATAL_ERROR "Cannot set OC_INOUT_BUFFER_POOL without dynamic allocation") endif() list(APPEND PUBLIC_COMPILE_DEFINITIONS "OC_INOUT_BUFFER_POOL=(${OC_INOUT_BUFFER_POOL})") list(APPEND MBEDTLS_COMPILE_DEFINITIONS "OC_INOUT_BUFFER_POOL=(${OC_INOUT_BUFFER_POOL})") endif() -if (NOT("${OC_APP_DATA_BUFFER_SIZE}" STREQUAL "")) +if(NOT("${OC_APP_DATA_BUFFER_SIZE}" STREQUAL "")) if(NOT OC_DYNAMIC_ALLOCATION_ENABLED) - message(FATAL_ERROR "Cannot set custom static buffer size for application messages without dynamic allocation") + message(FATAL_ERROR "Cannot set OC_APP_DATA_BUFFER_SIZE without dynamic allocation") endif() list(APPEND PUBLIC_COMPILE_DEFINITIONS "OC_APP_DATA_BUFFER_SIZE=(${OC_APP_DATA_BUFFER_SIZE})") list(APPEND MBEDTLS_COMPILE_DEFINITIONS "OC_APP_DATA_BUFFER_SIZE=(${OC_APP_DATA_BUFFER_SIZE})") endif() -if (NOT("${OC_APP_DATA_BUFFER_POOL}" STREQUAL "")) +if(NOT("${OC_APP_DATA_BUFFER_POOL}" STREQUAL "")) if(NOT OC_DYNAMIC_ALLOCATION_ENABLED) - message(FATAL_ERROR "Cannot set custom static pool size for application messages without dynamic allocation") + message(FATAL_ERROR "Cannot OC_APP_DATA_BUFFER_POOL without dynamic allocation") endif() list(APPEND PUBLIC_COMPILE_DEFINITIONS "OC_APP_DATA_BUFFER_POOL=(${OC_APP_DATA_BUFFER_POOL})") list(APPEND MBEDTLS_COMPILE_DEFINITIONS "OC_APP_DATA_BUFFER_POOL=(${OC_APP_DATA_BUFFER_POOL})") endif() -if(OC_VERSION_1_1_0_ENABLED) - list(APPEND PUBLIC_COMPILE_DEFINITIONS "OC_SPEC_VER_OIC") -endif() - -if(OC_ETAG_ENABLED) - list(APPEND PUBLIC_COMPILE_DEFINITIONS "OC_ETAG") -endif() - -if(OC_JSON_ENCODER_ENABLED) - list(APPEND PUBLIC_COMPILE_DEFINITIONS "OC_JSON_ENCODER") -endif() - -if(OC_SIMPLE_MAIN_LOOP_ENABLED) - list(APPEND PUBLIC_COMPILE_DEFINITIONS "OC_SIMPLE_MAIN_LOOP") -endif() - -if(PLGD_DEV_TIME_ENABLED) - list(APPEND PUBLIC_COMPILE_DEFINITIONS "PLGD_DEV_TIME") - if(BUILD_MBEDTLS) - list(APPEND MBEDTLS_COMPILE_DEFINITIONS "PLGD_DEV_TIME") +if(NOT("${OC_DEVICE_MAX_NUM_CONCURRENT_REQUESTS}" STREQUAL "")) + if(NOT OC_DYNAMIC_ALLOCATION_ENABLED) + message(FATAL_ERROR "Cannot set OC_DEVICE_MAX_NUM_CONCURRENT_REQUESTS without dynamic allocation") endif() + list(APPEND OC_DEVICE_MAX_NUM_CONCURRENT_REQUESTS "OC_DEVICE_MAX_NUM_CONCURRENT_REQUESTS=(${OC_DEVICE_MAX_NUM_CONCURRENT_REQUESTS})") endif() if(BUILD_TESTING) From 98e3782367030ad69cdb13f725919fcdf333d4b1 Mon Sep 17 00:00:00 2001 From: sp-martin Date: Wed, 12 Jun 2024 15:45:13 +0000 Subject: [PATCH 27/35] - tests for the network event queue, wakeup connectivity tests - fixed deadlock on recursive entry into mutex in oc_network_drop_receive_events - fixed nullptr crash when comapring uri strings --- api/oc_core_res.c | 2 +- api/oc_network_events.c | 8 +- port/unittest/connectivitytest.cpp | 144 ++++++++++++++++++++++++++++- 3 files changed, 150 insertions(+), 4 deletions(-) diff --git a/api/oc_core_res.c b/api/oc_core_res.c index ab4751fc83..4784f0be3f 100644 --- a/api/oc_core_res.c +++ b/api/oc_core_res.c @@ -673,7 +673,7 @@ static bool core_is_resource_uri(const char *uri, size_t uri_len, const char *r_uri, size_t r_uri_len) { - if (uri[0] == '/') { + if (uri_len > 0 && uri[0] == '/') { uri = &uri[1]; --uri_len; } diff --git a/api/oc_network_events.c b/api/oc_network_events.c index d10e1349d1..8092019b2f 100644 --- a/api/oc_network_events.c +++ b/api/oc_network_events.c @@ -193,6 +193,7 @@ size_t oc_network_drop_receive_events(const oc_endpoint_t *endpoint) { size_t dropped = 0; + bool signal_wakeup = false; oc_network_event_handler_mutex_lock(); for (oc_message_t *message = (oc_message_t *)oc_list_head(g_network_events); message != NULL;) { @@ -219,11 +220,14 @@ oc_network_drop_receive_events(const oc_endpoint_t *endpoint) if (get_events_queue_length(endpoint->device, g_network_events) + dropped >= OC_DEVICE_MAX_NUM_CONCURRENT_REQUESTS) { // send a wake-up signal in case the queue for the device was full - oc_connectivity_wakeup(endpoint->device); + signal_wakeup = true; } #endif /* OC_DYNAMIC_ALLOCATION */ - oc_network_event_handler_mutex_unlock(); + + if(signal_wakeup) { + oc_connectivity_wakeup(endpoint->device); + } return dropped; } diff --git a/port/unittest/connectivitytest.cpp b/port/unittest/connectivitytest.cpp index 52b7b3b1d5..9886004813 100644 --- a/port/unittest/connectivitytest.cpp +++ b/port/unittest/connectivitytest.cpp @@ -17,6 +17,7 @@ ******************************************************************/ #include "api/oc_message_internal.h" +#include "api/oc_network_events_internal.h" #include "api/oc_tcp_internal.h" #include "api/oc_session_events_internal.h" #include "messaging/coap/coap_internal.h" @@ -45,6 +46,7 @@ using namespace std::chrono_literals; static constexpr size_t kDeviceID = 0; +static constexpr size_t kInvalidDeviceID = 42; class TestConnectivity : public testing::Test { public: @@ -131,7 +133,25 @@ TEST(TestConnectivity_init, AllDisabled) TEST(TestConnectivity_shutdown, InvalidDevice) { - oc_connectivity_shutdown(42); + oc_connectivity_shutdown(kInvalidDeviceID); +} + +TEST(TestConnectivity_wakeup, WakeupSuccess) +{ + oc_connectivity_ports_t ports; + memset(&ports, 0, sizeof(oc_connectivity_ports_t)); + oc_connectivity_init(kDeviceID, ports); + oc_connectivity_wakeup(kDeviceID); + oc_connectivity_shutdown(kDeviceID); +} + +TEST(TestConnectivity_wakeup, WakeupInvalidDevice) +{ + oc_connectivity_ports_t ports; + memset(&ports, 0, sizeof(oc_connectivity_ports_t)); + oc_connectivity_init(kDeviceID, ports); + oc_connectivity_wakeup(kInvalidDeviceID); + oc_connectivity_shutdown(kDeviceID); } static void @@ -397,6 +417,12 @@ class TestConnectivityWithServer : public testing::Test { static std::optional findEndpoint(size_t device); static std::atomic is_callback_received; + +#ifdef OC_DYNAMIC_ALLOCATION + static oc_message_t* CreateTestUdpMsg(const std::vector &data); + static oc_message_t* CreateValidTestUdpMsg(void); + static oc_message_t* CreateInvalidTestUdpMsg(void); +#endif /* OC_DYNAMIC_ALLOCATION */ }; std::atomic TestConnectivityWithServer::is_callback_received{ false }; @@ -420,12 +446,128 @@ TestConnectivityWithServer::findEndpoint(size_t device) return ep; } +#ifdef OC_DYNAMIC_ALLOCATION + oc_message_t* TestConnectivityWithServer::CreateTestUdpMsg(const std::vector &data) + { + oc_message_t *msg = oc_allocate_message(); + msg->endpoint.flags = IPV6; + memcpy(msg->data, &data[0], data.size()); + msg->length = data.size(); + return msg; + } + + oc_message_t* TestConnectivityWithServer::CreateValidTestUdpMsg(void) + { + const std::vector data = { 1 << COAP_HEADER_VERSION_POSITION, 2, 3, 4 }; + return TestConnectivityWithServer::CreateTestUdpMsg(data); + } + + oc_message_t* TestConnectivityWithServer::CreateInvalidTestUdpMsg(void) + { + const std::vector data = { 0xff, 2, 3, 4 }; + return TestConnectivityWithServer::CreateTestUdpMsg(data); + } +#endif /* OC_DYNAMIC_ALLOCATION */ + TEST_F(TestConnectivityWithServer, oc_connectivity_get_endpoints) { oc_endpoint_t *ep = oc_connectivity_get_endpoints(kDeviceID); EXPECT_NE(nullptr, ep); } +#ifdef OC_DYNAMIC_ALLOCATION + +TEST_F(TestConnectivityWithServer, oc_network_receive_event_valid) +{ + // verify initial size of event queue + size_t initialCount = oc_network_get_event_queue_length(kDeviceID); + EXPECT_EQ(initialCount,0); + + // add a valid udp message to the queue + oc_message_t *message = TestConnectivityWithServer::CreateValidTestUdpMsg(); + message->endpoint.device = kDeviceID; + oc_network_receive_event(message); + + // verify the queue contains new message + size_t eventCount = oc_network_get_event_queue_length(kDeviceID); + EXPECT_EQ(eventCount,1); +} + + +TEST_F(TestConnectivityWithServer, oc_network_receive_event_invalid) +{ + // verify initial size of event queue + size_t initialCount = oc_network_get_event_queue_length(kDeviceID); + EXPECT_EQ(initialCount,0); + + // try to add an invalid udp message to the queue + oc_message_t *message = TestConnectivityWithServer::CreateInvalidTestUdpMsg(); + message->endpoint.device = kDeviceID; + oc_network_receive_event(message); + + // verify the queue is still empty + size_t eventCount = oc_network_get_event_queue_length(kDeviceID); + EXPECT_EQ(eventCount,0); +} + +TEST_F(TestConnectivityWithServer, oc_network_get_event_queue_length) +{ + constexpr size_t kDeviceA = kDeviceID; + constexpr size_t kDeviceB = kDeviceID + 1; + + size_t eventCountA = oc_network_get_event_queue_length(kDeviceA); + EXPECT_EQ(eventCountA,0); + size_t eventCountB = oc_network_get_event_queue_length(kDeviceB); + EXPECT_EQ(eventCountB,0); + + // add valid messages for kDeviceA and kDeviceB + oc_message_t *messageA = TestConnectivityWithServer::CreateValidTestUdpMsg(); + messageA->endpoint.device = kDeviceA; + oc_network_receive_event(messageA); + oc_message_t *messageB = TestConnectivityWithServer::CreateValidTestUdpMsg(); + messageB->endpoint.device = kDeviceB; + oc_network_receive_event(messageB); + + // verify msg count for kDeviceA and kDeviceB + eventCountA = oc_network_get_event_queue_length(kDeviceA); + EXPECT_EQ(eventCountA,1); + eventCountB = oc_network_get_event_queue_length(kDeviceB); + EXPECT_EQ(eventCountB,1); +} + +TEST_F(TestConnectivityWithServer, oc_network_drop_receive_events) +{ + size_t eventCount = oc_network_get_event_queue_length(kDeviceID); + EXPECT_EQ(eventCount,0); + + // add max allowed amount of messages defined by OC_DEVICE_MAX_NUM_CONCURRENT_REQUESTS + for(size_t i = 0; i < OC_DEVICE_MAX_NUM_CONCURRENT_REQUESTS; ++i) + { + oc_message_t *message = TestConnectivityWithServer::CreateValidTestUdpMsg(); + message->endpoint.device = kDeviceID; + oc_network_receive_event(message); + } + + // verify all messages are in the queue + eventCount = oc_network_get_event_queue_length(kDeviceID); + EXPECT_EQ(eventCount, OC_DEVICE_MAX_NUM_CONCURRENT_REQUESTS); + + // remove all messages specified by endpoint + oc_endpoint_t defaultEndPoint; + memset(&defaultEndPoint, 0, sizeof(oc_endpoint_t)); + oc_message_t *message = TestConnectivityWithServer::CreateValidTestUdpMsg(); + defaultEndPoint = message->endpoint; + size_t dropped = oc_network_drop_receive_events(&defaultEndPoint); + oc_message_unref(message); + + // all messages are equeal -> verify they are all removed + EXPECT_EQ(dropped, OC_DEVICE_MAX_NUM_CONCURRENT_REQUESTS); + eventCount = oc_network_get_event_queue_length(kDeviceID); + EXPECT_EQ(eventCount, 0); +} + +#endif /* OC_DYNAMIC_ALLOCATION */ + #ifdef OC_TCP #ifdef OC_HAS_FEATURE_TCP_ASYNC_CONNECT From 26df754e4135e03d1c87d01593698b2825606184 Mon Sep 17 00:00:00 2001 From: Cascoda Bot Date: Thu, 13 Jun 2024 06:38:09 +0000 Subject: [PATCH 28/35] Automatic format commit --- api/oc_network_events.c | 4 +- port/unittest/connectivitytest.cpp | 79 ++++++++++++++++-------------- 2 files changed, 43 insertions(+), 40 deletions(-) diff --git a/api/oc_network_events.c b/api/oc_network_events.c index 8092019b2f..3e998a6d8b 100644 --- a/api/oc_network_events.c +++ b/api/oc_network_events.c @@ -220,12 +220,12 @@ oc_network_drop_receive_events(const oc_endpoint_t *endpoint) if (get_events_queue_length(endpoint->device, g_network_events) + dropped >= OC_DEVICE_MAX_NUM_CONCURRENT_REQUESTS) { // send a wake-up signal in case the queue for the device was full - signal_wakeup = true; + signal_wakeup = true; } #endif /* OC_DYNAMIC_ALLOCATION */ oc_network_event_handler_mutex_unlock(); - if(signal_wakeup) { + if (signal_wakeup) { oc_connectivity_wakeup(endpoint->device); } return dropped; diff --git a/port/unittest/connectivitytest.cpp b/port/unittest/connectivitytest.cpp index 9886004813..ae45e55c84 100644 --- a/port/unittest/connectivitytest.cpp +++ b/port/unittest/connectivitytest.cpp @@ -419,9 +419,9 @@ class TestConnectivityWithServer : public testing::Test { static std::atomic is_callback_received; #ifdef OC_DYNAMIC_ALLOCATION - static oc_message_t* CreateTestUdpMsg(const std::vector &data); - static oc_message_t* CreateValidTestUdpMsg(void); - static oc_message_t* CreateInvalidTestUdpMsg(void); + static oc_message_t *CreateTestUdpMsg(const std::vector &data); + static oc_message_t *CreateValidTestUdpMsg(void); + static oc_message_t *CreateInvalidTestUdpMsg(void); #endif /* OC_DYNAMIC_ALLOCATION */ }; @@ -447,26 +447,30 @@ TestConnectivityWithServer::findEndpoint(size_t device) } #ifdef OC_DYNAMIC_ALLOCATION - oc_message_t* TestConnectivityWithServer::CreateTestUdpMsg(const std::vector &data) - { - oc_message_t *msg = oc_allocate_message(); - msg->endpoint.flags = IPV6; - memcpy(msg->data, &data[0], data.size()); - msg->length = data.size(); - return msg; - } +oc_message_t * +TestConnectivityWithServer::CreateTestUdpMsg(const std::vector &data) +{ + oc_message_t *msg = oc_allocate_message(); + msg->endpoint.flags = IPV6; + memcpy(msg->data, &data[0], data.size()); + msg->length = data.size(); + return msg; +} - oc_message_t* TestConnectivityWithServer::CreateValidTestUdpMsg(void) - { - const std::vector data = { 1 << COAP_HEADER_VERSION_POSITION, 2, 3, 4 }; - return TestConnectivityWithServer::CreateTestUdpMsg(data); - } +oc_message_t * +TestConnectivityWithServer::CreateValidTestUdpMsg(void) +{ + const std::vector data = { 1 << COAP_HEADER_VERSION_POSITION, 2, 3, + 4 }; + return TestConnectivityWithServer::CreateTestUdpMsg(data); +} - oc_message_t* TestConnectivityWithServer::CreateInvalidTestUdpMsg(void) - { - const std::vector data = { 0xff, 2, 3, 4 }; - return TestConnectivityWithServer::CreateTestUdpMsg(data); - } +oc_message_t * +TestConnectivityWithServer::CreateInvalidTestUdpMsg(void) +{ + const std::vector data = { 0xff, 2, 3, 4 }; + return TestConnectivityWithServer::CreateTestUdpMsg(data); +} #endif /* OC_DYNAMIC_ALLOCATION */ TEST_F(TestConnectivityWithServer, oc_connectivity_get_endpoints) @@ -481,33 +485,32 @@ TEST_F(TestConnectivityWithServer, oc_network_receive_event_valid) { // verify initial size of event queue size_t initialCount = oc_network_get_event_queue_length(kDeviceID); - EXPECT_EQ(initialCount,0); + EXPECT_EQ(initialCount, 0); - // add a valid udp message to the queue + // add a valid udp message to the queue oc_message_t *message = TestConnectivityWithServer::CreateValidTestUdpMsg(); message->endpoint.device = kDeviceID; oc_network_receive_event(message); // verify the queue contains new message size_t eventCount = oc_network_get_event_queue_length(kDeviceID); - EXPECT_EQ(eventCount,1); + EXPECT_EQ(eventCount, 1); } - TEST_F(TestConnectivityWithServer, oc_network_receive_event_invalid) { // verify initial size of event queue size_t initialCount = oc_network_get_event_queue_length(kDeviceID); - EXPECT_EQ(initialCount,0); + EXPECT_EQ(initialCount, 0); - // try to add an invalid udp message to the queue + // try to add an invalid udp message to the queue oc_message_t *message = TestConnectivityWithServer::CreateInvalidTestUdpMsg(); message->endpoint.device = kDeviceID; oc_network_receive_event(message); // verify the queue is still empty size_t eventCount = oc_network_get_event_queue_length(kDeviceID); - EXPECT_EQ(eventCount,0); + EXPECT_EQ(eventCount, 0); } TEST_F(TestConnectivityWithServer, oc_network_get_event_queue_length) @@ -516,9 +519,9 @@ TEST_F(TestConnectivityWithServer, oc_network_get_event_queue_length) constexpr size_t kDeviceB = kDeviceID + 1; size_t eventCountA = oc_network_get_event_queue_length(kDeviceA); - EXPECT_EQ(eventCountA,0); + EXPECT_EQ(eventCountA, 0); size_t eventCountB = oc_network_get_event_queue_length(kDeviceB); - EXPECT_EQ(eventCountB,0); + EXPECT_EQ(eventCountB, 0); // add valid messages for kDeviceA and kDeviceB oc_message_t *messageA = TestConnectivityWithServer::CreateValidTestUdpMsg(); @@ -530,25 +533,25 @@ TEST_F(TestConnectivityWithServer, oc_network_get_event_queue_length) // verify msg count for kDeviceA and kDeviceB eventCountA = oc_network_get_event_queue_length(kDeviceA); - EXPECT_EQ(eventCountA,1); + EXPECT_EQ(eventCountA, 1); eventCountB = oc_network_get_event_queue_length(kDeviceB); - EXPECT_EQ(eventCountB,1); + EXPECT_EQ(eventCountB, 1); } TEST_F(TestConnectivityWithServer, oc_network_drop_receive_events) { size_t eventCount = oc_network_get_event_queue_length(kDeviceID); - EXPECT_EQ(eventCount,0); + EXPECT_EQ(eventCount, 0); - // add max allowed amount of messages defined by OC_DEVICE_MAX_NUM_CONCURRENT_REQUESTS - for(size_t i = 0; i < OC_DEVICE_MAX_NUM_CONCURRENT_REQUESTS; ++i) - { + // add max allowed amount of messages defined by + // OC_DEVICE_MAX_NUM_CONCURRENT_REQUESTS + for (size_t i = 0; i < OC_DEVICE_MAX_NUM_CONCURRENT_REQUESTS; ++i) { oc_message_t *message = TestConnectivityWithServer::CreateValidTestUdpMsg(); message->endpoint.device = kDeviceID; oc_network_receive_event(message); } - // verify all messages are in the queue + // verify all messages are in the queue eventCount = oc_network_get_event_queue_length(kDeviceID); EXPECT_EQ(eventCount, OC_DEVICE_MAX_NUM_CONCURRENT_REQUESTS); @@ -560,7 +563,7 @@ TEST_F(TestConnectivityWithServer, oc_network_drop_receive_events) size_t dropped = oc_network_drop_receive_events(&defaultEndPoint); oc_message_unref(message); - // all messages are equeal -> verify they are all removed + // all messages are equeal -> verify they are all removed EXPECT_EQ(dropped, OC_DEVICE_MAX_NUM_CONCURRENT_REQUESTS); eventCount = oc_network_get_event_queue_length(kDeviceID); EXPECT_EQ(eventCount, 0); From e6338d24d6fbaa9a718be9ec6efe17264c00cf21 Mon Sep 17 00:00:00 2001 From: sp-martin Date: Thu, 13 Jun 2024 07:52:06 +0000 Subject: [PATCH 29/35] - fixed OC_DYNAMIC_ALLOCATION=OFF builds --- api/oc_network_events.c | 15 ++++++++------- port/unittest/connectivitytest.cpp | 2 ++ 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/api/oc_network_events.c b/api/oc_network_events.c index 3e998a6d8b..3f3068a3b1 100644 --- a/api/oc_network_events.c +++ b/api/oc_network_events.c @@ -193,7 +193,6 @@ size_t oc_network_drop_receive_events(const oc_endpoint_t *endpoint) { size_t dropped = 0; - bool signal_wakeup = false; oc_network_event_handler_mutex_lock(); for (oc_message_t *message = (oc_message_t *)oc_list_head(g_network_events); message != NULL;) { @@ -219,15 +218,17 @@ oc_network_drop_receive_events(const oc_endpoint_t *endpoint) #ifdef OC_DYNAMIC_ALLOCATION if (get_events_queue_length(endpoint->device, g_network_events) + dropped >= OC_DEVICE_MAX_NUM_CONCURRENT_REQUESTS) { - // send a wake-up signal in case the queue for the device was full - signal_wakeup = true; + // unlock mutex and send a wake-up signal in case the queue for the device + // was full + oc_network_event_handler_mutex_unlock(); + oc_connectivity_wakeup(endpoint->device); + } else { + oc_network_event_handler_mutex_unlock(); } -#endif /* OC_DYNAMIC_ALLOCATION */ +#else oc_network_event_handler_mutex_unlock(); +#endif /* OC_DYNAMIC_ALLOCATION */ - if (signal_wakeup) { - oc_connectivity_wakeup(endpoint->device); - } return dropped; } diff --git a/port/unittest/connectivitytest.cpp b/port/unittest/connectivitytest.cpp index ae45e55c84..69a09a498e 100644 --- a/port/unittest/connectivitytest.cpp +++ b/port/unittest/connectivitytest.cpp @@ -136,6 +136,7 @@ TEST(TestConnectivity_shutdown, InvalidDevice) oc_connectivity_shutdown(kInvalidDeviceID); } +#ifdef OC_DYNAMIC_ALLOCATION TEST(TestConnectivity_wakeup, WakeupSuccess) { oc_connectivity_ports_t ports; @@ -153,6 +154,7 @@ TEST(TestConnectivity_wakeup, WakeupInvalidDevice) oc_connectivity_wakeup(kInvalidDeviceID); oc_connectivity_shutdown(kDeviceID); } +#endif /* OC_DYNAMIC_ALLOCATION */ static void interface_event_handler(oc_interface_event_t event) From 718ce711fbf24f2502007ba403ff48663ce743ed Mon Sep 17 00:00:00 2001 From: sp-martin Date: Thu, 13 Jun 2024 09:32:25 +0000 Subject: [PATCH 30/35] - generic solution for comparing fd_set --- port/linux/ipadapter.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/port/linux/ipadapter.c b/port/linux/ipadapter.c index 2126c9467a..1ed0a2a948 100644 --- a/port/linux/ipadapter.c +++ b/port/linux/ipadapter.c @@ -900,7 +900,12 @@ fd_sets_are_equal(const fd_set *fd1, const fd_set *fd2) return (memcmp(__FDS_BITS(fd1), __FDS_BITS(fd2), sizeof(__FDS_BITS(fd1))) == 0); #else //!__FDS_BITS - return (memcmp(fd1->fds_bits, fd2->fds_bits, sizeof(fd1->fds_bits)) == 0); + for (int i = 0; i < FD_SETSIZE; ++i) { + if (FD_ISSET(i, fd1) != FD_ISSET(i, fd2)) { + return false; + } + } + return true; #endif //__FDS_BITS } From 4b254d8b5ed882fef9bf115a7cd28a5093f2e067 Mon Sep 17 00:00:00 2001 From: Daniel Adam Date: Thu, 13 Jun 2024 15:20:41 +0200 Subject: [PATCH 31/35] Run tests with OC_DEVICE_MAX_NUM_CONCURRENT_REQUESTS=1 on GitHub --- .github/workflows/cmake-windows.yml | 7 +++++++ .github/workflows/plgd-device-tests.yml | 5 +++++ .github/workflows/plgd-hub-tests.yml | 5 +++++ .github/workflows/sonar-cloud-analysis.yml | 4 ++++ CMakeLists.txt | 18 +++++++++++++----- api/cloud/unittest/rd_client_test.cpp | 6 ++++-- api/unittest/introspectiontest.cpp | 7 +++++++ port/unittest/connectivitytest.cpp | 14 +++++++++++--- 8 files changed, 56 insertions(+), 10 deletions(-) diff --git a/.github/workflows/cmake-windows.yml b/.github/workflows/cmake-windows.yml index 6a6cce2da1..78c6c89cb8 100644 --- a/.github/workflows/cmake-windows.yml +++ b/.github/workflows/cmake-windows.yml @@ -37,6 +37,12 @@ jobs: cc: "gcc" cxx: "g++" build_testing: "ON" + - name: "MinGW-gcc debug-discovery-resource-observable-rep-realloc-concurrent-requests-1" + build_type: "Debug" + cc: "gcc" + cxx: "g++" + build_testing: "ON" + build_args: "-DOC_DISCOVERY_RESOURCE_OBSERVABLE_ENABLED=ON -DOC_REPRESENTATION_REALLOC_ENCODING_ENABLED=ON -DOC_DEVICE_MAX_NUM_CONCURRENT_REQUESTS=1" steps: - name: Checkout repository @@ -93,6 +99,7 @@ jobs: -D PLGD_DEV_TIME_ENABLED=ON -D OC_ETAG_ENABLED=ON -D OC_DEBUG_ENABLED=ON + ${{ matrix.build_args }} COMMAND_ERROR_IS_FATAL ANY ) diff --git a/.github/workflows/plgd-device-tests.yml b/.github/workflows/plgd-device-tests.yml index 023aa288b9..9c8a97fcda 100644 --- a/.github/workflows/plgd-device-tests.yml +++ b/.github/workflows/plgd-device-tests.yml @@ -64,6 +64,11 @@ jobs: args: "-DOC_TSAN_ENABLED=ON -DOC_RESOURCE_ACCESS_IN_RFOTM_ENABLED=ON" docker_file: docker/apps/Dockerfile.cloud-server-debug-clang + - name: cloud-server-access-in-RFOTM-concurrent-requests-1 + # same configuration as " cloud-server-access-in-RFOTM-concurrent-requests-1" in the SonarCloud scan job, skip for events that trigger both jobs + skip: ${{ github.event_name != 'workflow_dispatch' }} + args: "-DOC_RESOURCE_ACCESS_IN_RFOTM_ENABLED=ON -DOC_DEVICE_MAX_NUM_CONCURRENT_REQUESTS=1" + - name: cloud-server-discovery-resource-observable args: "-DOC_DISCOVERY_RESOURCE_OBSERVABLE_ENABLED=ON" - name: cloud-server-discovery-resource-observable-asan diff --git a/.github/workflows/plgd-hub-tests.yml b/.github/workflows/plgd-hub-tests.yml index 018cee57de..6390aa23b3 100644 --- a/.github/workflows/plgd-hub-tests.yml +++ b/.github/workflows/plgd-hub-tests.yml @@ -137,6 +137,11 @@ jobs: build_args: "-DOC_DISCOVERY_RESOURCE_OBSERVABLE_ENABLED=ON -DOC_RESOURCE_ACCESS_IN_RFOTM_ENABLED=ON -DOC_REPRESENTATION_REALLOC_ENCODING_ENABLED=ON -DOC_TSAN_ENABLED=ON" docker_file: docker/apps/Dockerfile.cloud-server-debug-clang + - name: cloud-server-discovery-resource-observable-access-in-RFOTM-rep-realloc-concurrent-requests-1 + # same configuration as "cloud-server-discovery-resource-observable-access-in-RFOTM-rep-realloc-concurrent-requests-1" in the SonarCloud scan job, skip for events that trigger both jobs + skip: ${{ github.event_name != 'workflow_dispatch' }} + build_args: "-DOC_DISCOVERY_RESOURCE_OBSERVABLE_ENABLED=ON -DOC_RESOURCE_ACCESS_IN_RFOTM_ENABLED=ON -DOC_REPRESENTATION_REALLOC_ENCODING_ENABLED=ON -DOC_DEVICE_MAX_NUM_CONCURRENT_REQUESTS=1" + # ports - name: cloud-server-tcp-disabled args: "--udp-port 61234 --udp-port4 61234 --dtls-port 61235 --dtls-port4 61235 --tcp-port -1 --tcp-port4 -1 --tls-port -1 --tls-port4 -1" diff --git a/.github/workflows/sonar-cloud-analysis.yml b/.github/workflows/sonar-cloud-analysis.yml index ee0407830f..30811d9e05 100644 --- a/.github/workflows/sonar-cloud-analysis.yml +++ b/.github/workflows/sonar-cloud-analysis.yml @@ -51,6 +51,8 @@ jobs: include: - name: cloud-server build_args: "" + - name: cloud-server-access-in-RFOTM-concurrent-requests-1 + build_args: "-DOC_RESOURCE_ACCESS_IN_RFOTM_ENABLED=ON -DOC_DEVICE_MAX_NUM_CONCURRENT_REQUESTS=1" - name: cloud-server-discovery-resource-observable-access-in-RFOTM-rep-realloc build_args: "-DOC_DISCOVERY_RESOURCE_OBSERVABLE_ENABLED=ON -DOC_RESOURCE_ACCESS_IN_RFOTM_ENABLED=ON -DOC_REPRESENTATION_REALLOC_ENCODING_ENABLED=ON" # try with SHA384 @@ -72,6 +74,8 @@ jobs: include: - name: cloud-server-discovery-resource-observable-access-in-RFOTM build_args: "-DOC_DISCOVERY_RESOURCE_OBSERVABLE_ENABLED=ON -DOC_RESOURCE_ACCESS_IN_RFOTM_ENABLED=ON" + - name: cloud-server-discovery-resource-observable-access-in-RFOTM-rep-realloc-concurrent-requests-1 + build_args: "-DOC_DISCOVERY_RESOURCE_OBSERVABLE_ENABLED=ON -DOC_RESOURCE_ACCESS_IN_RFOTM_ENABLED=ON -DOC_REPRESENTATION_REALLOC_ENCODING_ENABLED=ON -DOC_DEVICE_MAX_NUM_CONCURRENT_REQUESTS=1" - name: dtls-cloud-server-rep-realloc build_args: "-DOC_REPRESENTATION_REALLOC_ENCODING_ENABLED=ON" hub_args: "-e COAP_GATEWAY_UDP_ENABLED=true" diff --git a/CMakeLists.txt b/CMakeLists.txt index 30f08b40c1..4f490b7e3b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -429,7 +429,9 @@ if(NOT("${OC_INOUT_BUFFER_SIZE}" STREQUAL "")) message(FATAL_ERROR "Cannot OC_INOUT_BUFFER_SIZE without dynamic allocation") endif() list(APPEND PUBLIC_COMPILE_DEFINITIONS "OC_INOUT_BUFFER_SIZE=(${OC_INOUT_BUFFER_SIZE})") - list(APPEND MBEDTLS_COMPILE_DEFINITIONS "OC_INOUT_BUFFER_SIZE=(${OC_INOUT_BUFFER_SIZE})") + if(BUILD_MBEDTLS) + list(APPEND MBEDTLS_COMPILE_DEFINITIONS "OC_INOUT_BUFFER_SIZE=(${OC_INOUT_BUFFER_SIZE})") + endif() endif() if(NOT("${OC_INOUT_BUFFER_POOL}" STREQUAL "")) @@ -437,7 +439,9 @@ if(NOT("${OC_INOUT_BUFFER_POOL}" STREQUAL "")) message(FATAL_ERROR "Cannot set OC_INOUT_BUFFER_POOL without dynamic allocation") endif() list(APPEND PUBLIC_COMPILE_DEFINITIONS "OC_INOUT_BUFFER_POOL=(${OC_INOUT_BUFFER_POOL})") - list(APPEND MBEDTLS_COMPILE_DEFINITIONS "OC_INOUT_BUFFER_POOL=(${OC_INOUT_BUFFER_POOL})") + if(BUILD_MBEDTLS) + list(APPEND MBEDTLS_COMPILE_DEFINITIONS "OC_INOUT_BUFFER_POOL=(${OC_INOUT_BUFFER_POOL})") + endif() endif() if(NOT("${OC_APP_DATA_BUFFER_SIZE}" STREQUAL "")) @@ -445,7 +449,9 @@ if(NOT("${OC_APP_DATA_BUFFER_SIZE}" STREQUAL "")) message(FATAL_ERROR "Cannot set OC_APP_DATA_BUFFER_SIZE without dynamic allocation") endif() list(APPEND PUBLIC_COMPILE_DEFINITIONS "OC_APP_DATA_BUFFER_SIZE=(${OC_APP_DATA_BUFFER_SIZE})") - list(APPEND MBEDTLS_COMPILE_DEFINITIONS "OC_APP_DATA_BUFFER_SIZE=(${OC_APP_DATA_BUFFER_SIZE})") + if(BUILD_MBEDTLS) + list(APPEND MBEDTLS_COMPILE_DEFINITIONS "OC_APP_DATA_BUFFER_SIZE=(${OC_APP_DATA_BUFFER_SIZE})") + endif() endif() if(NOT("${OC_APP_DATA_BUFFER_POOL}" STREQUAL "")) @@ -453,14 +459,16 @@ if(NOT("${OC_APP_DATA_BUFFER_POOL}" STREQUAL "")) message(FATAL_ERROR "Cannot OC_APP_DATA_BUFFER_POOL without dynamic allocation") endif() list(APPEND PUBLIC_COMPILE_DEFINITIONS "OC_APP_DATA_BUFFER_POOL=(${OC_APP_DATA_BUFFER_POOL})") - list(APPEND MBEDTLS_COMPILE_DEFINITIONS "OC_APP_DATA_BUFFER_POOL=(${OC_APP_DATA_BUFFER_POOL})") + if(BUILD_MBEDTLS) + list(APPEND MBEDTLS_COMPILE_DEFINITIONS "OC_APP_DATA_BUFFER_POOL=(${OC_APP_DATA_BUFFER_POOL})") + endif() endif() if(NOT("${OC_DEVICE_MAX_NUM_CONCURRENT_REQUESTS}" STREQUAL "")) if(NOT OC_DYNAMIC_ALLOCATION_ENABLED) message(FATAL_ERROR "Cannot set OC_DEVICE_MAX_NUM_CONCURRENT_REQUESTS without dynamic allocation") endif() - list(APPEND OC_DEVICE_MAX_NUM_CONCURRENT_REQUESTS "OC_DEVICE_MAX_NUM_CONCURRENT_REQUESTS=(${OC_DEVICE_MAX_NUM_CONCURRENT_REQUESTS})") + list(APPEND PUBLIC_COMPILE_DEFINITIONS "OC_DEVICE_MAX_NUM_CONCURRENT_REQUESTS=(${OC_DEVICE_MAX_NUM_CONCURRENT_REQUESTS})") endif() if(BUILD_TESTING) diff --git a/api/cloud/unittest/rd_client_test.cpp b/api/cloud/unittest/rd_client_test.cpp index 633749fa78..6a2dbd9a98 100644 --- a/api/cloud/unittest/rd_client_test.cpp +++ b/api/cloud/unittest/rd_client_test.cpp @@ -215,7 +215,8 @@ TEST_F(TestRDClient, Publish_FailBadInput) /*user_data*/ nullptr)); } -#if defined(OC_DYNAMIC_ALLOCATION) && !defined(OC_APP_DATA_BUFFER_SIZE) +#if defined(OC_DYNAMIC_ALLOCATION) && !defined(OC_APP_DATA_BUFFER_SIZE) && \ + !defined(OC_REP_ENCODING_REALLOC) TEST_F(TestRDClient, Publish_FailPayloadTooLarge) { @@ -228,7 +229,8 @@ TEST_F(TestRDClient, Publish_FailPayloadTooLarge) oc_set_max_app_data_size(kDefaultSize); } -#endif // OC_DYNAMIC_ALLOCATION && !OC_APP_DATA_BUFFER_SIZE +#endif // OC_DYNAMIC_ALLOCATION && !OC_APP_DATA_BUFFER_SIZE && + // !OC_REP_ENCODING_REALLOC #ifndef OC_DYNAMIC_ALLOCATION diff --git a/api/unittest/introspectiontest.cpp b/api/unittest/introspectiontest.cpp index 52e03b200b..a55e18a128 100644 --- a/api/unittest/introspectiontest.cpp +++ b/api/unittest/introspectiontest.cpp @@ -199,6 +199,11 @@ TEST_F(TestIntrospectionWithServer, GetRequest) // the IDD data is too large for non-dynamic allocation and byte pool gets // exhausted +#ifndef OC_REP_ENCODING_REALLOC + +// TODO: if the default application data size is too small, the introspection +// data should realloc the buffer to sufficient size + TEST_F(TestIntrospectionWithServer, GetDataRequest) { auto epOpt = oc::TestDevice::GetEndpoint(kDeviceID); @@ -221,6 +226,8 @@ TEST_F(TestIntrospectionWithServer, GetDataRequest) EXPECT_TRUE(invoked); } +#endif /* !OC_REP_ENCODING_REALLOC */ + TEST_F(TestIntrospectionWithServer, GetDataRequest_Fail) { oc::TestDevice::StopServer(); diff --git a/port/unittest/connectivitytest.cpp b/port/unittest/connectivitytest.cpp index 69a09a498e..1a7cc895d6 100644 --- a/port/unittest/connectivitytest.cpp +++ b/port/unittest/connectivitytest.cpp @@ -545,9 +545,17 @@ TEST_F(TestConnectivityWithServer, oc_network_drop_receive_events) size_t eventCount = oc_network_get_event_queue_length(kDeviceID); EXPECT_EQ(eventCount, 0); +#ifdef OC_INOUT_BUFFER_POOL + const size_t message_count = + OC_INOUT_BUFFER_POOL - 1; // -1 in case some other API (for example + // interface change observer) generated a message +#else /* !OC_INOUT_BUFFER_POOL */ + const size_t message_count = OC_DEVICE_MAX_NUM_CONCURRENT_REQUESTS; +#endif /* OC_INOUT_BUFFER_POOL */ + // add max allowed amount of messages defined by // OC_DEVICE_MAX_NUM_CONCURRENT_REQUESTS - for (size_t i = 0; i < OC_DEVICE_MAX_NUM_CONCURRENT_REQUESTS; ++i) { + for (size_t i = 0; i < message_count; ++i) { oc_message_t *message = TestConnectivityWithServer::CreateValidTestUdpMsg(); message->endpoint.device = kDeviceID; oc_network_receive_event(message); @@ -555,7 +563,7 @@ TEST_F(TestConnectivityWithServer, oc_network_drop_receive_events) // verify all messages are in the queue eventCount = oc_network_get_event_queue_length(kDeviceID); - EXPECT_EQ(eventCount, OC_DEVICE_MAX_NUM_CONCURRENT_REQUESTS); + EXPECT_EQ(eventCount, message_count); // remove all messages specified by endpoint oc_endpoint_t defaultEndPoint; @@ -566,7 +574,7 @@ TEST_F(TestConnectivityWithServer, oc_network_drop_receive_events) oc_message_unref(message); // all messages are equeal -> verify they are all removed - EXPECT_EQ(dropped, OC_DEVICE_MAX_NUM_CONCURRENT_REQUESTS); + EXPECT_EQ(dropped, message_count); eventCount = oc_network_get_event_queue_length(kDeviceID); EXPECT_EQ(eventCount, 0); } From 30cace2b103a295ae4cbef5dc80db6f454c54a7e Mon Sep 17 00:00:00 2001 From: sp-martin Date: Thu, 13 Jun 2024 18:28:34 +0000 Subject: [PATCH 32/35] - fixed generation of random negative numbers causing the pick_random_fd method to fail. --- port/android/ipadapter.c | 2 +- port/esp32/adapter/src/ipadapter.c | 2 +- port/linux/ipadapter.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/port/android/ipadapter.c b/port/android/ipadapter.c index e47c176a10..b910f90b0d 100644 --- a/port/android/ipadapter.c +++ b/port/android/ipadapter.c @@ -815,7 +815,7 @@ static int pick_random_fd(const fd_set *sourcefds, int fd_count, int max_fd) { assert(fd_count > 0); - int random_rfd = (int)oc_random_value() % fd_count; + int random_rfd = (int)(oc_random_value() % fd_count); for (int i = 0; i <= max_fd; i++) { if (FD_ISSET(i, sourcefds)) { if (--fd_count == random_rfd) { diff --git a/port/esp32/adapter/src/ipadapter.c b/port/esp32/adapter/src/ipadapter.c index 40cb2a4633..c7f52d64d1 100644 --- a/port/esp32/adapter/src/ipadapter.c +++ b/port/esp32/adapter/src/ipadapter.c @@ -840,7 +840,7 @@ static int pick_random_fd(const fd_set *sourcefds, int fd_count, int max_fd) { assert(fd_count > 0); - int random_rfd = (int)oc_random_value() % fd_count; + int random_rfd = (int)(oc_random_value() % fd_count); for (int i = 0; i <= max_fd; i++) { if (FD_ISSET(i, sourcefds)) { if (--fd_count == random_rfd) { diff --git a/port/linux/ipadapter.c b/port/linux/ipadapter.c index 1ed0a2a948..d0831f1544 100644 --- a/port/linux/ipadapter.c +++ b/port/linux/ipadapter.c @@ -937,7 +937,7 @@ static int pick_random_fd(const fd_set *sourcefds, int fd_count, int max_fd) { assert(fd_count > 0); - int random_rfd = (int)oc_random_value() % fd_count; + int random_rfd = (int)(oc_random_value() % fd_count); for (int i = 0; i <= max_fd; i++) { if (FD_ISSET(i, sourcefds)) { if (--fd_count == random_rfd) { From 72f5d63b6beddce0eab359c94d1440fa62db2a12 Mon Sep 17 00:00:00 2001 From: sp-martin Date: Fri, 14 Jun 2024 10:39:49 +0000 Subject: [PATCH 33/35] - corrected issues reported by SonarCloud --- port/android/ipadapter.c | 10 ++++------ port/esp32/adapter/src/ipadapter.c | 10 ++++------ port/linux/ipadapter.c | 10 ++++------ 3 files changed, 12 insertions(+), 18 deletions(-) diff --git a/port/android/ipadapter.c b/port/android/ipadapter.c index b910f90b0d..5f02e7ab02 100644 --- a/port/android/ipadapter.c +++ b/port/android/ipadapter.c @@ -817,10 +817,8 @@ pick_random_fd(const fd_set *sourcefds, int fd_count, int max_fd) assert(fd_count > 0); int random_rfd = (int)(oc_random_value() % fd_count); for (int i = 0; i <= max_fd; i++) { - if (FD_ISSET(i, sourcefds)) { - if (--fd_count == random_rfd) { - return i; - } + if (FD_ISSET(i, sourcefds) && (--fd_count == random_rfd)) { + return i; } } return -1; @@ -1072,7 +1070,7 @@ process_events(ip_context_t *dev, fd_set *rdfds, fd_set *wfds, int fd_count, #ifdef OC_DYNAMIC_ALLOCATION // check if network queue can consume all 'ready' events int available_count = OC_DEVICE_MAX_NUM_CONCURRENT_REQUESTS - - oc_network_get_event_queue_length(dev->device); + (int)oc_network_get_event_queue_length(dev->device); if (available_count < fd_count) { // get the number of read file descriptors int rfds_count = fds_count(rdfds, max_read_fd); @@ -1762,7 +1760,7 @@ oc_connectivity_init(size_t device, oc_connectivity_ports_t ports) } static void -signal_event_thread(ip_context_t *dev) +signal_event_thread(const ip_context_t *dev) { ssize_t result; do { diff --git a/port/esp32/adapter/src/ipadapter.c b/port/esp32/adapter/src/ipadapter.c index c7f52d64d1..d788b3f5aa 100644 --- a/port/esp32/adapter/src/ipadapter.c +++ b/port/esp32/adapter/src/ipadapter.c @@ -842,10 +842,8 @@ pick_random_fd(const fd_set *sourcefds, int fd_count, int max_fd) assert(fd_count > 0); int random_rfd = (int)(oc_random_value() % fd_count); for (int i = 0; i <= max_fd; i++) { - if (FD_ISSET(i, sourcefds)) { - if (--fd_count == random_rfd) { - return i; - } + if (FD_ISSET(i, sourcefds) && (--fd_count == random_rfd)) { + return i; } } return -1; @@ -983,7 +981,7 @@ process_events(ip_context_t *dev, fd_set *rdfds, fd_set *wfds, int fd_count, #ifdef OC_DYNAMIC_ALLOCATION // check if network queue can consume all 'ready' events int available_count = OC_DEVICE_MAX_NUM_CONCURRENT_REQUESTS - - oc_network_get_event_queue_length(dev->device); + (int)oc_network_get_event_queue_length(dev->device); if (available_count < fd_count) { // get the number of read file descriptors int rfds_count = fds_count(rdfds, max_read_fd); @@ -1742,7 +1740,7 @@ oc_connectivity_init(size_t device, oc_connectivity_ports_t ports) } static void -signal_event_thread(ip_context_t *dev) +signal_event_thread(const ip_context_t *dev) { ssize_t result; do { diff --git a/port/linux/ipadapter.c b/port/linux/ipadapter.c index d0831f1544..c0a7bb8fce 100644 --- a/port/linux/ipadapter.c +++ b/port/linux/ipadapter.c @@ -939,10 +939,8 @@ pick_random_fd(const fd_set *sourcefds, int fd_count, int max_fd) assert(fd_count > 0); int random_rfd = (int)(oc_random_value() % fd_count); for (int i = 0; i <= max_fd; i++) { - if (FD_ISSET(i, sourcefds)) { - if (--fd_count == random_rfd) { - return i; - } + if (FD_ISSET(i, sourcefds) && (--fd_count == random_rfd)) { + return i; } } return -1; @@ -998,7 +996,7 @@ process_events(ip_context_t *dev, fd_set *rdfds, fd_set *wfds, int fd_count, #ifdef OC_DYNAMIC_ALLOCATION // check if network queue can consume all 'ready' events int available_count = OC_DEVICE_MAX_NUM_CONCURRENT_REQUESTS - - oc_network_get_event_queue_length(dev->device); + (int)oc_network_get_event_queue_length(dev->device); if (available_count < fd_count) { // get the number of read file descriptors int rfds_count = fds_count(rdfds, max_read_fd); @@ -1621,7 +1619,7 @@ initialize_ip_context(ip_context_t *dev, size_t device, } static void -signal_event_thread(ip_context_t *dev) +signal_event_thread(const ip_context_t *dev) { ssize_t result; do { From 584a7566910467c8eac258b3770ea2a83e1c4340 Mon Sep 17 00:00:00 2001 From: sp-martin Date: Fri, 14 Jun 2024 14:05:53 +0000 Subject: [PATCH 34/35] - addressed sonar cloud issues --- port/android/ipadapter.c | 15 ++++++++++----- port/esp32/adapter/src/ipadapter.c | 15 ++++++++++----- port/linux/ipadapter.c | 15 ++++++++++----- 3 files changed, 30 insertions(+), 15 deletions(-) diff --git a/port/android/ipadapter.c b/port/android/ipadapter.c index 5f02e7ab02..7c82089fc8 100644 --- a/port/android/ipadapter.c +++ b/port/android/ipadapter.c @@ -815,10 +815,15 @@ static int pick_random_fd(const fd_set *sourcefds, int fd_count, int max_fd) { assert(fd_count > 0); - int random_rfd = (int)(oc_random_value() % fd_count); - for (int i = 0; i <= max_fd; i++) { - if (FD_ISSET(i, sourcefds) && (--fd_count == random_rfd)) { - return i; + // get random number representing the position of descriptor in the fd_set + int random_pos = (int)(oc_random_value() % fd_count); + for (int i = 0, fd_pos = 0; i <= max_fd; i++) { + if (FD_ISSET(i, sourcefds)) { + if (random_pos == fd_pos) { + return i; + } + // advance to the position + fd_pos++; } } return -1; @@ -1781,7 +1786,7 @@ signal_event_thread(const ip_context_t *dev) void oc_connectivity_wakeup(size_t device) { - ip_context_t *dev = get_ip_context_for_device(device); + const ip_context_t *dev = get_ip_context_for_device(device); if (dev == NULL) { OC_WRN("no ip-context found for device(%zu)", device); return; diff --git a/port/esp32/adapter/src/ipadapter.c b/port/esp32/adapter/src/ipadapter.c index d788b3f5aa..5f9b9ef8ad 100644 --- a/port/esp32/adapter/src/ipadapter.c +++ b/port/esp32/adapter/src/ipadapter.c @@ -840,10 +840,15 @@ static int pick_random_fd(const fd_set *sourcefds, int fd_count, int max_fd) { assert(fd_count > 0); - int random_rfd = (int)(oc_random_value() % fd_count); - for (int i = 0; i <= max_fd; i++) { - if (FD_ISSET(i, sourcefds) && (--fd_count == random_rfd)) { - return i; + // get random number representing the position of descriptor in the fd_set + int random_pos = (int)(oc_random_value() % fd_count); + for (int i = 0, fd_pos = 0; i <= max_fd; i++) { + if (FD_ISSET(i, sourcefds)) { + if (random_pos == fd_pos) { + return i; + } + // advance to the position + fd_pos++; } } return -1; @@ -1761,7 +1766,7 @@ signal_event_thread(const ip_context_t *dev) void oc_connectivity_wakeup(size_t device) { - ip_context_t *dev = get_ip_context_for_device(device); + const ip_context_t *dev = get_ip_context_for_device(device); if (dev == NULL) { OC_WRN("no ip-context found for device(%zu)", device); return; diff --git a/port/linux/ipadapter.c b/port/linux/ipadapter.c index c0a7bb8fce..1e9395f1a2 100644 --- a/port/linux/ipadapter.c +++ b/port/linux/ipadapter.c @@ -937,10 +937,15 @@ static int pick_random_fd(const fd_set *sourcefds, int fd_count, int max_fd) { assert(fd_count > 0); - int random_rfd = (int)(oc_random_value() % fd_count); - for (int i = 0; i <= max_fd; i++) { - if (FD_ISSET(i, sourcefds) && (--fd_count == random_rfd)) { - return i; + // get random number representing the position of descriptor in the fd_set + int random_pos = (int)(oc_random_value() % fd_count); + for (int i = 0, fd_pos = 0; i <= max_fd; i++) { + if (FD_ISSET(i, sourcefds)) { + if (random_pos == fd_pos) { + return i; + } + // advance to the position + fd_pos++; } } return -1; @@ -1663,7 +1668,7 @@ oc_connectivity_init(size_t device, oc_connectivity_ports_t ports) void oc_connectivity_wakeup(size_t device) { - ip_context_t *dev = oc_get_ip_context_for_device(device); + const ip_context_t *dev = oc_get_ip_context_for_device(device); if (dev == NULL) { OC_WRN("no ip-context found for device(%zu)", device); return; From bbdd320bb9bd2a0d55db97b3f2d191181ecd49d2 Mon Sep 17 00:00:00 2001 From: Daniel Adam Date: Fri, 14 Jun 2024 21:36:58 +0200 Subject: [PATCH 35/35] - run tests on GitHub with thread sanitizer --- .github/workflows/plgd-device-tests.yml | 3 +++ .github/workflows/plgd-hub-tests.yml | 3 +++ api/oc_network_events.c | 13 ++++++------- 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/.github/workflows/plgd-device-tests.yml b/.github/workflows/plgd-device-tests.yml index 9c8a97fcda..4262527b20 100644 --- a/.github/workflows/plgd-device-tests.yml +++ b/.github/workflows/plgd-device-tests.yml @@ -68,6 +68,9 @@ jobs: # same configuration as " cloud-server-access-in-RFOTM-concurrent-requests-1" in the SonarCloud scan job, skip for events that trigger both jobs skip: ${{ github.event_name != 'workflow_dispatch' }} args: "-DOC_RESOURCE_ACCESS_IN_RFOTM_ENABLED=ON -DOC_DEVICE_MAX_NUM_CONCURRENT_REQUESTS=1" + - name: cloud-server-access-in-RFOTM-concurrent-requests-1-tsan + args: "-DOC_TSAN_ENABLED=ON -DOC_RESOURCE_ACCESS_IN_RFOTM_ENABLED=ON -DOC_DEVICE_MAX_NUM_CONCURRENT_REQUESTS=1" + docker_file: docker/apps/Dockerfile.cloud-server-debug-clang - name: cloud-server-discovery-resource-observable args: "-DOC_DISCOVERY_RESOURCE_OBSERVABLE_ENABLED=ON" diff --git a/.github/workflows/plgd-hub-tests.yml b/.github/workflows/plgd-hub-tests.yml index 6390aa23b3..c008660ea7 100644 --- a/.github/workflows/plgd-hub-tests.yml +++ b/.github/workflows/plgd-hub-tests.yml @@ -141,6 +141,9 @@ jobs: # same configuration as "cloud-server-discovery-resource-observable-access-in-RFOTM-rep-realloc-concurrent-requests-1" in the SonarCloud scan job, skip for events that trigger both jobs skip: ${{ github.event_name != 'workflow_dispatch' }} build_args: "-DOC_DISCOVERY_RESOURCE_OBSERVABLE_ENABLED=ON -DOC_RESOURCE_ACCESS_IN_RFOTM_ENABLED=ON -DOC_REPRESENTATION_REALLOC_ENCODING_ENABLED=ON -DOC_DEVICE_MAX_NUM_CONCURRENT_REQUESTS=1" + - name: cloud-server-discovery-resource-observable-access-in-RFOTM-rep-realloc-concurrent-requests-1-tsan + build_args: "-DOC_DISCOVERY_RESOURCE_OBSERVABLE_ENABLED=ON -DOC_RESOURCE_ACCESS_IN_RFOTM_ENABLED=ON -DOC_REPRESENTATION_REALLOC_ENCODING_ENABLED=ON -DOC_DEVICE_MAX_NUM_CONCURRENT_REQUESTS=1 -DOC_TSAN_ENABLED=ON" + docker_file: docker/apps/Dockerfile.cloud-server-debug-clang # ports - name: cloud-server-tcp-disabled diff --git a/api/oc_network_events.c b/api/oc_network_events.c index 3f3068a3b1..9b7c504461 100644 --- a/api/oc_network_events.c +++ b/api/oc_network_events.c @@ -216,14 +216,13 @@ oc_network_drop_receive_events(const oc_endpoint_t *endpoint) } #ifdef OC_DYNAMIC_ALLOCATION - if (get_events_queue_length(endpoint->device, g_network_events) + dropped >= - OC_DEVICE_MAX_NUM_CONCURRENT_REQUESTS) { - // unlock mutex and send a wake-up signal in case the queue for the device - // was full - oc_network_event_handler_mutex_unlock(); + size_t queue_len = + get_events_queue_length(endpoint->device, g_network_events); + // unlock mutex and send a wake-up signal in case the queue for the device was + // full + oc_network_event_handler_mutex_unlock(); + if (queue_len + dropped >= OC_DEVICE_MAX_NUM_CONCURRENT_REQUESTS) { oc_connectivity_wakeup(endpoint->device); - } else { - oc_network_event_handler_mutex_unlock(); } #else oc_network_event_handler_mutex_unlock();