diff --git a/api/cloud/oc_cloud.c b/api/cloud/oc_cloud.c index 7db7f44c0..2831ee5f0 100644 --- a/api/cloud/oc_cloud.c +++ b/api/cloud/oc_cloud.c @@ -132,19 +132,7 @@ void oc_cloud_close_endpoint(const oc_endpoint_t *ep) { OC_CLOUD_DBG("oc_cloud_close_endpoint"); -#ifdef OC_SECURITY - const oc_tls_peer_t *peer = oc_tls_get_peer(ep); - if (peer != NULL) { - OC_CLOUD_DBG("oc_cloud_close_endpoint: oc_tls_close_connection"); - oc_tls_close_connection(ep); - } else -#endif /* OC_SECURITY */ - { -#ifdef OC_TCP - OC_CLOUD_DBG("oc_cloud_close_endpoint: oc_connectivity_end_session"); - oc_connectivity_end_session(ep); -#endif /* OC_TCP */ - } + oc_close_session(ep); } void diff --git a/api/oc_client_api.c b/api/oc_client_api.c index c01aceae7..645ea65c5 100644 --- a/api/oc_client_api.c +++ b/api/oc_client_api.c @@ -18,6 +18,18 @@ #include "oc_config.h" +#include "oc_api.h" +#include "oc_endpoint.h" + +#ifdef OC_TCP +#include "api/oc_session_events_internal.h" +#include "port/oc_connectivity_internal.h" +#endif /* OC_TCP */ + +#ifdef OC_SECURITY +#include "security/oc_tls_internal.h" +#endif /* OC_SECURITY */ + #ifdef OC_CLIENT #include "api/client/oc_client_cb_internal.h" @@ -38,10 +50,6 @@ #include "messaging/coap/signal_internal.h" #endif /* OC_TCP */ -#ifdef OC_SECURITY -#include "security/oc_tls_internal.h" -#endif /* OC_SECURITY */ - #include typedef struct oc_dispatch_context_t @@ -948,18 +956,28 @@ oc_do_ip_discovery_at_endpoint(const char *rt, oc_discovery_handler_t handler, return status; } +#endif /* OC_CLIENT */ + void oc_close_session(const oc_endpoint_t *endpoint) { - if (endpoint->flags & SECURED) { #ifdef OC_SECURITY + if ((endpoint->flags & SECURED) != 0) { oc_tls_close_connection(endpoint); + return; + } #endif /* OC_SECURITY */ - } else if (endpoint->flags & TCP) { #ifdef OC_TCP - oc_connectivity_end_session(endpoint); -#endif /* OC_TCP */ + if ((endpoint->flags & TCP) != 0) { + oc_endpoint_t session_endpoint; + while (oc_connectivity_end_session_v1(endpoint, false, &session_endpoint)) { + oc_handle_session(&session_endpoint, OC_SESSION_DISCONNECTED); + } + return; } -} +#endif /* OC_TCP */ -#endif /* OC_CLIENT */ +#if !defined(OC_TCP) && !defined(OC_SECURITY) + (void)endpoint; +#endif /* !OC_TCP && !OC_SECURITY */ +} diff --git a/api/oc_endpoint.c b/api/oc_endpoint.c index 45a489f66..ff5bd19c2 100644 --- a/api/oc_endpoint.c +++ b/api/oc_endpoint.c @@ -675,6 +675,18 @@ oc_endpoint_compare_address(const oc_endpoint_t *ep1, const oc_endpoint_t *ep2) return -1; } +#ifdef OC_TCP +static int +oc_endpoint_compare_session_ids(const oc_endpoint_t *ep1, + const oc_endpoint_t *ep2) +{ + if (ep1->session_id == 0 || ep2->session_id == 0) { + return 0; // session_id == 0 means any + } + return ep1->session_id == ep2->session_id ? 0 : -1; +} +#endif /* OC_TCP */ + int oc_endpoint_compare(const oc_endpoint_t *ep1, const oc_endpoint_t *ep2) { @@ -690,19 +702,28 @@ oc_endpoint_compare(const oc_endpoint_t *ep1, const oc_endpoint_t *ep2) if (ep1->flags & IPV6) { if (memcmp(ep1->addr.ipv6.address, ep2->addr.ipv6.address, 16) == 0 && ep1->addr.ipv6.port == ep2->addr.ipv6.port) { +#ifdef OC_TCP + return oc_endpoint_compare_session_ids(ep1, ep2); +#else /* OC_TCP */ return 0; +#endif /* !OC_TCP */ } return -1; } #ifdef OC_IPV4 - else if (ep1->flags & IPV4) { + if (ep1->flags & IPV4) { if (memcmp(ep1->addr.ipv4.address, ep2->addr.ipv4.address, 4) == 0 && ep1->addr.ipv4.port == ep2->addr.ipv4.port) { +#ifdef OC_TCP + return oc_endpoint_compare_session_ids(ep1, ep2); +#else /* OC_TCP */ return 0; +#endif /* !OC_TCP */ } return -1; } #endif /* OC_IPV4 */ + // TODO: Add support for other endpoint types return -1; } diff --git a/api/oc_session_events.c b/api/oc_session_events.c index 66420f013..94ef2e39e 100644 --- a/api/oc_session_events.c +++ b/api/oc_session_events.c @@ -133,6 +133,9 @@ oc_session_start_event(const oc_endpoint_t *endpoint) return; } + // only a specific session should be connected + assert(endpoint->session_id != 0); + oc_endpoint_t *ep = oc_new_endpoint(); memcpy(ep, endpoint, sizeof(oc_endpoint_t)); ep->next = NULL; @@ -152,6 +155,9 @@ oc_session_end_event(const oc_endpoint_t *endpoint) return; } + // only a specific session should be disconnected + assert(endpoint->session_id != 0); + oc_endpoint_t *ep = oc_new_endpoint(); memcpy(ep, endpoint, sizeof(oc_endpoint_t)); ep->next = NULL; @@ -332,7 +338,7 @@ handle_session_disconnected(const oc_endpoint_t *endpoint) (void)endpoint; #ifdef OC_SECURITY if ((endpoint->flags & SECURED) != 0 && (endpoint->flags & TCP) != 0) { - oc_tls_remove_peer(endpoint); + oc_tls_remove_peer(endpoint, false); } #endif /* OC_SECURITY */ #ifdef OC_SERVER diff --git a/api/oc_session_events_internal.h b/api/oc_session_events_internal.h index 0fa18b6cf..416f11516 100644 --- a/api/oc_session_events_internal.h +++ b/api/oc_session_events_internal.h @@ -22,11 +22,22 @@ #include "oc_endpoint.h" #include "oc_session_events.h" #include "util/oc_process.h" +#include "util/oc_features.h" #ifdef __cplusplus extern "C" { #endif +/** + * @brief Invoke all session handlers associated with given endpoint + * + * @param endpoint endpoint of the session event (cannot be NULLL) + * @param state new session state + */ +void oc_handle_session(const oc_endpoint_t *endpoint, oc_session_state_t state); + +#ifdef OC_SESSION_EVENTS + #define OC_SESSION_EVENT_API_V0 (0) #define OC_SESSION_EVENT_API_V1 (1) @@ -61,6 +72,30 @@ typedef struct oc_session_event_cb void *user_data; } oc_session_event_cb_t; +/** + * @brief Find first session event callback matching the input parameters. + * + * @param cb handler to match + * @param user_data match user data (only valid for v1 handlers) + * @param ignore_user_data ignore user data for match (only valid for v1 + * handlers) + * @return oc_session_event_cb_t* first matched session event callback + * @return NULL if no match is found + */ +oc_session_event_cb_t *oc_session_event_callback_find( + session_event_versioned_handler_t cb, const void *user_data, + bool ignore_user_data); + +/** + * @brief Remove all previously registered session event notifications + * callbacks. + */ +void oc_session_events_remove_all_callbacks(void); + +#endif /* OC_SESSION_EVENTS */ + +#ifdef OC_TCP + OC_PROCESS_NAME(oc_session_events); /** @@ -77,14 +112,6 @@ void oc_session_start_event(const oc_endpoint_t *endpoint); */ void oc_session_end_event(const oc_endpoint_t *endpoint); -/** - * @brief Invoke all session handlers associated with given endpoint - * - * @param endpoint endpoint of the session event (cannot be NULLL) - * @param state new session state - */ -void oc_handle_session(const oc_endpoint_t *endpoint, oc_session_state_t state); - /** * @brief Check if session events are currently in the process of being * disconnected. @@ -95,25 +122,7 @@ void oc_handle_session(const oc_endpoint_t *endpoint, oc_session_state_t state); */ bool oc_session_events_disconnect_is_ongoing(void); -/** - * @brief Find first session event callback matching the input parameters. - * - * @param cb handler to match - * @param user_data match user data (only valid for v1 handlers) - * @param ignore_user_data ignore user data for match (only valid for v1 - * handlers) - * @return oc_session_event_cb_t* first matched session event callback - * @return NULL if no match is found - */ -oc_session_event_cb_t *oc_session_event_callback_find( - session_event_versioned_handler_t cb, const void *user_data, - bool ignore_user_data); - -/** - * @brief Remove all previously registered session event notifications - * callbacks. - */ -void oc_session_events_remove_all_callbacks(void); +#endif /* OC_TCP */ #ifdef __cplusplus } diff --git a/api/oc_tcp.c b/api/oc_tcp.c index 02c6f290e..17c1a4fa8 100644 --- a/api/oc_tcp.c +++ b/api/oc_tcp.c @@ -24,6 +24,7 @@ #include "oc_endpoint.h" #include "port/oc_connectivity.h" #include "oc_tcp_internal.h" +#include "util/oc_atomic.h" #ifdef OC_SECURITY #include #ifdef OC_OSCORE @@ -86,6 +87,15 @@ oc_tcp_on_connect_event_free(oc_tcp_on_connect_event_t *event) #endif /* OC_HAS_FEATURE_TCP_ASYNC_CONNECT */ +static OC_ATOMIC_UINT32_T g_tcp_session_id = 0; + +uint32_t +oc_tcp_get_new_session_id(void) +{ + uint32_t v = OC_ATOMIC_INCREMENT32(g_tcp_session_id); + return (v == 0) ? OC_ATOMIC_INCREMENT32(g_tcp_session_id) : v; +} + bool oc_tcp_is_valid_header(const uint8_t *data, size_t data_size, bool is_tls) { diff --git a/api/oc_tcp_internal.h b/api/oc_tcp_internal.h index 26c05b812..2c9923de2 100644 --- a/api/oc_tcp_internal.h +++ b/api/oc_tcp_internal.h @@ -26,6 +26,7 @@ #include "messaging/coap/constants.h" #include "port/oc_connectivity.h" #include "oc_endpoint.h" +#include #ifdef __cplusplus extern "C" { @@ -34,6 +35,9 @@ extern "C" { #define OC_TCP_DEFAULT_RECEIVE_SIZE \ (COAP_TCP_DEFAULT_HEADER_LEN + COAP_TCP_MAX_EXTENDED_LENGTH_LEN) +/** @brief Get new tcp session ID */ +uint32_t oc_tcp_get_new_session_id(void); + #ifdef OC_HAS_FEATURE_TCP_ASYNC_CONNECT typedef struct oc_tcp_on_connect_event_s diff --git a/api/plgd/plgd_time.c b/api/plgd/plgd_time.c index bf26bb801..1188764e6 100644 --- a/api/plgd/plgd_time.c +++ b/api/plgd/plgd_time.c @@ -922,7 +922,7 @@ plgd_time_fetch(plgd_time_fetch_config_t fetch, unsigned *flags) OC_ERR("failed to send fetch plgd-time request to endpoint"); #if defined(OC_SECURITY) && defined(OC_PKI) if (add_insecure_peer) { - oc_tls_remove_peer(fetch.endpoint); + oc_tls_remove_peer(fetch.endpoint, true); } #endif /* OC_SECURITY && OC_PKI */ oc_memb_free(&g_fetch_params_s, fetch_params); diff --git a/apps/client_multithread_linux.c b/apps/client_multithread_linux.c index b558b111d..57eab2def 100644 --- a/apps/client_multithread_linux.c +++ b/apps/client_multithread_linux.c @@ -107,7 +107,7 @@ pong_received_handler(oc_client_response_t *data) ping_count++; if (ping_count > PING_RETRY_COUNT) { OC_PRINTF("retry over. close connection.\n"); - oc_connectivity_end_session(data->endpoint); + oc_close_session(data->endpoint); } else { ping_timeout <<= 1; OC_PRINTF("PING send again.[retry: %zd, time: %u]\n", ping_count, diff --git a/include/oc_endpoint.h b/include/oc_endpoint.h index d60dcbd07..ca25526ec 100644 --- a/include/oc_endpoint.h +++ b/include/oc_endpoint.h @@ -98,7 +98,7 @@ typedef struct oc_endpoint_t oc_ipv4_addr_t ipv4; ///< ipv4 address oc_le_addr_t bt; ///< blue tooth address } addr, addr_local; - unsigned interface_index; ///< interface index (valid intefaces are >0, 0 + unsigned interface_index; ///< interface index (valid interfaces are >0, 0 ///< means no index or error) uint8_t priority; ///< priority ocf_version_t version; ///< ocf version @@ -106,6 +106,10 @@ typedef struct oc_endpoint_t uint8_t piv[OSCORE_PIV_LEN]; uint8_t piv_len; #endif /* OC_OSCORE */ +#ifdef OC_TCP + uint32_t session_id; ///< session id for pairing tls peer with tcp session - 0 + ///< means any +#endif } oc_endpoint_t; #define oc_make_ipv4_endpoint(__name__, __flags__, __port__, ...) \ diff --git a/messaging/coap/engine.c b/messaging/coap/engine.c index aa0352097..9fe51449d 100644 --- a/messaging/coap/engine.c +++ b/messaging/coap/engine.c @@ -1100,7 +1100,7 @@ coap_process_invalid_inbound_message(const coap_packet_t *packet, #endif /* OC_SECURITY */ #ifdef OC_TCP if ((msg->endpoint.flags & TCP) != 0) { - oc_connectivity_end_session(&msg->endpoint); + oc_close_session(&msg->endpoint); return; } #endif /* OC_TCP */ diff --git a/messaging/coap/signal.c b/messaging/coap/signal.c index 7995b7550..0212fad3f 100644 --- a/messaging/coap/signal.c +++ b/messaging/coap/signal.c @@ -21,6 +21,7 @@ #include "log_internal.h" #include "signal_internal.h" #include "coap_internal.h" +#include "oc_api.h" #include "transactions_internal.h" #include @@ -223,7 +224,7 @@ coap_signal_handle_message(const coap_packet_t *packet, if (packet->code == RELEASE_7_04) { // alternative address // hold off - oc_connectivity_end_session(endpoint); + oc_close_session(endpoint); return COAP_SIGNAL_DONE; } diff --git a/port/android/ipadapter.c b/port/android/ipadapter.c index dc228895c..9a769fef8 100644 --- a/port/android/ipadapter.c +++ b/port/android/ipadapter.c @@ -1629,13 +1629,25 @@ oc_connectivity_shutdown(size_t device) #ifdef OC_TCP void oc_connectivity_end_session(const oc_endpoint_t *endpoint) +{ + while (oc_connectivity_end_session_v1(endpoint, true, NULL)) { + // no-op + } +} + +bool +oc_connectivity_end_session_v1(const oc_endpoint_t *endpoint, + bool notify_session_end, + oc_endpoint_t *session_endpoint) { if (endpoint->flags & TCP) { ip_context_t *dev = get_ip_context_for_device(endpoint->device); if (dev) { - oc_tcp_end_session(dev, endpoint); + return oc_tcp_end_session(dev, endpoint, notify_session_end, + session_endpoint); } } + return false; } #endif /* OC_TCP */ diff --git a/port/android/tcpadapter.c b/port/android/tcpadapter.c index b811f560f..ccb81ec61 100644 --- a/port/android/tcpadapter.c +++ b/port/android/tcpadapter.c @@ -28,6 +28,7 @@ #include "oc_endpoint.h" #include "oc_session_events.h" #include "port/oc_assert.h" +#include "port/oc_connectivity_internal.h" #include "port/oc_log_internal.h" #include "port/oc_tcp_socket_internal.h" #include "tcpadapter.h" @@ -189,11 +190,11 @@ oc_tcp_add_socks_to_fd_set(ip_context_t *dev) } static void -free_tcp_session(tcp_session_t *session) +free_tcp_session(tcp_session_t *session, bool notify_session_end) { oc_list_remove(session_list, session); - if (!oc_session_events_disconnect_is_ongoing()) { + if (!oc_session_events_disconnect_is_ongoing() && notify_session_end) { oc_session_end_event(&session->endpoint); } @@ -214,7 +215,7 @@ free_tcp_session(tcp_session_t *session) static int add_new_session(int sock, ip_context_t *dev, oc_endpoint_t *endpoint, - tcp_csm_state_t state) + uint32_t session_id, tcp_csm_state_t state) { long if_index = get_interface_index(sock); if (if_index == -1) { @@ -228,9 +229,12 @@ add_new_session(int sock, ip_context_t *dev, oc_endpoint_t *endpoint, return -1; } - endpoint->interface_index = (unsigned)if_index; - session->dev = dev; + endpoint->interface_index = (unsigned)if_index; + if (session_id == 0) { + session_id = oc_tcp_get_new_session_id(); + } + endpoint->session_id = session_id; memcpy(&session->endpoint, endpoint, sizeof(oc_endpoint_t)); session->endpoint.next = NULL; session->sock = sock; @@ -238,8 +242,8 @@ add_new_session(int sock, ip_context_t *dev, oc_endpoint_t *endpoint, oc_list_add(session_list, session); - if (!(endpoint->flags & SECURED)) { - oc_session_start_event(endpoint); + if ((session->endpoint.flags & SECURED) == 0) { + oc_session_start_event(&session->endpoint); } OC_DBG("recorded new TCP session"); @@ -277,7 +281,8 @@ accept_new_session(ip_context_t *dev, int fd, fd_set *setfds, FD_CLR(fd, setfds); - if (add_new_session(new_socket, dev, endpoint, CSM_NONE) < 0) { + if (add_new_session(new_socket, dev, endpoint, /*session_id*/ 0, CSM_NONE) < + 0) { OC_ERR("could not record new TCP session"); close(new_socket); return -1; @@ -309,6 +314,22 @@ find_session_by_endpoint(const oc_endpoint_t *endpoint) return session; } +static tcp_session_t * +find_session_by_id(uint32_t session_id) +{ + tcp_session_t *session = oc_list_head(session_list); + while (session != NULL && session->endpoint.session_id != session_id) { + session = session->next; + } + + if (!session) { + OC_DBG("could not find ongoing TCP session for session id %d", session_id); + return NULL; + } + OC_DBG("found TCP session for session id %d", session_id); + return session; +} + static tcp_session_t * get_ready_to_read_session(fd_set *setfds) { @@ -401,13 +422,13 @@ oc_tcp_receive_message(ip_context_t *dev, fd_set *fds, oc_message_t *message) if (count < 0) { OC_ERR("recv error! %d", errno); - free_tcp_session(session); + free_tcp_session(session, true); ret_with_code(ADAPTER_STATUS_ERROR); } else if (count == 0) { OC_DBG("peer closed TCP session\n"); - free_tcp_session(session); + free_tcp_session(session, true); ret_with_code(ADAPTER_STATUS_NONE); } @@ -428,7 +449,7 @@ oc_tcp_receive_message(ip_context_t *dev, fd_set *fds, oc_message_t *message) oc_tcp_get_total_length_from_message_header(message); if (length_from_header < 0) { OC_ERR("invalid message size in header"); - free_tcp_session(session); + free_tcp_session(session, true); ret_with_code(ADAPTER_STATUS_ERROR); } @@ -438,7 +459,7 @@ oc_tcp_receive_message(ip_context_t *dev, fd_set *fds, oc_message_t *message) OC_ERR( "total receive length(%zu) is bigger than message buffer size(%zu)", total_length, oc_message_buffer_size(message)); - free_tcp_session(session); + free_tcp_session(session, true); ret_with_code(ADAPTER_STATUS_ERROR); } OC_DBG("tcp packet total length : %zu bytes.", total_length); @@ -448,7 +469,7 @@ oc_tcp_receive_message(ip_context_t *dev, fd_set *fds, oc_message_t *message) } while (total_length > message->length); if (!oc_tcp_is_valid_message(message)) { - free_tcp_session(session); + free_tcp_session(session, true); return ADAPTER_STATUS_ERROR; } @@ -461,15 +482,20 @@ oc_tcp_receive_message(ip_context_t *dev, fd_set *fds, oc_message_t *message) return ret; } -void -oc_tcp_end_session(ip_context_t *dev, const oc_endpoint_t *endpoint) +bool +oc_tcp_end_session(ip_context_t *dev, const oc_endpoint_t *endpoint, + bool notify_session_end, oc_endpoint_t *session_endpoint) { pthread_mutex_lock(&dev->tcp.mutex); tcp_session_t *session = find_session_by_endpoint(endpoint); if (session) { - free_tcp_session(session); + if (session_endpoint) { + memcpy(session_endpoint, &session->endpoint, sizeof(oc_endpoint_t)); + } + free_tcp_session(session, notify_session_end); } pthread_mutex_unlock(&dev->tcp.mutex); + return session != NULL; } static int @@ -487,6 +513,7 @@ get_session_socket(const oc_endpoint_t *endpoint) static int initiate_new_session(ip_context_t *dev, oc_endpoint_t *endpoint, + uint32_t session_id, const struct sockaddr_storage *receiver) { int sock = -1; @@ -509,7 +536,7 @@ initiate_new_session(ip_context_t *dev, oc_endpoint_t *endpoint, OC_DBG("successfully initiated TCP connection"); - if (add_new_session(sock, dev, endpoint, CSM_SENT) < 0) { + if (add_new_session(sock, dev, endpoint, session_id, CSM_SENT) < 0) { OC_ERR("could not record new TCP session"); close(sock); return -1; @@ -541,8 +568,9 @@ oc_tcp_send_buffer(ip_context_t *dev, oc_message_t *message, OC_ERR("connection was closed"); goto oc_tcp_send_buffer_done; } - if ((send_sock = initiate_new_session(dev, &message->endpoint, receiver)) < - 0) { + if ((send_sock = + initiate_new_session(dev, &message->endpoint, + message->endpoint.session_id, receiver)) < 0) { OC_ERR("could not initiate new TCP session"); goto oc_tcp_send_buffer_done; } @@ -764,7 +792,7 @@ oc_tcp_connectivity_shutdown(ip_context_t *dev) while (session != NULL) { next = session->next; if (session->endpoint.device == dev->device) { - free_tcp_session(session); + free_tcp_session(session, true); } session = next; } @@ -783,6 +811,15 @@ oc_tcp_connection_state(const oc_endpoint_t *endpoint) return -1; } +int +oc_tcp_session_state(uint32_t session_id) +{ + if (find_session_by_id(session_id) != NULL) { + return OC_TCP_SOCKET_STATE_CONNECTED; + } + return -1; +} + tcp_csm_state_t oc_tcp_get_csm_state(const oc_endpoint_t *endpoint) { diff --git a/port/android/tcpadapter.h b/port/android/tcpadapter.h index 3d400e875..a48c870b6 100644 --- a/port/android/tcpadapter.h +++ b/port/android/tcpadapter.h @@ -39,7 +39,9 @@ void oc_tcp_add_socks_to_fd_set(ip_context_t *dev); adapter_receive_state_t oc_tcp_receive_message(ip_context_t *dev, fd_set *fds, oc_message_t *message); -void oc_tcp_end_session(ip_context_t *dev, const oc_endpoint_t *endpoint); +bool oc_tcp_end_session(ip_context_t *dev, const oc_endpoint_t *endpoint, + bool notify_session_end, + oc_endpoint_t *session_endpoint); #ifdef __cplusplus } diff --git a/port/esp32/adapter/src/ipadapter.c b/port/esp32/adapter/src/ipadapter.c index 1f2dac88f..3946e1cd1 100644 --- a/port/esp32/adapter/src/ipadapter.c +++ b/port/esp32/adapter/src/ipadapter.c @@ -1617,13 +1617,25 @@ oc_connectivity_shutdown(size_t device) #ifdef OC_TCP void oc_connectivity_end_session(const oc_endpoint_t *endpoint) +{ + while (oc_connectivity_end_session_v1(endpoint, true, NULL)) { + // no-op + } +} + +bool +oc_connectivity_end_session_v1(const oc_endpoint_t *endpoint, + bool notify_session_end, + oc_endpoint_t *session_endpoint) { if (endpoint->flags & TCP) { ip_context_t *dev = get_ip_context_for_device(endpoint->device); if (dev) { - oc_tcp_end_session(dev, endpoint); + return oc_tcp_end_session(dev, endpoint, notify_session_end, + session_endpoint); } } + return false; } #endif /* OC_TCP */ diff --git a/port/esp32/adapter/src/tcpadapter.c b/port/esp32/adapter/src/tcpadapter.c index 45acfc8a6..b07c29e2c 100644 --- a/port/esp32/adapter/src/tcpadapter.c +++ b/port/esp32/adapter/src/tcpadapter.c @@ -28,20 +28,21 @@ #include "oc_endpoint.h" #include "oc_session_events.h" #include "port/oc_assert.h" +#include "port/oc_connectivity_internal.h" #include "port/oc_log_internal.h" #include "port/oc_tcp_socket_internal.h" #include "tcpadapter.h" #include "util/oc_memb.h" +#include "vfs_pipe.h" #include #include #include +#include #include -// #include -#include "esp_netif.h" -#include "vfs_pipe.h" #include #include +#include #include #include @@ -159,11 +160,11 @@ oc_tcp_add_socks_to_fd_set(ip_context_t *dev) } static void -free_tcp_session(tcp_session_t *session) +free_tcp_session(tcp_session_t *session, bool notify_session_end) { oc_list_remove(session_list, session); - if (!oc_session_events_disconnect_is_ongoing()) { + if (!oc_session_events_disconnect_is_ongoing() && notify_session_end) { oc_session_end_event(&session->endpoint); } @@ -184,7 +185,7 @@ free_tcp_session(tcp_session_t *session) static int add_new_session(int sock, ip_context_t *dev, oc_endpoint_t *endpoint, - tcp_csm_state_t state) + uint32_t session_id, tcp_csm_state_t state) { int if_index = get_interface_index(sock); if (if_index < 0) { @@ -198,9 +199,12 @@ add_new_session(int sock, ip_context_t *dev, oc_endpoint_t *endpoint, return -1; } - endpoint->interface_index = (unsigned)if_index; - session->dev = dev; + endpoint->interface_index = (unsigned)if_index; + if (session_id == 0) { + session_id = oc_tcp_get_new_session_id(); + } + endpoint->session_id = session_id; memcpy(&session->endpoint, endpoint, sizeof(oc_endpoint_t)); session->endpoint.next = NULL; session->sock = sock; @@ -208,8 +212,8 @@ add_new_session(int sock, ip_context_t *dev, oc_endpoint_t *endpoint, oc_list_add(session_list, session); - if (!(endpoint->flags & SECURED)) { - oc_session_start_event(endpoint); + if ((session->endpoint.flags & SECURED) == 0) { + oc_session_start_event(&session->endpoint); } OC_DBG("recorded new TCP session"); @@ -248,7 +252,8 @@ accept_new_session(ip_context_t *dev, int fd, fd_set *setfds, FD_CLR(fd, setfds); - if (add_new_session(new_socket, dev, endpoint, CSM_NONE) < 0) { + if (add_new_session(new_socket, dev, endpoint, /*session_id*/ 0, CSM_NONE) < + 0) { OC_ERR("could not record new TCP session"); close(new_socket); return -1; @@ -280,6 +285,22 @@ find_session_by_endpoint(const oc_endpoint_t *endpoint) return session; } +static tcp_session_t * +find_session_by_id(uint32_t session_id) +{ + tcp_session_t *session = oc_list_head(session_list); + while (session != NULL && session->endpoint.session_id != session_id) { + session = session->next; + } + + if (!session) { + OC_DBG("could not find ongoing TCP session for session id %d", session_id); + return NULL; + } + OC_DBG("found TCP session for session id %d", session_id); + return session; +} + static tcp_session_t * get_ready_to_read_session(fd_set *setfds) { @@ -374,13 +395,13 @@ oc_tcp_receive_message(ip_context_t *dev, fd_set *fds, oc_message_t *message) if (count < 0) { OC_ERR("recv error! %d", errno); - free_tcp_session(session); + free_tcp_session(session, true); ret_with_code(ADAPTER_STATUS_ERROR); } else if (count == 0) { OC_DBG("peer closed TCP session\n"); - free_tcp_session(session); + free_tcp_session(session, true); ret_with_code(ADAPTER_STATUS_NONE); } @@ -401,7 +422,7 @@ oc_tcp_receive_message(ip_context_t *dev, fd_set *fds, oc_message_t *message) oc_tcp_get_total_length_from_message_header(message); if (length_from_header < 0) { OC_ERR("invalid message size in header"); - free_tcp_session(session); + free_tcp_session(session, true); ret_with_code(ADAPTER_STATUS_ERROR); } @@ -411,7 +432,7 @@ oc_tcp_receive_message(ip_context_t *dev, fd_set *fds, oc_message_t *message) OC_ERR( "total receive length(%zu) is bigger than message buffer size(%zu)", total_length, oc_message_buffer_size(message)); - free_tcp_session(session); + free_tcp_session(session, true); ret_with_code(ADAPTER_STATUS_ERROR); } OC_DBG("tcp packet total length : %zu bytes.", total_length); @@ -421,7 +442,7 @@ oc_tcp_receive_message(ip_context_t *dev, fd_set *fds, oc_message_t *message) } while (total_length > message->length); if (!oc_tcp_is_valid_message(message)) { - free_tcp_session(session); + free_tcp_session(session, true); ret_with_code(ADAPTER_STATUS_ERROR); } @@ -434,15 +455,20 @@ oc_tcp_receive_message(ip_context_t *dev, fd_set *fds, oc_message_t *message) return ret; } -void -oc_tcp_end_session(ip_context_t *dev, const oc_endpoint_t *endpoint) +bool +oc_tcp_end_session(ip_context_t *dev, const oc_endpoint_t *endpoint, + bool notify_session_end, oc_endpoint_t *session_endpoint) { pthread_mutex_lock(&dev->tcp.mutex); tcp_session_t *session = find_session_by_endpoint(endpoint); if (session) { - free_tcp_session(session); + if (session_endpoint) { + memcpy(session_endpoint, &session->endpoint, sizeof(oc_endpoint_t)); + } + free_tcp_session(session, notify_session_end); } pthread_mutex_unlock(&dev->tcp.mutex); + return session != NULL; } static int @@ -460,6 +486,7 @@ get_session_socket(const oc_endpoint_t *endpoint) static int initiate_new_session(ip_context_t *dev, oc_endpoint_t *endpoint, + uint32_t session_id, const struct sockaddr_storage *receiver) { int sock = -1; @@ -482,7 +509,7 @@ initiate_new_session(ip_context_t *dev, oc_endpoint_t *endpoint, OC_DBG("successfully initiated TCP connection"); - if (add_new_session(sock, dev, endpoint, CSM_SENT) < 0) { + if (add_new_session(sock, dev, endpoint, session_id, CSM_SENT) < 0) { OC_ERR("could not record new TCP session"); close(sock); return -1; @@ -514,8 +541,9 @@ oc_tcp_send_buffer(ip_context_t *dev, oc_message_t *message, OC_ERR("connection was closed"); goto oc_tcp_send_buffer_done; } - if ((send_sock = initiate_new_session(dev, &message->endpoint, receiver)) < - 0) { + if ((send_sock = + initiate_new_session(dev, &message->endpoint, + message->endpoint.session_id, receiver)) < 0) { OC_ERR("could not initiate new TCP session"); goto oc_tcp_send_buffer_done; } @@ -724,7 +752,7 @@ oc_tcp_connectivity_shutdown(ip_context_t *dev) while (session != NULL) { next = session->next; if (session->endpoint.device == dev->device) { - free_tcp_session(session); + free_tcp_session(session, true); } session = next; } @@ -743,6 +771,15 @@ oc_tcp_connection_state(const oc_endpoint_t *endpoint) return -1; } +int +oc_tcp_session_state(uint32_t session_id) +{ + if (find_session_by_id(session_id) != NULL) { + return OC_TCP_SOCKET_STATE_CONNECTED; + } + return -1; +} + tcp_csm_state_t oc_tcp_get_csm_state(const oc_endpoint_t *endpoint) { diff --git a/port/esp32/adapter/src/tcpadapter.h b/port/esp32/adapter/src/tcpadapter.h index 3d400e875..a48c870b6 100644 --- a/port/esp32/adapter/src/tcpadapter.h +++ b/port/esp32/adapter/src/tcpadapter.h @@ -39,7 +39,9 @@ void oc_tcp_add_socks_to_fd_set(ip_context_t *dev); adapter_receive_state_t oc_tcp_receive_message(ip_context_t *dev, fd_set *fds, oc_message_t *message); -void oc_tcp_end_session(ip_context_t *dev, const oc_endpoint_t *endpoint); +bool oc_tcp_end_session(ip_context_t *dev, const oc_endpoint_t *endpoint, + bool notify_session_end, + oc_endpoint_t *session_endpoint); #ifdef __cplusplus } diff --git a/port/linux/ipadapter.c b/port/linux/ipadapter.c index 7a15a0e6b..646fdec05 100644 --- a/port/linux/ipadapter.c +++ b/port/linux/ipadapter.c @@ -1577,12 +1577,23 @@ oc_connectivity_shutdown(size_t device) } #ifdef OC_TCP -void -oc_connectivity_end_session(const oc_endpoint_t *endpoint) +bool +oc_connectivity_end_session_v1(const oc_endpoint_t *endpoint, + bool notify_session_end, + oc_endpoint_t *session_endpoint) { if ((endpoint->flags & TCP) != 0 && oc_get_ip_context_for_device(endpoint->device) != NULL) { - tcp_end_session(endpoint); + return tcp_end_session(endpoint, notify_session_end, session_endpoint); + } + return false; +} + +void +oc_connectivity_end_session(const oc_endpoint_t *endpoint) +{ + while (oc_connectivity_end_session_v1(endpoint, true, NULL)) { + // no-op } } #endif /* OC_TCP */ diff --git a/port/linux/tcpsession.c b/port/linux/tcpsession.c index 344583bb9..4199e259f 100644 --- a/port/linux/tcpsession.c +++ b/port/linux/tcpsession.c @@ -60,6 +60,7 @@ typedef struct tcp_session_t oc_endpoint_t endpoint; int sock; tcp_csm_state_t csm_state; + bool notify_session_end; } tcp_session_t; static pthread_mutex_t g_mutex = PTHREAD_MUTEX_INITIALIZER; @@ -95,6 +96,7 @@ typedef struct tcp_waiting_session_t OC_LIST_STRUCT(messages); on_tcp_connect_t on_tcp_connect; void *on_tcp_connect_data; + bool notify_session_end; } tcp_waiting_session_t; OC_LIST(g_waiting_session_list); ///< sessions waiting to open a connection, @@ -203,20 +205,39 @@ get_interface_index(int sock) static void log_new_session(oc_endpoint_t *endpoint, int sock, bool is_connected) { + // GCOVR_EXCL_START oc_string64_t ep; const char *addr = ""; if (oc_endpoint_to_string64(endpoint, &ep)) { addr = oc_string(ep); } OC_DBG("new TCP session endpoint: %s, endpoint interface: %d, sock: %d, " - "connected: %d", - addr, endpoint->interface_index, sock, (int)is_connected); + "connected: %d, session_id: %u", + addr, endpoint->interface_index, sock, (int)is_connected, + (unsigned)endpoint->session_id); + // GCOVR_EXCL_STOP } + +static void +log_free_session(oc_endpoint_t *endpoint, int sock) +{ + // GCOVR_EXCL_START + oc_string64_t ep; + const char *addr = ""; + if (oc_endpoint_to_string64(endpoint, &ep)) { + addr = oc_string(ep); + } + OC_DBG("free TCP session endpoint: %s, endpoint interface: %d, sock: %d, " + "session_id: %u", + addr, endpoint->interface_index, sock, (unsigned)endpoint->session_id); + // GCOVR_EXCL_STOP +} + #endif /* OC_DBG_IS_ENABLED */ static tcp_session_t * add_new_session_locked(int sock, ip_context_t *dev, oc_endpoint_t *endpoint, - tcp_csm_state_t state) + uint32_t session_id, tcp_csm_state_t state) { long if_index = get_interface_index(sock); if (if_index < 0) { @@ -233,10 +254,16 @@ add_new_session_locked(int sock, ip_context_t *dev, oc_endpoint_t *endpoint, session->dev = dev; endpoint->interface_index = (unsigned)if_index; + if (session_id == 0) { + session_id = oc_tcp_get_new_session_id(); + } + endpoint->session_id = session_id; memcpy(&session->endpoint, endpoint, sizeof(oc_endpoint_t)); session->endpoint.next = NULL; + session->endpoint.interface_index = (unsigned)if_index; session->sock = sock; session->csm_state = state; + session->notify_session_end = true; oc_list_add(g_session_list, session); @@ -281,7 +308,8 @@ accept_new_session_locked(ip_context_t *dev, int fd, fd_set *setfds, #endif /* !OC_IPV4 */ } - if (add_new_session_locked(new_socket, dev, endpoint, CSM_NONE) == NULL) { + if (add_new_session_locked(new_socket, dev, endpoint, + /*session_id*/ 0, CSM_NONE) == NULL) { OC_ERR("could not record new TCP session"); close(new_socket); return -1; @@ -297,7 +325,8 @@ free_session_locked(tcp_session_t *session, bool signal) oc_list_remove(g_session_list, session); oc_list_remove(g_free_session_list_async, session); - if (!oc_session_events_disconnect_is_ongoing()) { + if (!oc_session_events_disconnect_is_ongoing() && + session->notify_session_end) { oc_session_end_event(&session->endpoint); } @@ -307,8 +336,9 @@ free_session_locked(tcp_session_t *session, bool signal) signal_network_thread(&session->dev->tcp); } close(session->sock); - - OC_DBG("free TCP session(%p, fd=%d)", (void *)session, session->sock); +#if OC_DBG_IS_ENABLED + log_free_session(&session->endpoint, session->sock); +#endif /* OC_DBG_IS_ENABLED */ oc_memb_free(&g_tcp_session_s, session); } @@ -525,14 +555,24 @@ find_session_by_endpoint_locked(const oc_endpoint_t *endpoint) return session; } +static tcp_session_t * +find_session_by_id_locked(uint32_t session_id) +{ + tcp_session_t *session = oc_list_head(g_session_list); + while (session != NULL && session->endpoint.session_id != session_id) { + session = session->next; + } + return session; +} + #ifdef OC_HAS_FEATURE_TCP_ASYNC_CONNECT static tcp_session_t * tcp_create_session_locked(int sock, ip_context_t *dev, oc_endpoint_t *endpoint, - bool signal) + uint32_t session_id, bool signal) { tcp_session_t *session = - add_new_session_locked(sock, dev, endpoint, CSM_SENT); + add_new_session_locked(sock, dev, endpoint, session_id, CSM_SENT); if (session == NULL) { OC_ERR("could not record new TCP session"); return NULL; @@ -560,6 +600,17 @@ find_waiting_session_by_endpoint_locked(const oc_endpoint_t *endpoint) return ws; } +static tcp_waiting_session_t * +find_waiting_session_by_id_locked(uint32_t session_id) +{ + tcp_waiting_session_t *ws = + (tcp_waiting_session_t *)oc_list_head(g_waiting_session_list); + while (ws != NULL && ws->endpoint.session_id != session_id) { + ws = ws->next; + } + return ws; +} + static tcp_waiting_session_t * add_new_waiting_session_locked(int sock, ip_context_t *dev, const oc_endpoint_t *endpoint, @@ -575,6 +626,7 @@ add_new_waiting_session_locked(int sock, ip_context_t *dev, ws->dev = dev; memcpy(&ws->endpoint, endpoint, sizeof(oc_endpoint_t)); + ws->endpoint.session_id = oc_tcp_get_new_session_id(); ws->endpoint.next = NULL; ws->sock = sock; OC_LIST_STRUCT_INIT(ws, messages); @@ -582,6 +634,7 @@ add_new_waiting_session_locked(int sock, ip_context_t *dev, ws->retry.count = 0; ws->on_tcp_connect = on_tcp_connect; ws->on_tcp_connect_data = on_tcp_connect_data; + ws->notify_session_end = true; #if OC_DBG_IS_ENABLED log_new_session(&ws->endpoint, sock, false); @@ -655,8 +708,9 @@ tcp_connect_locked(ip_context_t *dev, oc_endpoint_t *endpoint, oc_tcp_socket_t cs = oc_tcp_socket_connect(endpoint, receiver); if (cs.state == OC_TCP_SOCKET_STATE_CONNECTED) { OC_DBG("successfully initiated TCP connection"); - s = tcp_create_session_locked(cs.fd, dev, endpoint, true); + s = tcp_create_session_locked(cs.fd, dev, endpoint, /*session_id*/ 0, true); if (s != NULL) { + res.session = s; res.created = true; return res; } @@ -679,10 +733,11 @@ tcp_connect_locked(ip_context_t *dev, oc_endpoint_t *endpoint, #endif /* OC_HAS_FEATURE_TCP_ASYNC_CONNECT */ static void -free_session_async_locked(tcp_session_t *s) +free_session_async_locked(tcp_session_t *s, bool notify_session_end) { oc_list_remove(g_session_list, s); oc_list_add(g_free_session_list_async, s); + s->notify_session_end = notify_session_end; signal_network_thread(&s->dev->tcp); OC_DBG("signaled network event thread to monitor that the session needs to " @@ -692,10 +747,12 @@ free_session_async_locked(tcp_session_t *s) #ifdef OC_HAS_FEATURE_TCP_ASYNC_CONNECT static void -free_waiting_session_async_locked(tcp_waiting_session_t *ws) +free_waiting_session_async_locked(tcp_waiting_session_t *ws, + bool notify_session_end) { oc_list_remove(g_waiting_session_list, ws); oc_list_add(g_free_waiting_session_list_async, ws); + ws->notify_session_end = notify_session_end; signal_network_thread(&ws->dev->tcp); OC_DBG("signaled network event thread to monitor that the session needs to " @@ -704,27 +761,35 @@ free_waiting_session_async_locked(tcp_waiting_session_t *ws) } #endif /* OC_HAS_FEATURE_TCP_ASYNC_CONNECT */ -void -tcp_end_session(const oc_endpoint_t *endpoint) +bool +tcp_end_session(const oc_endpoint_t *endpoint, bool notify_session_end, + oc_endpoint_t *session_endpoint) { pthread_mutex_lock(&g_mutex); tcp_session_t *s = find_session_by_endpoint_locked(endpoint); if (s != NULL) { - free_session_async_locked(s); + free_session_async_locked(s, notify_session_end); + if (session_endpoint) { + memcpy(session_endpoint, &s->endpoint, sizeof(oc_endpoint_t)); + } pthread_mutex_unlock(&g_mutex); - return; + return true; } #ifdef OC_HAS_FEATURE_TCP_ASYNC_CONNECT tcp_waiting_session_t *ws = find_waiting_session_by_endpoint_locked(endpoint); if (ws != NULL) { - free_waiting_session_async_locked(ws); + free_waiting_session_async_locked(ws, notify_session_end); + if (session_endpoint) { + memcpy(session_endpoint, &ws->endpoint, sizeof(oc_endpoint_t)); + } pthread_mutex_unlock(&g_mutex); - return; + return true; } #endif /* OC_HAS_FEATURE_TCP_ASYNC_CONNECT */ pthread_mutex_unlock(&g_mutex); + return false; } #ifdef OC_HAS_FEATURE_TCP_ASYNC_CONNECT @@ -839,6 +904,24 @@ oc_tcp_connection_state(const oc_endpoint_t *endpoint) return -1; } +int +oc_tcp_session_state(uint32_t session_id) +{ + pthread_mutex_lock(&g_mutex); + if (find_session_by_id_locked(session_id) != NULL) { + pthread_mutex_unlock(&g_mutex); + return OC_TCP_SOCKET_STATE_CONNECTED; + } +#ifdef OC_HAS_FEATURE_TCP_ASYNC_CONNECT + if (find_waiting_session_by_id_locked(session_id) != NULL) { + pthread_mutex_unlock(&g_mutex); + return OC_TCP_SOCKET_STATE_CONNECTING; + } +#endif /* OC_HAS_FEATURE_TCP_ASYNC_CONNECT */ + pthread_mutex_unlock(&g_mutex); + return -1; +} + static int tcp_send_message(int sockfd, const oc_message_t *message) { @@ -1080,8 +1163,8 @@ tcp_try_connect_waiting_session_locked(tcp_waiting_session_t *ws, int *err) return false; } - tcp_session_t *s = - tcp_create_session_locked(ws->sock, ws->dev, &ws->endpoint, false); + tcp_session_t *s = tcp_create_session_locked(ws->sock, ws->dev, &ws->endpoint, + ws->endpoint.session_id, false); if (s == NULL) { return false; } @@ -1155,8 +1238,8 @@ tcp_retry_waiting_session_locked(tcp_waiting_session_t *ws, oc_tcp_socket_t cs = oc_tcp_socket_connect(&ws->endpoint, NULL); if (cs.state == OC_TCP_SOCKET_STATE_CONNECTED) { OC_DBG("successfully initiated TCP connection"); - tcp_session_t *s = - tcp_create_session_locked(cs.fd, ws->dev, &ws->endpoint, false); + tcp_session_t *s = tcp_create_session_locked( + cs.fd, ws->dev, &ws->endpoint, ws->endpoint.session_id, false); if (s == NULL) { OC_ERR("cannot allocate ongoing TCP connection"); return -1; @@ -1266,40 +1349,74 @@ tcp_process_waiting_sessions(fd_set *fds) return ret; } -static int -oc_tcp_connect_to_endpoint(ip_context_t *dev, oc_endpoint_t *endpoint, - on_tcp_connect_t on_tcp_connect, - void *on_tcp_connect_data) +static oc_tcp_connect_result_t +tcp_connect_to_endpoint(ip_context_t *dev, oc_endpoint_t *endpoint, + on_tcp_connect_t on_tcp_connect, + void *on_tcp_connect_data) { struct sockaddr_storage receiver = oc_socket_get_address(endpoint); pthread_mutex_lock(&g_mutex); tcp_connect_result_t res = tcp_connect_locked( dev, endpoint, &receiver, on_tcp_connect, on_tcp_connect_data); + bool is_connected = false; + uint32_t session_id = 0; + if (res.session != NULL) { + is_connected = true; + session_id = res.session->endpoint.session_id; + } else if (res.waiting_session != NULL) { + session_id = res.waiting_session->endpoint.session_id; + } pthread_mutex_unlock(&g_mutex); - if (res.session == NULL && res.waiting_session == NULL) { - return OC_TCP_SOCKET_ERROR; + if (session_id == 0) { + return (oc_tcp_connect_result_t){ + .error = OC_TCP_SOCKET_ERROR, + }; } - bool is_connected = res.session != NULL; if (!res.created) { - return is_connected ? OC_TCP_SOCKET_ERROR_EXISTS_CONNECTED - : OC_TCP_SOCKET_ERROR_EXISTS_CONNECTING; - } + oc_tcp_socket_error_t err = is_connected + ? OC_TCP_SOCKET_ERROR_EXISTS_CONNECTED + : OC_TCP_SOCKET_ERROR_EXISTS_CONNECTING; + return (oc_tcp_connect_result_t){ + .session_id = session_id, + .error = err, + }; + } + + oc_tcp_socket_state_t state = is_connected ? OC_TCP_SOCKET_STATE_CONNECTED + : OC_TCP_SOCKET_STATE_CONNECTING; + return (oc_tcp_connect_result_t){ + .state = state, + .session_id = session_id, + }; +} - return is_connected ? OC_TCP_SOCKET_STATE_CONNECTED - : OC_TCP_SOCKET_STATE_CONNECTING; +oc_tcp_connect_result_t +oc_tcp_connect_to_endpoint(oc_endpoint_t *endpoint, + on_tcp_connect_t on_tcp_connect, + void *on_tcp_connect_data) +{ + assert((endpoint->flags & TCP) != 0); + ip_context_t *dev = oc_get_ip_context_for_device(endpoint->device); + if (dev == NULL) { + OC_ERR("cannot find ip-context for device(%zu)", endpoint->device); + return (oc_tcp_connect_result_t){ + .error = -1, + }; + } + return tcp_connect_to_endpoint(dev, endpoint, on_tcp_connect, + on_tcp_connect_data); } int oc_tcp_connect(oc_endpoint_t *endpoint, on_tcp_connect_t on_tcp_connect, void *on_tcp_connect_data) { - ip_context_t *dev = oc_get_ip_context_for_device(endpoint->device); - if (dev == NULL) { - OC_ERR("cannot find ip-context for device(%zu)", endpoint->device); - return -1; + oc_tcp_connect_result_t ret = + oc_tcp_connect_to_endpoint(endpoint, on_tcp_connect, on_tcp_connect_data); + if (ret.session_id != 0) { + endpoint->session_id = ret.session_id; } - return oc_tcp_connect_to_endpoint(dev, endpoint, on_tcp_connect, - on_tcp_connect_data); + return ret.error != 0 ? ret.error : (int)ret.state; } #endif /* OC_HAS_FEATURE_TCP_ASYNC_CONNECT */ diff --git a/port/linux/tcpsession.h b/port/linux/tcpsession.h index cd4488e79..e26d684c4 100644 --- a/port/linux/tcpsession.h +++ b/port/linux/tcpsession.h @@ -17,20 +17,22 @@ * ****************************************************************************/ -#ifndef TCP_SESION_H -#define TCP_SESION_H +#ifndef TCP_SESSION_H +#define TCP_SESSION_H + +#include "util/oc_features.h" + +#ifdef OC_TCP #include "port/oc_clock.h" #include "port/oc_connectivity.h" -#include "util/oc_features.h" #include "ipcontext.h" #include "oc_endpoint.h" #include "tcpcontext.h" + #include #include -#ifdef OC_TCP - #ifdef __cplusplus extern "C" { #endif @@ -105,7 +107,8 @@ adapter_receive_state_t tcp_receive_message(ip_context_t *dev, fd_set *fds, * @brief Schedule the session associated with the endpoint to be stopped and * deallocated (if it exists). */ -void tcp_end_session(const oc_endpoint_t *endpoint); +bool tcp_end_session(const oc_endpoint_t *endpoint, bool notify_session_end, + oc_endpoint_t *session_endpoint) OC_NONNULL(1); /** * @brief Handle data received on the signal pipe. @@ -118,6 +121,7 @@ void tcp_session_handle_signal(void); void tcp_session_shutdown(const ip_context_t *dev); #ifdef OC_HAS_FEATURE_TCP_ASYNC_CONNECT + /** * @brief Iterate over TCP sessions waiting for connection. Deallocate expired * sessions. Retry the connection process for sessions that haven't reached the @@ -154,4 +158,4 @@ bool tcp_process_waiting_sessions(fd_set *fds); #endif /* OC_TCP */ -#endif /* TCP_SESION_H */ +#endif /* TCP_SESSION_H */ diff --git a/port/oc_connectivity.h b/port/oc_connectivity.h index 0b6e2b15f..fb89df95a 100644 --- a/port/oc_connectivity.h +++ b/port/oc_connectivity.h @@ -158,11 +158,14 @@ int oc_send_buffer(oc_message_t *message); void oc_send_discovery_request(oc_message_t *message); /** - * @brief end session for the specific endpoint + * @brief end TCP session for the specific endpoint. * * @param endpoint the endpoint to close the session for + * + * @deprecated replaced by oc_close_session in v2.2.5.14 */ -void oc_connectivity_end_session(const oc_endpoint_t *endpoint); +void oc_connectivity_end_session(const oc_endpoint_t *endpoint) + OC_DEPRECATED("replaced by oc_close_session in v2.2.5.14"); #ifdef OC_DNS_LOOKUP /** diff --git a/port/oc_connectivity_internal.h b/port/oc_connectivity_internal.h index fa522b28c..413cab1b0 100644 --- a/port/oc_connectivity_internal.h +++ b/port/oc_connectivity_internal.h @@ -25,6 +25,7 @@ #include "oc_network_events.h" #include "oc_session_events.h" #include "port/oc_connectivity.h" +#include "util/oc_compiler.h" #include "util/oc_features.h" #include #include @@ -64,20 +65,6 @@ void oc_connectivity_shutdown(size_t device); */ int oc_send_buffer2(oc_message_t *message, bool queue); -#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 @@ -98,6 +85,64 @@ void handle_session_event_callback(const oc_endpoint_t *endpoint, oc_session_state_t state); #endif /* OC_SESSION_EVENTS */ +#ifdef OC_TCP + +/** + * @brief End TCP session for the specific endpoint. + * + * @param endpoint the endpoint to close the session for + * @param notify_session_end send the notification about the disconnection + * session. + * @param session_endpoint the endpoint of the session with session id + * @return bool true if the session will be closed + */ +bool oc_connectivity_end_session_v1(const oc_endpoint_t *endpoint, + bool notify_session_end, + oc_endpoint_t *session_endpoint) + OC_NONNULL(1); + +#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 + +/** @brief Connect to endpoint and return connection state and session id */ +typedef struct +{ + uint32_t session_id; + oc_tcp_socket_state_t state; + int error; +} oc_tcp_connect_result_t; + +/** @brief Connect to TCP endpoint and return connection state and session id */ +oc_tcp_connect_result_t oc_tcp_connect_to_endpoint( + oc_endpoint_t *endpoint, on_tcp_connect_t on_tcp_connect, + void *on_tcp_connect_data) OC_NONNULL(1); + +void oc_tcp_set_connect_retry(uint8_t max_count, uint16_t timeout); + +#endif /* OC_HAS_FEATURE_TCP_ASYNC_CONNECT */ + +/** + * @brief Get state of TCP connection for given session id. + * + * @param session_id session id + * @return OC_TCP_SOCKET_STATE_CONNECTED TCP connection exists and it is ongoing + * @return OC_TCP_SOCKET_STATE_CONNECTING TCP connection is waiting to be + * established + * @return -1 otherwise + */ +int oc_tcp_session_state(uint32_t session_id); + +#endif /* OC_TCP */ + #ifdef __cplusplus } #endif diff --git a/port/unittest/connectivitytest.cpp b/port/unittest/connectivitytest.cpp index f5a747cee..52b7b3b1d 100644 --- a/port/unittest/connectivitytest.cpp +++ b/port/unittest/connectivitytest.cpp @@ -42,6 +42,8 @@ #include #include +using namespace std::chrono_literals; + static constexpr size_t kDeviceID = 0; class TestConnectivity : public testing::Test { @@ -462,11 +464,14 @@ TEST_F(TestConnectivityWithServer, oc_tcp_update_csm_state_P) coap_serialize_message(&packet, msg->data, oc_message_buffer_size(msg)); oc_send_buffer(msg); + ep.session_id = msg->endpoint.session_id; oc_message_unref(msg); #endif /* OC_HAS_FEATURE_TCP_ASYNC_CONNECT */ #ifdef OC_TCP EXPECT_EQ(OC_TCP_SOCKET_STATE_CONNECTED, oc_tcp_connection_state(&ep)); + ASSERT_NE(0, ep.session_id); + EXPECT_EQ(OC_TCP_SOCKET_STATE_CONNECTED, oc_tcp_session_state(ep.session_id)); #endif /* OC_TCP */ EXPECT_EQ(0, oc_tcp_update_csm_state(&ep, CSM_DONE)); @@ -526,7 +531,7 @@ TEST_F(TestConnectivityWithServer, oc_tcp_connect_timeout) return; } - EXPECT_EQ(OC_TCP_SOCKET_STATE_CONNECTING, ret); + ASSERT_EQ(OC_TCP_SOCKET_STATE_CONNECTING, ret); oc_message_t *msg = oc_allocate_message(); memcpy(&msg->endpoint, &ep, sizeof(oc_endpoint_t)); @@ -544,6 +549,36 @@ TEST_F(TestConnectivityWithServer, oc_tcp_connect_timeout) restore_defaults(); } +TEST_F(TestConnectivityWithServer, oc_tcp_cleanup_waiting_session) +{ + auto addr = "coap+tcp://[::1]:12345"; + oc_endpoint_t ep1 = + oc::endpoint::FromString(addr); // reachable address, but inactive port + + oc_tcp_connect_result_t ret1 = + oc_tcp_connect_to_endpoint(&ep1, nullptr, nullptr); + ASSERT_EQ(0, ret1.error); + ASSERT_EQ(OC_TCP_SOCKET_STATE_CONNECTING, ret1.state); + ASSERT_NE(0, ret1.session_id); + + // disconnect is asynchronous, we should be able to open a new session to + // the same endpoint + oc_close_session(&ep1); + + oc_endpoint_t ep2 = oc::endpoint::FromString(addr); + oc_tcp_connect_result_t ret2 = + oc_tcp_connect_to_endpoint(&ep2, nullptr, nullptr); + ASSERT_EQ(0, ret2.error); + ASSERT_EQ(OC_TCP_SOCKET_STATE_CONNECTING, ret2.state); + ASSERT_NE(0, ret2.session_id); + + oc::TestDevice::PoolEventsMsV1(20ms); + + EXPECT_EQ(-1, oc_tcp_session_state(ret1.session_id)); + EXPECT_EQ(OC_TCP_SOCKET_STATE_CONNECTING, + oc_tcp_session_state(ret2.session_id)); +} + #endif /* __linux__ */ TEST_F(TestConnectivityWithServer, oc_tcp_connect_repeat_fail) diff --git a/port/windows/ipadapter.c b/port/windows/ipadapter.c index 34589fb06..4bb322ef3 100644 --- a/port/windows/ipadapter.c +++ b/port/windows/ipadapter.c @@ -1684,13 +1684,24 @@ oc_connectivity_shutdown(size_t device) #ifdef OC_TCP void oc_connectivity_end_session(const oc_endpoint_t *endpoint) +{ + while (oc_connectivity_end_session_v1(endpoint, true, NULL)) { + // no-op + } +} + +bool +oc_connectivity_end_session_v1(const oc_endpoint_t *endpoint, + bool notify_session_end, + oc_endpoint_t *session_endpoint) { if (endpoint->flags & TCP) { ip_context_t *dev = get_ip_context_for_device(endpoint->device); - if (dev != NULL) { - oc_tcp_end_session(endpoint); + if (dev) { + return oc_tcp_end_session(endpoint, notify_session_end, session_endpoint); } } + return false; } #endif /* OC_TCP */ diff --git a/port/windows/tcpadapter.c b/port/windows/tcpadapter.c index 0eea6b9f6..ed53f61a2 100644 --- a/port/windows/tcpadapter.c +++ b/port/windows/tcpadapter.c @@ -22,9 +22,9 @@ #include "api/oc_session_events_internal.h" #include "api/oc_tcp_internal.h" #include "port/oc_assert.h" +#include "port/oc_connectivity_internal.h" #include "port/oc_fcntl_internal.h" #include "port/oc_log_internal.h" -#include "util/oc_memb.h" #include "port/oc_tcp_socket_internal.h" #include "ipcontext.h" #include "messaging/coap/coap_internal.h" @@ -33,6 +33,7 @@ #include "oc_endpoint.h" #include "oc_session_events.h" #include "tcpadapter.h" +#include "util/oc_memb.h" #include #include @@ -54,6 +55,7 @@ typedef struct tcp_session SOCKET sock; HANDLE sock_event; tcp_csm_state_t csm_state; + bool notify_session_end; } tcp_session_t; OC_LIST(session_list); @@ -139,8 +141,9 @@ get_interface_index(SOCKET sock) struct sockaddr_in6 *a = (struct sockaddr_in6 *)&iface->addr; struct sockaddr_in6 *b = (struct sockaddr_in6 *)&addr; if (memcmp(a->sin6_addr.s6_addr, b->sin6_addr.s6_addr, 16) == 0) { + long if_index = iface->if_index; free_network_addresses(ifaddr_list); - return iface->if_index; + return if_index; } } #ifdef OC_IPV4 @@ -148,8 +151,9 @@ get_interface_index(SOCKET sock) struct sockaddr_in *a = (struct sockaddr_in *)&iface->addr; struct sockaddr_in *b = (struct sockaddr_in *)&addr; if (a->sin_addr.s_addr == b->sin_addr.s_addr) { + long if_index = iface->if_index; free_network_addresses(ifaddr_list); - return iface->if_index; + return if_index; } } #endif /* OC_IPV4 */ @@ -161,7 +165,8 @@ get_interface_index(SOCKET sock) static void free_tcp_session_locked(tcp_session_t *session, oc_endpoint_t *endpoint, - SOCKET *sock, HANDLE *sock_event) + SOCKET *sock, HANDLE *sock_event, + bool *notify_session_end) { oc_tcp_adapter_mutex_lock(); oc_list_remove(session_list, session); @@ -169,6 +174,9 @@ free_tcp_session_locked(tcp_session_t *session, oc_endpoint_t *endpoint, sizeof(session->endpoint)); *sock = session->sock; *sock_event = session->sock_event; + if (notify_session_end != NULL) { + *notify_session_end = session->notify_session_end; + } oc_memb_free(&tcp_session_s, session); oc_tcp_adapter_mutex_unlock(); @@ -181,10 +189,12 @@ free_tcp_session(tcp_session_t *session) oc_endpoint_t endpoint; SOCKET sock; HANDLE sock_event; - free_tcp_session_locked(session, &endpoint, &sock, &sock_event); + bool notify_session_end; + free_tcp_session_locked(session, &endpoint, &sock, &sock_event, + ¬ify_session_end); WSACloseEvent(sock_event); closesocket(sock); - if (!oc_session_events_disconnect_is_ongoing()) { + if (!oc_session_events_disconnect_is_ongoing() && notify_session_end) { oc_session_end_event(&endpoint); } @@ -192,10 +202,11 @@ free_tcp_session(tcp_session_t *session) } static void -free_tcp_session_async_locked(tcp_session_t *session) +free_tcp_session_async_locked(tcp_session_t *session, bool notify_session_end) { oc_list_remove(session_list, session); oc_list_add(free_session_list_async, session); + session->notify_session_end = notify_session_end; if (!SetEvent(session->dev->tcp.signal_event)) { OC_ERR("could not trigger signal event (%ld)\n", GetLastError()); @@ -205,7 +216,7 @@ free_tcp_session_async_locked(tcp_session_t *session) static int add_new_session_locked(SOCKET sock, ip_context_t *dev, oc_endpoint_t *endpoint, - tcp_csm_state_t state) + uint32_t session_id, tcp_csm_state_t state) { HANDLE sock_event = WSACreateEvent(); if (WSAEventSelect(sock, sock_event, FD_READ | FD_CLOSE) == SOCKET_ERROR) { @@ -227,18 +238,23 @@ add_new_session_locked(SOCKET sock, ip_context_t *dev, oc_endpoint_t *endpoint, return SOCKET_ERROR; } + session->dev = dev; endpoint->interface_index = (unsigned)if_index; + if (session_id == 0) { + session_id = oc_tcp_get_new_session_id(); + } + endpoint->session_id = session_id; memcpy(&session->endpoint, endpoint, sizeof(oc_endpoint_t)); - session->dev = dev; session->endpoint.next = NULL; session->sock = sock; session->csm_state = state; session->sock_event = sock_event; + session->notify_session_end = true; oc_list_add(session_list, session); - if (!(endpoint->flags & SECURED)) { - oc_session_start_event(endpoint); + if ((session->endpoint.flags & SECURED) == 0) { + oc_session_start_event(&session->endpoint); } OC_DBG("recorded new TCP session"); @@ -276,7 +292,8 @@ accept_new_session(ip_context_t *dev, SOCKET fd, oc_endpoint_t *endpoint) } oc_tcp_adapter_mutex_lock(); - if (add_new_session_locked(new_socket, dev, endpoint, CSM_NONE) < 0) { + if (add_new_session_locked(new_socket, dev, endpoint, /*session_id*/ 0, + CSM_NONE) < 0) { oc_tcp_adapter_mutex_unlock(); OC_ERR("could not record new TCP session"); closesocket(new_socket); @@ -313,15 +330,36 @@ find_session_by_endpoint_locked(const oc_endpoint_t *endpoint) return session; } -void -oc_tcp_end_session(const oc_endpoint_t *endpoint) +static tcp_session_t * +find_session_by_id_locked(uint32_t session_id) +{ + tcp_session_t *session = oc_list_head(session_list); + while (session != NULL && session->endpoint.session_id != session_id) { + session = session->next; + } + + if (!session) { + OC_DBG("could not find ongoing TCP session for session id %d", session_id); + return NULL; + } + OC_DBG("found TCP session for session id %d", session_id); + return session; +} + +bool +oc_tcp_end_session(const oc_endpoint_t *endpoint, bool notify_session_end, + oc_endpoint_t *session_endpoint) { oc_tcp_adapter_mutex_lock(); tcp_session_t *session = find_session_by_endpoint_locked(endpoint); if (session) { - free_tcp_session_async_locked(session); + if (session_endpoint) { + memcpy(session_endpoint, &session->endpoint, sizeof(oc_endpoint_t)); + } + free_tcp_session_async_locked(session, notify_session_end); } oc_tcp_adapter_mutex_unlock(); + return session != NULL; } static SOCKET @@ -339,6 +377,7 @@ get_session_socket_locked(oc_endpoint_t *endpoint) static SOCKET initiate_new_session_locked(ip_context_t *dev, oc_endpoint_t *endpoint, + uint32_t session_id, const struct sockaddr_storage *receiver) { SOCKET sock = INVALID_SOCKET; @@ -362,7 +401,7 @@ initiate_new_session_locked(ip_context_t *dev, oc_endpoint_t *endpoint, OC_DBG("successfully initiated TCP connection"); - if (add_new_session_locked(sock, dev, endpoint, CSM_SENT) < 0) { + if (add_new_session_locked(sock, dev, endpoint, session_id, CSM_SENT) < 0) { OC_ERR("could not record new TCP session"); closesocket(sock); return INVALID_SOCKET; @@ -391,6 +430,7 @@ oc_tcp_send_buffer(ip_context_t *dev, oc_message_t *message, goto oc_tcp_send_buffer_done; } if ((send_sock = initiate_new_session_locked(dev, &message->endpoint, + message->endpoint.session_id, receiver)) == INVALID_SOCKET) { OC_ERR("could not initiate new TCP session"); goto oc_tcp_send_buffer_done; @@ -963,7 +1003,7 @@ oc_tcp_connectivity_shutdown(ip_context_t *dev) oc_endpoint_t endpoint; SOCKET sock; HANDLE sock_event; - free_tcp_session_locked(session, &endpoint, &sock, &sock_event); + free_tcp_session_locked(session, &endpoint, &sock, &sock_event, NULL); WSACloseEvent(sock_event); closesocket(sock); if (!oc_session_events_disconnect_is_ongoing()) { @@ -992,6 +1032,18 @@ oc_tcp_connection_state(const oc_endpoint_t *endpoint) return -1; } +int +oc_tcp_session_state(uint32_t session_id) +{ + oc_tcp_adapter_mutex_lock(); + tcp_session_t *session = find_session_by_id_locked(session_id); + oc_tcp_adapter_mutex_unlock(); + if (session != NULL) { + return OC_TCP_SOCKET_STATE_CONNECTED; + } + return -1; +} + tcp_csm_state_t oc_tcp_get_csm_state(const oc_endpoint_t *endpoint) { diff --git a/port/windows/tcpadapter.h b/port/windows/tcpadapter.h index 23be79cd5..742567222 100644 --- a/port/windows/tcpadapter.h +++ b/port/windows/tcpadapter.h @@ -33,7 +33,8 @@ void oc_tcp_connectivity_shutdown(ip_context_t *dev); int oc_tcp_send_buffer(ip_context_t *dev, oc_message_t *message, const struct sockaddr_storage *receiver); -void oc_tcp_end_session(const oc_endpoint_t *endpoint); +bool oc_tcp_end_session(const oc_endpoint_t *endpoint, bool notify_session_end, + oc_endpoint_t *session_endpoint); void oc_tcp_adapter_mutex_init(void); diff --git a/security/oc_tls.c b/security/oc_tls.c index 92949f3d8..58df3f2e8 100644 --- a/security/oc_tls.c +++ b/security/oc_tls.c @@ -462,7 +462,8 @@ tls_drop_endpoint_events(const oc_endpoint_t *endpoint) } static void -oc_tls_free_peer(oc_tls_peer_t *peer, bool inactivity_cb, bool from_reset) +oc_tls_free_peer(oc_tls_peer_t *peer, bool inactivity_cb, bool from_reset, + bool notify_session_end) { #if OC_DBG_IS_ENABLED // GCOVR_EXCL_START @@ -539,10 +540,10 @@ oc_tls_free_peer(oc_tls_peer_t *peer, bool inactivity_cb, bool from_reset) #ifdef OC_TCP if (endpoint.flags & TCP) { - oc_connectivity_end_session(&endpoint); - } else + oc_connectivity_end_session_v1(&endpoint, false, NULL); + } #endif /* OC_TCP */ - { + if (notify_session_end) { oc_handle_session(&endpoint, OC_SESSION_DISCONNECTED); } } @@ -569,14 +570,29 @@ oc_tls_peer_is_doc(const oc_endpoint_t *endpoint) } void -oc_tls_remove_peer(const oc_endpoint_t *endpoint) +oc_tls_remove_peer(const oc_endpoint_t *endpoint, bool notify_session_end) { - oc_tls_peer_t *peer = oc_tls_get_peer(endpoint); - if (peer != NULL) { - oc_tls_free_peer(peer, false, false); - } else { - tls_drop_endpoint_events(endpoint); + oc_endpoint_t ep_copy; + oc_endpoint_copy(&ep_copy, endpoint); + oc_tls_peer_t *peer = oc_tls_get_peer(&ep_copy); + if (peer == NULL) { + tls_drop_endpoint_events(&ep_copy); + return; } + do { + oc_tls_free_peer(peer, false, false, notify_session_end); +#ifdef OC_TCP + if ((ep_copy.flags & TCP) != 0 || ep_copy.session_id != 0) { + break; + } +#endif /* OC_TCP */ + peer = oc_tls_get_peer(&ep_copy); + } while (peer != NULL); +#ifdef OC_TCP + if ((ep_copy.flags & TCP) == 0 && ep_copy.session_id == 0) { + tls_drop_endpoint_events(&ep_copy); + } +#endif /* OC_TCP */ } static void @@ -587,7 +603,7 @@ oc_tls_close_peer(oc_tls_peer_t *peer, bool from_reset) if ((peer->endpoint.flags & TCP) == 0) { mbedtls_ssl_close_notify(&peer->ssl_ctx); } - oc_tls_free_peer(peer, false, from_reset); + oc_tls_free_peer(peer, false, from_reset, true); } void @@ -663,7 +679,7 @@ oc_dtls_inactive(void *data) mbedtls_ssl_close_notify(&peer->ssl_ctx); } OC_DBG("oc_tls: Removing inactive peer"); - oc_tls_free_peer(peer, true, false); + oc_tls_free_peer(peer, true, false, true); return OC_EVENT_DONE; } @@ -733,7 +749,7 @@ check_retry_timers(void) &peer->ssl_ctx, (const unsigned char *)&peer->endpoint.addr, sizeof(peer->endpoint.addr)) != 0) { TLS_LOG_MBEDTLS_ERROR("mbedtls_ssl_set_client_transport_id", ret); - oc_tls_free_peer(peer, false, false); + oc_tls_free_peer(peer, false, false, true); peer = next; continue; } @@ -741,7 +757,7 @@ check_retry_timers(void) if (ret < 0 && ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) { TLS_LOG_MBEDTLS_ERROR("mbedtls_ssl_handshake", ret); - oc_tls_free_peer(peer, false, false); + oc_tls_free_peer(peer, false, false, true); } } } @@ -2156,7 +2172,7 @@ oc_tls_add_new_peer(oc_tls_new_peer_params_t params) } if (oc_tls_peer_ssl_init(peer) != 0) { - oc_tls_free_peer(peer, false, false); + oc_tls_free_peer(peer, false, false, true); return NULL; } @@ -2222,7 +2238,7 @@ oc_tls_shutdown(void) { oc_tls_peer_t *p = oc_list_pop(g_tls_peers); while (p != NULL) { - oc_tls_free_peer(p, false, true); + oc_tls_free_peer(p, false, true, true); p = oc_list_pop(g_tls_peers); } #ifdef OC_PKI @@ -2285,9 +2301,17 @@ oc_tls_init_context(void) static void tls_close_connection(const oc_endpoint_t *endpoint, bool from_reset) { - oc_tls_peer_t *peer = oc_tls_get_peer(endpoint); - if (peer != NULL) { + oc_endpoint_t ep_copy; + oc_endpoint_copy(&ep_copy, endpoint); + oc_tls_peer_t *peer = oc_tls_get_peer(&ep_copy); + while (peer != NULL) { oc_tls_close_peer(peer, from_reset); +#ifdef OC_TCP + if ((ep_copy.flags & TCP) != 0 || ep_copy.session_id != 0) { + break; + } +#endif /* OC_TCP */ + peer = oc_tls_get_peer(&ep_copy); } } @@ -2542,7 +2566,7 @@ oc_tls_send_message_internal(oc_message_t *message) ? "ssl_write_tcp" : "mbedtls_ssl_write", ret); - oc_tls_free_peer(peer, false, false); + oc_tls_free_peer(peer, false, false, true); } else { length = message->length; } @@ -2595,7 +2619,7 @@ write_application_data(oc_tls_peer_t *peer) ? "ssl_write_tcp" : "mbedtls_ssl_write", ret); - oc_tls_free_peer(peer, false, false); + oc_tls_free_peer(peer, false, false, true); break; } message = (oc_message_t *)oc_list_pop(peer->send_q); @@ -2609,7 +2633,7 @@ oc_tls_handshake(oc_tls_peer_t *peer) if (ret < 0 && ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) { TLS_LOG_MBEDTLS_ERROR("mbedtls_ssl_handshake", ret); - oc_tls_free_peer(peer, false, false); + oc_tls_free_peer(peer, false, false, true); return; } if (ret == 0) { @@ -2634,7 +2658,7 @@ oc_tls_on_tcp_connect(const oc_endpoint_t *endpoint, int state, void *data) return; } OC_ERR("oc_tls_on_tcp_connect: ends with error state: %d", state); - oc_tls_free_peer(peer, false, false); + oc_tls_free_peer(peer, false, false, true); } #endif /* OC_HAS_FEATURE_TCP_ASYNC_CONNECT */ @@ -2683,17 +2707,27 @@ oc_tls_init_connection(oc_message_t *message) return; } -#ifdef OC_HAS_FEATURE_TCP_ASYNC_CONNECT +#ifdef OC_TCP if ((peer->endpoint.flags & TCP) != 0) { - int state = oc_tcp_connect(&peer->endpoint, oc_tls_on_tcp_connect, NULL); - if (state == OC_TCP_SOCKET_STATE_CONNECTED || - state == OC_TCP_SOCKET_ERROR_EXISTS_CONNECTED) { +#ifndef OC_HAS_FEATURE_TCP_ASYNC_CONNECT + if (peer->endpoint.session_id == 0) { + peer->endpoint.session_id = oc_tcp_get_new_session_id(); + } +#endif /* !OC_HAS_FEATURE_TCP_ASYNC_CONNECT */ + +#ifdef OC_HAS_FEATURE_TCP_ASYNC_CONNECT + oc_tcp_connect_result_t res = + oc_tcp_connect_to_endpoint(&peer->endpoint, oc_tls_on_tcp_connect, NULL); + if (res.state == OC_TCP_SOCKET_STATE_CONNECTED || + res.error == OC_TCP_SOCKET_ERROR_EXISTS_CONNECTED) { + peer->endpoint.session_id = res.session_id; oc_tls_handshake(peer); oc_message_unref(message); return; } - if (state == OC_TCP_SOCKET_STATE_CONNECTING || - state == OC_TCP_SOCKET_ERROR_EXISTS_CONNECTING) { + if (res.state == OC_TCP_SOCKET_STATE_CONNECTING || + res.error == OC_TCP_SOCKET_ERROR_EXISTS_CONNECTING) { + peer->endpoint.session_id = res.session_id; // just wait for connection to be established; oc_tls_handshake or // oc_tls_free_peer will be called from oc_tls_on_tcp_connect oc_message_unref(message); @@ -2701,12 +2735,13 @@ oc_tls_init_connection(oc_message_t *message) } OC_ERR( "oc_tls_init_connection: oc_tcp_connect returns unexpected state: %d", - state); - oc_tls_free_peer(peer, false, false); + res.state); + oc_tls_free_peer(peer, false, false, true); oc_message_unref(message); return; - } #endif /* OC_HAS_FEATURE_TCP_ASYNC_CONNECT */ + } +#endif /* OC_TCP */ oc_tls_handshake(peer); oc_message_unref(message); } @@ -2781,7 +2816,7 @@ tls_read_application_data_tcp(oc_tls_peer_t *peer) OC_ERR("oc_tls_tcp: total receive length(%ld) is bigger than max pdu " "size(%ld)", (long)total_length, (long)OC_PDU_SIZE); - oc_tls_free_peer(peer, false, false); + oc_tls_free_peer(peer, false, false, true); return; } want_read = total_length - peer->processed_recv_message->length; @@ -2809,7 +2844,7 @@ tls_read_application_data_tcp(oc_tls_peer_t *peer) mbedtls_ssl_close_notify(&peer->ssl_ctx); } TLS_LOG_MBEDTLS_ERROR("mbedtls_ssl_read", ret); - oc_tls_free_peer(peer, false, false); + oc_tls_free_peer(peer, false, false, true); return; } peer->processed_recv_message->length += ret; @@ -2847,7 +2882,7 @@ tls_handshake_step(oc_tls_peer_t *peer) &peer->ssl_ctx, (const unsigned char *)&peer->endpoint.addr, sizeof(peer->endpoint.addr)) != 0) { TLS_LOG_MBEDTLS_ERROR("mbedtls_ssl_set_client_transport_id", ret); - oc_tls_free_peer(peer, false, false); + oc_tls_free_peer(peer, false, false, true); return; } continue; @@ -2858,7 +2893,7 @@ tls_handshake_step(oc_tls_peer_t *peer) break; } TLS_LOG_MBEDTLS_ERROR("mbedtls_ssl_handshake_step", ret); - oc_tls_free_peer(peer, false, false); + oc_tls_free_peer(peer, false, false, true); return; } } while (peer->ssl_ctx.state != MBEDTLS_SSL_HANDSHAKE_OVER); @@ -2913,7 +2948,7 @@ tls_read_application_data_udp(oc_tls_peer_t *peer) mbedtls_ssl_close_notify(&peer->ssl_ctx); mbedtls_ssl_close_notify(&peer->ssl_ctx); } - oc_tls_free_peer(peer, false, false); + oc_tls_free_peer(peer, false, false, true); return; } @@ -3053,7 +3088,9 @@ close_all_tls_sessions_for_device_reset(size_t device) while (p != NULL) { oc_tls_peer_t *next = p->next; if (p->endpoint.device == device) { - tls_close_connection(&p->endpoint, true); + oc_endpoint_t endpoint; + oc_endpoint_copy(&endpoint, &p->endpoint); + tls_close_connection(&endpoint, true); } p = next; } diff --git a/security/oc_tls_internal.h b/security/oc_tls_internal.h index 527e89341..592f68c55 100644 --- a/security/oc_tls_internal.h +++ b/security/oc_tls_internal.h @@ -160,8 +160,9 @@ oc_tls_pki_verification_params_t oc_tls_peer_pki_default_verification_params( * @brief Remove and deallocate the peer for the endpoint. * * @param endpoint the endpoint + * @param notify_session_end send session end notification */ -void oc_tls_remove_peer(const oc_endpoint_t *endpoint); +void oc_tls_remove_peer(const oc_endpoint_t *endpoint, bool notify_session_end); /** * @brief Remove TLS peers matching filter. diff --git a/security/unittest/acltest.cpp b/security/unittest/acltest.cpp index 621be3b8d..b8f58c132 100644 --- a/security/unittest/acltest.cpp +++ b/security/unittest/acltest.cpp @@ -320,7 +320,7 @@ TEST_F(TestAcl, oc_sec_check_acl_FailInsecureDOC) resource.device = kDeviceID; EXPECT_FALSE(oc_sec_check_acl(OC_GET, &resource, &ep)); - oc_tls_remove_peer(&ep); + oc_tls_remove_peer(&ep, true); } #ifdef OC_HAS_FEATURE_RESOURCE_ACCESS_IN_RFOTM @@ -397,7 +397,7 @@ TEST_F(TestAcl, oc_sec_check_acl_DOCAccessToDCR) EXPECT_TRUE(oc_sec_check_acl(OC_GET, resource, &ep)); - oc_tls_remove_peer(&ep); + oc_tls_remove_peer(&ep, true); } TEST_F(TestAcl, oc_sec_check_acl_GETinRFOTM) @@ -643,7 +643,7 @@ TEST_F(TestAcl, oc_sec_check_acl_AccessToSVRBySubject) EXPECT_FALSE(oc_sec_check_acl(OC_FETCH, doxm, &ep)); oc_sec_acl_clear(kDeviceID, nullptr, nullptr); - oc_tls_remove_peer(&ep); + oc_tls_remove_peer(&ep, true); } TEST_F(TestAcl, oc_sec_check_acl_AccessToSVRByPSK) @@ -731,7 +731,7 @@ TEST_F(TestAcl, oc_sec_check_acl_AccessToSVRByPSK) oc_sec_acl_clear(kDeviceID, nullptr, nullptr); peer->ssl_ctx.session = nullptr; - oc_tls_remove_peer(&ep); + oc_tls_remove_peer(&ep, true); } #if defined(OC_DYNAMIC_ALLOCATION) && defined(OC_PKI) @@ -781,7 +781,7 @@ TEST_F(TestAcl, oc_sec_check_acl_AccessToSVRByOwnerRoleCred) ASSERT_NE(-1, credid); checkAccessToResource(doxm, &ep); - oc_tls_remove_peer(&ep); + oc_tls_remove_peer(&ep, true); } TEST_F(TestAcl, oc_sec_check_acl_AccessToSVRByNonOwnerRoleCred) @@ -839,7 +839,7 @@ TEST_F(TestAcl, oc_sec_check_acl_AccessToSVRByNonOwnerRoleCred) checkAccessToResource(doxm, &ep, false, true, true, false); oc_sec_acl_clear(kDeviceID, nullptr, nullptr); - oc_tls_remove_peer(&ep); + oc_tls_remove_peer(&ep, true); } #endif /* OC_DYNAMIC_ALLOCATION && OC_PKI */ diff --git a/security/unittest/rolestest.cpp b/security/unittest/rolestest.cpp index 50594fef0..bfbe8210d 100644 --- a/security/unittest/rolestest.cpp +++ b/security/unittest/rolestest.cpp @@ -79,7 +79,7 @@ class TestRolesWithServer : public testing::Test { void TearDown() override { for (auto &peer : peers_) { - oc_tls_remove_peer(&peer->endpoint); + oc_tls_remove_peer(&peer->endpoint, true); } peers_.clear(); diff --git a/security/unittest/tlstest.cpp b/security/unittest/tlstest.cpp index 70147d982..bd07c55a6 100644 --- a/security/unittest/tlstest.cpp +++ b/security/unittest/tlstest.cpp @@ -176,7 +176,7 @@ TEST_F(TestEventsWithServer, DropOutputMessages) oc_send_message(msg); EXPECT_LT(0, countInboundOrOutboundEvents()); - oc_tls_remove_peer(&ep); + oc_tls_remove_peer(&ep, true); ASSERT_EQ(0, countInboundOrOutboundEvents()); } @@ -208,7 +208,7 @@ TEST_F(TestEventsWithServer, DropOutputMessagesTCP) oc_send_message(msg); EXPECT_LT(0, countInboundOrOutboundEvents()); - oc_tls_remove_peer(&ep); + oc_tls_remove_peer(&ep, true); ASSERT_EQ(0, countInboundOrOutboundEvents()); } #endif /* OC_TCP */ diff --git a/swig/swig_interfaces/oc_connectivity.i b/swig/swig_interfaces/oc_connectivity.i index 91d90e625..f55bc60a7 100644 --- a/swig/swig_interfaces/oc_connectivity.i +++ b/swig/swig_interfaces/oc_connectivity.i @@ -58,6 +58,7 @@ void jni_connectivity_shutdown(size_t device) %} %ignore oc_send_discovery_request; %ignore oc_connectivity_end_session; +%ignore oc_connectivity_end_session_v1; %ignore oc_dns_lookup; %ignore oc_connectivity_get_endpoints; %ignore handle_network_interface_event_callback;