From cb20c482b2bb857a2f06c342ecb8c8c6d5f387ce Mon Sep 17 00:00:00 2001 From: Jon Shallow Date: Thu, 23 May 2024 08:33:22 +0100 Subject: [PATCH] locking: Simplify maintenance / debugging /documentation Update the Public API equivalent of the libcoap functions that need to be called when locked with a name suffix of _lkd. Move matching Public API functions out of coap_threadsafe.c to be coded just ahead of the newly renamed _lkd function. Properly define the _lkd function in the appropriate _internal.h file for documentation, removing the #defines from coap_threadsafe_internal.h. Tag all the Public API functions that have a _lkd function with COAP_API. COAP_API can then be defined as to what should be done for that function. Check libcoap library does not call the original Public API function when it should be calling the _lkd function by marking the Public API not _lkd functions as deprecated during the libcoap library build. [Done by the new COAP_API being defined as __attribute__((deprecated)).] Work in progress for all the functions that need to be multi-thread safe. --- examples/lwip/client-coap.c | 11 - examples/lwip/server-coap.c | 11 - include/coap3/coap_block.h | 6 +- include/coap3/coap_block_internal.h | 39 +++ include/coap3/coap_layers_internal.h | 4 +- include/coap3/coap_mutex_internal.h | 235 ----------------- include/coap3/coap_net.h | 42 +-- include/coap3/coap_net_internal.h | 174 +++++++++++++ include/coap3/coap_oscore_internal.h | 6 +- include/coap3/coap_pdu.h | 10 +- include/coap3/coap_pdu_internal.h | 21 ++ include/coap3/coap_session.h | 15 +- include/coap3/coap_session_internal.h | 75 +++++- include/coap3/coap_subscribe.h | 24 +- include/coap3/coap_subscribe_internal.h | 68 +++++ include/coap3/coap_threadsafe_internal.h | 309 +++++++++++++++++------ man/coap_locking.txt.in | 37 ++- src/coap_async.c | 8 +- src/coap_block.c | 95 ++++--- src/coap_dtls.c | 4 +- src/coap_gnutls.c | 16 +- src/coap_io.c | 10 +- src/coap_io_lwip.c | 10 +- src/coap_mbedtls.c | 18 +- src/coap_net.c | 220 ++++++++++++---- src/coap_openssl.c | 18 +- src/coap_oscore.c | 18 +- src/coap_pdu.c | 33 ++- src/coap_resource.c | 15 +- src/coap_session.c | 113 +++++++-- src/coap_subscribe.c | 67 ++++- src/coap_threadsafe.c | 294 +-------------------- src/coap_tinydtls.c | 8 +- src/coap_wolfssl.c | 18 +- src/coap_ws.c | 10 +- src/oscore/oscore_context.c | 4 +- tests/test_common.h.in | 3 - 37 files changed, 1149 insertions(+), 920 deletions(-) diff --git a/examples/lwip/client-coap.c b/examples/lwip/client-coap.c index 947bb35535..0429cadcf6 100644 --- a/examples/lwip/client-coap.c +++ b/examples/lwip/client-coap.c @@ -12,17 +12,6 @@ #include "coap_config.h" -#if COAP_THREAD_SAFE -/* - * Unfortunately, this needs to be set so that locking mapping of coap_ - * functions does not take place in this file. coap.h includes coap_mem.h which - * includes lwip headers (lwippools.h) which includes coap_internal.h which - * includes coap_threadsafe_internal.h which does the mapping unless - * COAP_THREAD_IGNORE_LOCKED_MAPPING is set. - */ -#define COAP_THREAD_IGNORE_LOCKED_MAPPING -#endif - #include #include #include diff --git a/examples/lwip/server-coap.c b/examples/lwip/server-coap.c index e26d05cf4b..d2aefd4c5e 100644 --- a/examples/lwip/server-coap.c +++ b/examples/lwip/server-coap.c @@ -12,17 +12,6 @@ #include "coap_config.h" -#if COAP_THREAD_SAFE -/* - * Unfortunately, this needs to be set so that locking mapping of coap_ - * functions does not take place in this file. coap.h includes coap_mem.h which - * includes lwip headers (lwippools.h) which includes coap_internal.h which - * includes coap_threadsafe_internal.h which does the mapping unless - * COAP_THREAD_IGNORE_LOCKED_MAPPING is set. - */ -#define COAP_THREAD_IGNORE_LOCKED_MAPPING -#endif - #include #include "server-coap.h" diff --git a/include/coap3/coap_block.h b/include/coap3/coap_block.h index 1c1fb1197d..fbf64c3b03 100644 --- a/include/coap3/coap_block.h +++ b/include/coap3/coap_block.h @@ -423,8 +423,8 @@ COAP_API int coap_add_data_large_response(coap_resource_t *resource, * @param context The coap_context_t object. * @param block_mode Zero or more COAP_BLOCK_ or'd options */ -void coap_context_set_block_mode(coap_context_t *context, - uint32_t block_mode); +COAP_API void coap_context_set_block_mode(coap_context_t *context, + uint32_t block_mode); /** * Set the context level maximum block size that the server supports when sending @@ -440,7 +440,7 @@ void coap_context_set_block_mode(coap_context_t *context, * @param max_block_size The maximum block size a server supports. Can be 0 * (reset), or must be 16, 32, 64, 128, 256, 512 or 1024. */ -int coap_context_set_max_block_size(coap_context_t *context, size_t max_block_size); +COAP_API int coap_context_set_max_block_size(coap_context_t *context, size_t max_block_size); /**@}*/ diff --git a/include/coap3/coap_block_internal.h b/include/coap3/coap_block_internal.h index c51efdcbbe..41abb6d653 100644 --- a/include/coap3/coap_block_internal.h +++ b/include/coap3/coap_block_internal.h @@ -419,6 +419,45 @@ void coap_check_code_lg_xmit(const coap_session_t *session, const coap_resource_t *resource, const coap_string_t *query); +/** + * Set the context level CoAP block handling bits for handling RFC7959. + * These bits flow down to a session when a session is created and if the peer + * does not support something, an appropriate bit may get disabled in the + * session block_mode. + * The session block_mode then flows down into coap_crcv_t or coap_srcv_t where + * again an appropriate bit may get disabled. + * + * Note: This function must be called before the session is set up. + * + * Note: COAP_BLOCK_USE_LIBCOAP must be set if libcoap is to do all the + * block tracking and requesting, otherwise the application will have to do + * all of this work (the default if coap_context_set_block_mode() is not + * called). + * + * @param context The coap_context_t object. + * @param block_mode Zero or more COAP_BLOCK_ or'd options + */ +void coap_context_set_block_mode_lkd(coap_context_t *context, + uint32_t block_mode); + +/** + * Set the context level maximum block size that the server supports when sending + * or receiving packets with Block1 or Block2 options. + * This maximum block size flows down to a session when a session is created. + * + * Note: This function must be called before the session is set up. + * + * Note: This function must be called before the session is set up. + * + * Note: COAP_BLOCK_USE_LIBCOAP must be set using coap_context_set_block_mode() + * if libcoap is to do this work. + * + * @param context The coap_context_t object. + * @param max_block_size The maximum block size a server supports. Can be 0 + * (reset), or must be 16, 32, 64, 128, 256, 512 or 1024. + */ +int coap_context_set_max_block_size_lkd(coap_context_t *context, size_t max_block_size); + #if COAP_CLIENT_SUPPORT /** * Associates given data with the @p pdu that is passed as second parameter. diff --git a/include/coap3/coap_layers_internal.h b/include/coap3/coap_layers_internal.h index 74ddc4f0aa..a90b1f882c 100644 --- a/include/coap3/coap_layers_internal.h +++ b/include/coap3/coap_layers_internal.h @@ -84,8 +84,8 @@ typedef ssize_t (*coap_layer_write_t)(coap_session_t *session, * session->lfunc[_this_layer_].l_establish(session) * (or done at any point when layer is established). * If the establishment of a layer fails, then - * coap_session_disconnected(session, COAP_NACK_xxx_LAYER_FAILED) must be - * called. + * coap_session_disconnected_lkd(session, COAP_NACK_xxx_LAYER_FAILED) must + * be called. * * @param session Session being established */ diff --git a/include/coap3/coap_mutex_internal.h b/include/coap3/coap_mutex_internal.h index aaca90cf6e..ec91f6c1b8 100644 --- a/include/coap3/coap_mutex_internal.h +++ b/include/coap3/coap_mutex_internal.h @@ -161,239 +161,4 @@ extern coap_mutex_t m_persist_add; #endif /* COAP_CONSTRAINED_STACK */ -/* - * Support thread safe access into libcoap - * - * Locking at different component levels (i.e context and session) is - * problematic in that coap_process_io() needs to lock the context as - * it scans for all the sessions and then could lock the session being - * processed as well - but context needs to remain locked as a list is - * being scanned. - * - * Then if the session process needs to update context ( e.g. delayqueue), - * context needs to be locked. So, if coap_send() is done on a session, - * it has to be locked, but a retransmission of a PDU by coap_process_io() - * has the context already locked. - * - * So the initial support for thread safe is done at the context level. - * - * New model, simplifying debugging and better documentation. - * - * Any public API call needs to potentially lock context, as there may be - * multiple contexts. If a public API needs thread safe protection, the - * coap_X() function locks the context lock, calls the coap_X_lkd() function - * that does all the work and on return unlocks the context before returning - * to the caller of coap_X(). - * - * Any internal libcoap calls that are to the public API coap_X() must call - * coap_X_lkd() if the calling code is already locked. - * - * Old, equivalent model - * - * Any public API call needs to potentially lock context, as there may be - * multiple contexts. If a public API needs thread safe protection, a - * locking wrapper for coap_X() is added to src/coap_threadsafe.c which then - * calls the coap_X_locked() function of coap_X() having locked context. - * - * Then an entry is added to include/coap3/coap_threadsafe_internal.h to map - * all the coap_X() definitions and calls within the libcoap code to - * coap_X_locked() (with the exception of src/coap_threadsafe.c). - * - * A second entry is added to include/coap3/coap_threadsafe_internal.h which - * defines the coap_X_locked() function header. - * - * Any call-back into app space must be done by using the coap_lock_callback() - * (or coap_lock_callback_ret()) wrapper. - * - * Note: - * libcoap may call a handler, which may in turn call into libcoap, which may - * then call a handler. context will remain locked thoughout this process. - * - * Any wait on select() or equivalent when a thread is waiting on an event - * must be preceded by unlock context, and then context re-locked after - * return; - * - * To check for recursive deadlocks, COAP_THREAD_RECURSIVE_CHECK needs to be - * defined. - * - * If thread safe is not enabled, then coap_threadsafe.c and - * coap_threadsafe_internal.h do nothing. - */ -#if COAP_THREAD_SAFE -# if COAP_THREAD_RECURSIVE_CHECK - -/* - * Locking, with deadlock detection - */ -typedef struct coap_lock_t { - coap_mutex_t mutex; - coap_thread_pid_t pid; - coap_thread_pid_t freeing_pid; - const char *lock_file; - unsigned int lock_line; - unsigned int unlock_line; - const char *unlock_file; - const char *callback_file; - unsigned int callback_line; - unsigned int being_freed; - unsigned int in_callback; - unsigned int lock_count; -} coap_lock_t; - -void coap_lock_unlock_func(coap_lock_t *lock, const char *file, int line); -int coap_lock_lock_func(coap_lock_t *lock, const char *file, int line); - -#define coap_lock_lock(s,failed) do { \ - assert(s); \ - if (!coap_lock_lock_func(&(s)->lock, __FILE__, __LINE__)) { \ - failed; \ - } \ - } while (0) - -#define coap_lock_unlock(s) do { \ - assert(s); \ - coap_lock_unlock_func(&(s)->lock, __FILE__, __LINE__); \ - } while (0) - -#define coap_lock_callback(s,func) do { \ - coap_lock_check_locked(s); \ - (s)->lock.in_callback++; \ - (s)->lock.callback_file = __FILE__; \ - (s)->lock.callback_line = __LINE__; \ - func; \ - (s)->lock.in_callback--; \ - } while (0) - -#define coap_lock_callback_ret(r,s,func) do { \ - coap_lock_check_locked(s); \ - (s)->lock.in_callback++; \ - (s)->lock.callback_file = __FILE__; \ - (s)->lock.callback_line = __LINE__; \ - r = func; \ - (s)->lock.in_callback--; \ - } while (0) - -#define coap_lock_callback_release(s,func,fail) do { \ - coap_lock_check_locked(s); \ - coap_lock_unlock(s); \ - func; \ - coap_lock_lock(s,fail); \ - } while (0) - -#define coap_lock_callback_ret_release(r,s,func,fail) do { \ - coap_lock_check_locked(s); \ - coap_lock_unlock(s); \ - r = func; \ - coap_lock_lock(s,fail); \ - } while (0) - -# else /* ! COAP_THREAD_RECURSIVE_CHECK */ - -/* - * Locking, but no deadlock detection - */ -typedef struct coap_lock_t { - coap_mutex_t mutex; - coap_thread_pid_t pid; - coap_thread_pid_t freeing_pid; - uint32_t being_freed; - uint32_t in_callback; - volatile uint32_t lock_count; -} coap_lock_t; - -void coap_lock_unlock_func(coap_lock_t *lock); -int coap_lock_lock_func(coap_lock_t *lock); - -#define coap_lock_lock(s,failed) do { \ - assert(s); \ - if (!coap_lock_lock_func(&(s)->lock)) { \ - failed; \ - } \ - } while (0) - -#define coap_lock_unlock(s) do { \ - assert(s); \ - coap_lock_unlock_func(&(s)->lock); \ - } while (0) - -#define coap_lock_callback(s,func) do { \ - coap_lock_check_locked(s); \ - (s)->lock.in_callback++; \ - func; \ - (s)->lock.in_callback--; \ - } while (0) - -#define coap_lock_callback_ret(r,s,func) do { \ - coap_lock_check_locked(s); \ - (s)->lock.in_callback++; \ - r = func; \ - (s)->lock.in_callback--; \ - } while (0) - -#define coap_lock_callback_release(s,func,fail) do { \ - coap_lock_check_locked(s); \ - coap_lock_unlock(s); \ - func; \ - coap_lock_lock(s,fail); \ - } while (0) - -#define coap_lock_callback_ret_release(r,s,func,fail) do { \ - coap_lock_check_locked(s); \ - coap_lock_unlock(s); \ - r = func; \ - coap_lock_lock(s,fail); \ - } while (0) - -# endif /* ! COAP_THREAD_RECURSIVE_CHECK */ - -#define coap_lock_init(s) do { \ - assert(s); \ - memset(&((s)->lock), 0, sizeof((s)->lock)); \ - coap_mutex_init(&(s)->lock.mutex); \ - } while (0) - -#define coap_lock_being_freed(s,failed) do { \ - coap_lock_lock(s,failed); \ - (s)->lock.being_freed = 1; \ - (s)->lock.freeing_pid = coap_thread_pid; \ - coap_lock_unlock(s); \ - } while (0) - -#define coap_lock_check_locked(s) do { \ - assert((s) && \ - coap_thread_pid == ((s)->lock.being_freed ? (s)->lock.freeing_pid : \ - (s)->lock.pid)); \ - } while (0) - -#define coap_lock_invert(s,func,f) do { \ - coap_lock_check_locked(s); \ - if (!(s)->lock.being_freed) { \ - coap_lock_unlock(s); \ - func; \ - coap_lock_lock(s,f); \ - } else { \ - func; \ - } \ - } while (0) - -#else /* ! COAP_THREAD_SAFE */ - -/* - * No locking - single thread - */ -typedef coap_mutex_t coap_lock_t; - -#define coap_lock_lock(s,failed) -#define coap_lock_unlock(s) -#define coap_lock_init(s) -#define coap_lock_being_freed(s,failed) -#define coap_lock_check_locked(s) {} -#define coap_lock_callback(s,func) func -#define coap_lock_callback_ret(r,s,func) ret = func -#define coap_lock_callback_release(s,func,fail) func -#define coap_lock_callback_ret_release(r,s,func,fail) ret = func -#define coap_lock_invert(s,func,f) func - -#endif /* ! COAP_THREAD_SAFE */ - #endif /* COAP_MUTEX_INTERNAL_H_ */ diff --git a/include/coap3/coap_net.h b/include/coap3/coap_net.h index 29ca4d2aca..ebb650aa8e 100644 --- a/include/coap3/coap_net.h +++ b/include/coap3/coap_net.h @@ -149,7 +149,7 @@ void coap_register_pong_handler(coap_context_t *context, * @param ctx The context to use. * @param type The option type to register. */ -void coap_register_option(coap_context_t *ctx, uint16_t type); +COAP_API void coap_register_option(coap_context_t *ctx, uint16_t type); /** * Creates a new coap_context_t object that will hold the CoAP stack status. @@ -170,8 +170,8 @@ coap_context_t *coap_new_context(const coap_address_t *listen_addr); * * @return @c 1 if successful, else @c 0. */ -int coap_context_set_psk(coap_context_t *context, const char *hint, - const uint8_t *key, size_t key_len); +COAP_API int coap_context_set_psk(coap_context_t *context, const char *hint, + const uint8_t *key, size_t key_len); /** * Set the context's default PSK hint and/or key for a server. @@ -182,8 +182,8 @@ int coap_context_set_psk(coap_context_t *context, const char *hint, * * @return @c 1 if successful, else @c 0. */ -int coap_context_set_psk2(coap_context_t *context, - coap_dtls_spsk_t *setup_data); +COAP_API int coap_context_set_psk2(coap_context_t *context, + coap_dtls_spsk_t *setup_data); /** * Set the context's default PKI information for a server. @@ -194,8 +194,8 @@ int coap_context_set_psk2(coap_context_t *context, * * @return @c 1 if successful, else @c 0. */ -int coap_context_set_pki(coap_context_t *context, - const coap_dtls_pki_t *setup_data); +COAP_API int coap_context_set_pki(coap_context_t *context, + const coap_dtls_pki_t *setup_data); /** * Set the context's default Root CA information for a client or server. @@ -208,9 +208,9 @@ int coap_context_set_pki(coap_context_t *context, * * @return @c 1 if successful, else @c 0. */ -int coap_context_set_pki_root_cas(coap_context_t *context, - const char *ca_file, - const char *ca_dir); +COAP_API int coap_context_set_pki_root_cas(coap_context_t *context, + const char *ca_file, + const char *ca_dir); /** * Set the context keepalive timer for sessions. @@ -458,10 +458,10 @@ coap_pdu_t *coap_new_error_response(const coap_pdu_t *request, * @return The message id if the message was sent, or @c * COAP_INVALID_MID otherwise. */ -coap_mid_t coap_send_error(coap_session_t *session, - const coap_pdu_t *request, - coap_pdu_code_t code, - coap_opt_filter_t *opts); +COAP_API coap_mid_t coap_send_error(coap_session_t *session, + const coap_pdu_t *request, + coap_pdu_code_t code, + coap_opt_filter_t *opts); /** * Helper function to create and send a message with @p type (usually ACK or @@ -474,8 +474,8 @@ coap_mid_t coap_send_error(coap_session_t *session, * @return message id on success or @c COAP_INVALID_MID * otherwise. */ -coap_mid_t coap_send_message_type(coap_session_t *session, const coap_pdu_t *request, - coap_pdu_type_t type); +COAP_API coap_mid_t coap_send_message_type(coap_session_t *session, const coap_pdu_t *request, + coap_pdu_type_t type); /** * Sends an ACK message with code @c 0 for the specified @p request to @p dst. @@ -488,7 +488,7 @@ coap_mid_t coap_send_message_type(coap_session_t *session, const coap_pdu_t *req * @return The message id if ACK was sent or @c * COAP_INVALID_MID on error. */ -coap_mid_t coap_send_ack(coap_session_t *session, const coap_pdu_t *request); +COAP_API coap_mid_t coap_send_ack(coap_session_t *session, const coap_pdu_t *request); /** * Sends an RST message with code @c 0 for the specified @p request to @p dst. @@ -501,7 +501,7 @@ coap_mid_t coap_send_ack(coap_session_t *session, const coap_pdu_t *request); * @return The message id if RST was sent or @c * COAP_INVALID_MID on error. */ -coap_mid_t coap_send_rst(coap_session_t *session, const coap_pdu_t *request); +COAP_API coap_mid_t coap_send_rst(coap_session_t *session, const coap_pdu_t *request); /** * Sends a CoAP message to given peer. The memory that is @@ -514,7 +514,7 @@ coap_mid_t coap_send_rst(coap_session_t *session, const coap_pdu_t *request); * @return The message id of the sent message or @c * COAP_INVALID_MID on error. */ -coap_mid_t coap_send(coap_session_t *session, coap_pdu_t *pdu); +COAP_API coap_mid_t coap_send(coap_session_t *session, coap_pdu_t *pdu); #define coap_send_large(session, pdu) coap_send(session, pdu) @@ -560,8 +560,8 @@ void coap_ticks(coap_tick_t *); * * @return 0 on success, -1 on error */ -int coap_join_mcast_group_intf(coap_context_t *ctx, const char *groupname, - const char *ifname); +COAP_API int coap_join_mcast_group_intf(coap_context_t *ctx, const char *groupname, + const char *ifname); #define coap_join_mcast_group(ctx, groupname) \ (coap_join_mcast_group_intf(ctx, groupname, NULL)) diff --git a/include/coap3/coap_net_internal.h b/include/coap3/coap_net_internal.h index 24b95b6b68..0c0b28547f 100644 --- a/include/coap3/coap_net_internal.h +++ b/include/coap3/coap_net_internal.h @@ -20,6 +20,7 @@ #include "coap_internal.h" #include "coap_subscribe.h" +#include "coap_threadsafe_internal.h" /** * @ingroup internal_api @@ -501,6 +502,96 @@ int coap_handle_event_lkd(coap_context_t *context, */ int coap_can_exit_lkd(coap_context_t *context); +/** + * Function interface for joining a multicast group for listening for the + * currently defined endpoints that are UDP. + * + * Note: This function must be called in the locked state. + * + * @param ctx The current context. + * @param groupname The name of the group that is to be joined for listening. + * @param ifname Network interface to join the group on, or NULL if first + * appropriate interface is to be chosen by the O/S. + * + * @return 0 on success, -1 on error + */ +int coap_join_mcast_group_intf_lkd(coap_context_t *ctx, const char *groupname, + const char *ifname); + +/** + * Registers the option type @p type with the given context object @p ctx. + * + * Note: This function must be called in the locked state. + * + * @param ctx The context to use. + * @param type The option type to register. + */ +void coap_register_option_lkd(coap_context_t *ctx, uint16_t type); + +/** + * Set the context's default PKI information for a server. + * + * Note: This function must be called in the locked state. + * + * @param context The current coap_context_t object. + * @param setup_data If NULL, PKI authentication will fail. Certificate + * information required. + * + * @return @c 1 if successful, else @c 0. + */ +int coap_context_set_pki_lkd(coap_context_t *context, + const coap_dtls_pki_t *setup_data); + +/** + * Set the context's default Root CA information for a client or server. + * + * Note: This function must be called in the locked state. + * + * @param context The current coap_context_t object. + * @param ca_file If not NULL, is the full path name of a PEM encoded + * file containing all the Root CAs to be used. + * @param ca_dir If not NULL, points to a directory containing PEM + * encoded files containing all the Root CAs to be used. + * + * @return @c 1 if successful, else @c 0. + */ +int coap_context_set_pki_root_cas_lkd(coap_context_t *context, + const char *ca_file, + const char *ca_dir); + +/** + * Set the context's default PSK hint and/or key for a server. + * + * @deprecated Use coap_context_set_psk2() instead. + * + * Note: This function must be called in the locked state. + * + * @param context The current coap_context_t object. + * @param hint The default PSK server hint sent to a client. If NULL, PSK + * authentication is disabled. Empty string is a valid hint. + * @param key The default PSK key. If NULL, PSK authentication will fail. + * @param key_len The default PSK key's length. If @p 0, PSK authentication will + * fail. + * + * @return @c 1 if successful, else @c 0. + */ +int coap_context_set_psk_lkd(coap_context_t *context, const char *hint, + const uint8_t *key, size_t key_len); + +/** + * Set the context's default PSK hint and/or key for a server. + * + * Note: This function must be called in the locked state. + * + * @param context The current coap_context_t object. + * @param setup_data If NULL, PSK authentication will fail. PSK + * information required. + * + * @return @c 1 if successful, else @c 0. + */ +int coap_context_set_psk2_lkd(coap_context_t *context, + coap_dtls_spsk_t *setup_data); + /** @} */ /** @@ -686,6 +777,89 @@ int coap_io_process_with_fds_lkd(coap_context_t *ctx, uint32_t timeout_ms, fd_set *exceptfds); #endif /* ! RIOT_VERSION && ! WITH_CONTIKI */ +/** +* Sends a CoAP message to given peer. The memory that is +* allocated for the pdu will be released by coap_send_lkd(). +* The caller must not use or delete the pdu after calling coap_send_lkd(). + * + * Note: This function must be called in the locked state. +* +* @param session The CoAP session. +* @param pdu The CoAP PDU to send. +* +* @return The message id of the sent message or @c +* COAP_INVALID_MID on error. +*/ +coap_mid_t coap_send_lkd(coap_session_t *session, coap_pdu_t *pdu); + +/** + * Sends an error response with code @p code for request @p request to @p dst. + * @p opts will be passed to coap_new_error_response() to copy marked options + * from the request. This function returns the message id if the message was + * sent, or @c COAP_INVALID_MID otherwise. + * + * Note: This function must be called in the locked state. + * + * @param session The CoAP session. + * @param request The original request to respond to. + * @param code The response code. + * @param opts A filter that specifies the options to copy from the + * @p request. + * + * @return The message id if the message was sent, or @c + * COAP_INVALID_MID otherwise. + */ +coap_mid_t coap_send_error_lkd(coap_session_t *session, + const coap_pdu_t *request, + coap_pdu_code_t code, + coap_opt_filter_t *opts); + +/** + * Helper function to create and send a message with @p type (usually ACK or + * RST). This function returns @c COAP_INVALID_MID when the message was not + * sent, a valid transaction id otherwise. + * + * Note: This function must be called in the locked state. + * + * @param session The CoAP session. + * @param request The request that should be responded to. + * @param type Which type to set. + * @return message id on success or @c COAP_INVALID_MID + * otherwise. + */ +coap_mid_t coap_send_message_type_lkd(coap_session_t *session, const coap_pdu_t *request, + coap_pdu_type_t type); + +/** + * Sends an ACK message with code @c 0 for the specified @p request to @p dst. + * This function returns the corresponding message id if the message was + * sent or @c COAP_INVALID_MID on error. + * + * Note: This function must be called in the locked state. + * + * @param session The CoAP session. + * @param request The request to be acknowledged. + * + * @return The message id if ACK was sent or @c + * COAP_INVALID_MID on error. + */ +coap_mid_t coap_send_ack_lkd(coap_session_t *session, const coap_pdu_t *request); + +/** + * Sends an RST message with code @c 0 for the specified @p request to @p dst. + * This function returns the corresponding message id if the message was + * sent or @c COAP_INVALID_MID on error. + * + * Note: This function must be called in the locked state. + * + * @param session The CoAP session. + * @param request The request to be reset. + * + * @return The message id if RST was sent or @c + * COAP_INVALID_MID on error. + */ +coap_mid_t coap_send_rst_lkd(coap_session_t *session, const coap_pdu_t *request); + /**@}*/ extern int coap_started; diff --git a/include/coap3/coap_oscore_internal.h b/include/coap3/coap_oscore_internal.h index 7762e6f491..96e64ff4d0 100644 --- a/include/coap3/coap_oscore_internal.h +++ b/include/coap3/coap_oscore_internal.h @@ -211,7 +211,7 @@ int coap_delete_oscore_recipient_lkd(coap_context_t *context, * @param oscore_conf OSCORE configuration information. This structure is * freed off by this call. * - * @return A new CoAP session or NULL if failed. Call coap_session_release() + * @return A new CoAP session or NULL if failed. Call coap_session_release_lkd() * to free. */ coap_session_t *coap_new_client_session_oscore_lkd(coap_context_t *ctx, @@ -238,7 +238,7 @@ coap_session_t *coap_new_client_session_oscore_lkd(coap_context_t *ctx, * @param oscore_conf OSCORE configuration information. This structure is * freed off by this call. * - * @return A new CoAP session or NULL if failed. Call coap_session_release() + * @return A new CoAP session or NULL if failed. Call coap_session_release_lkd() * to free. */ coap_session_t *coap_new_client_session_oscore_pki_lkd(coap_context_t *ctx, @@ -266,7 +266,7 @@ coap_session_t *coap_new_client_session_oscore_pki_lkd(coap_context_t *ctx, * @param oscore_conf OSCORE configuration information. This structure is * freed off by this call. * - * @return A new CoAP session or NULL if failed. Call coap_session_release() + * @return A new CoAP session or NULL if failed. Call coap_session_release_lkd() * to free. */ coap_session_t *coap_new_client_session_oscore_psk_lkd(coap_context_t *ctx, diff --git a/include/coap3/coap_pdu.h b/include/coap3/coap_pdu.h index f72d253059..e51345d423 100644 --- a/include/coap3/coap_pdu.h +++ b/include/coap3/coap_pdu.h @@ -422,11 +422,11 @@ void coap_delete_pdu(coap_pdu_t *pdu); * * @return The duplicated PDU or @c NULL if failure. */ -coap_pdu_t *coap_pdu_duplicate(const coap_pdu_t *old_pdu, - coap_session_t *session, - size_t token_length, - const uint8_t *token, - coap_opt_filter_t *drop_options); +COAP_API coap_pdu_t *coap_pdu_duplicate(const coap_pdu_t *old_pdu, + coap_session_t *session, + size_t token_length, + const uint8_t *token, + coap_opt_filter_t *drop_options); /** * Parses @p data into the CoAP PDU structure given in @p result. diff --git a/include/coap3/coap_pdu_internal.h b/include/coap3/coap_pdu_internal.h index 5a4c130f6c..aabc362a8b 100644 --- a/include/coap3/coap_pdu_internal.h +++ b/include/coap3/coap_pdu_internal.h @@ -371,6 +371,27 @@ int coap_option_check_repeatable(coap_option_num_t number); coap_pdu_t *coap_new_pdu_lkd(coap_pdu_type_t type, coap_pdu_code_t code, coap_session_t *session); +/** + * Duplicate an existing PDU. Specific options can be ignored and not copied + * across. The PDU data payload is not copied across. + * + * Note: This function must be called in the locked state. + * + * @param old_pdu The PDU to duplicate + * @param session The session that will be using this PDU. + * @param token_length The length of the token to use in this duplicated PDU. + * @param token The token to use in this duplicated PDU. + * @param drop_options A list of options not to copy into the duplicated PDU. + * If @c NULL, then all options are copied across. + * + * @return The duplicated PDU or @c NULL if failure. + */ +coap_pdu_t *coap_pdu_duplicate_lkd(const coap_pdu_t *old_pdu, + coap_session_t *session, + size_t token_length, + const uint8_t *token, + coap_opt_filter_t *drop_options); + /** @} */ #endif /* COAP_COAP_PDU_INTERNAL_H_ */ diff --git a/include/coap3/coap_session.h b/include/coap3/coap_session.h index e09e479aa7..2573c000cc 100644 --- a/include/coap3/coap_session.h +++ b/include/coap3/coap_session.h @@ -66,7 +66,7 @@ typedef enum coap_session_state_t { * @param session The CoAP session. * @return same as session */ -coap_session_t *coap_session_reference(coap_session_t *session); +COAP_API coap_session_t *coap_session_reference(coap_session_t *session); /** * Decrement reference counter on a session. @@ -75,7 +75,7 @@ coap_session_t *coap_session_reference(coap_session_t *session); * * @param session The CoAP session. */ -void coap_session_release(coap_session_t *session); +COAP_API void coap_session_release(coap_session_t *session); /** * Notify session that it has failed. This cleans up any outstanding / queued @@ -84,8 +84,8 @@ void coap_session_release(coap_session_t *session); * @param session The CoAP session. * @param reason The reason why the session was disconnected. */ -void coap_session_disconnected(coap_session_t *session, - coap_nack_reason_t reason); +COAP_API void coap_session_disconnected(coap_session_t *session, + coap_nack_reason_t reason); /** * Stores @p data with the given session. This function overwrites any value @@ -238,7 +238,7 @@ void coap_session_set_mtu(coap_session_t *session, unsigned mtu); * * @return maximum PDU size, not including header (but including token). */ -size_t coap_session_max_pdu_size(const coap_session_t *session); +COAP_API size_t coap_session_max_pdu_size(const coap_session_t *session); /** * Creates a new client session to the designated server. @@ -422,7 +422,7 @@ void coap_endpoint_set_default_mtu(coap_endpoint_t *endpoint, unsigned mtu); * * @param endpoint The endpoint to release. */ -void coap_free_endpoint(coap_endpoint_t *endpoint); +COAP_API void coap_free_endpoint(coap_endpoint_t *endpoint); /** * Get the session associated with the specified @p remote_addr and @p index. @@ -795,13 +795,14 @@ coap_fixed_point_t coap_session_get_non_receive_timeout( const coap_session_t *session); /** @} */ + /** * Send a ping message for the session. * @param session The CoAP session. * * @return COAP_INVALID_MID if there is an error */ -coap_mid_t coap_session_send_ping(coap_session_t *session); +COAP_API coap_mid_t coap_session_send_ping(coap_session_t *session); /** * Disable client automatically sending observe cancel on session close diff --git a/include/coap3/coap_session_internal.h b/include/coap3/coap_session_internal.h index 8883df9156..80fcf9509e 100644 --- a/include/coap3/coap_session_internal.h +++ b/include/coap3/coap_session_internal.h @@ -270,6 +270,28 @@ void coap_session_send_csm(coap_session_t *session); */ void coap_session_connected(coap_session_t *session); +/** + * Notify session that it has failed. This cleans up any outstanding / queued + * transmissions, observations etc.. + * + * Note: This function must be called in the locked state. + * + * @param session The CoAP session. + * @param reason The reason why the session was disconnected. + */ +void coap_session_disconnected_lkd(coap_session_t *session, + coap_nack_reason_t reason); + +/** + * Send a ping message for the session. + * @param session The CoAP session. + * + * Note: This function must be called in the locked state. + * + * @return COAP_INVALID_MID if there is an error + */ +coap_mid_t coap_session_send_ping_lkd(coap_session_t *session); + /** * Refresh the session's current Identity Hint (PSK). * Note: A copy of @p psk_hint is maintained in the session by libcoap. @@ -316,7 +338,7 @@ int coap_session_refresh_psk_identity(coap_session_t *session, * @param ep An endpoint where an incoming connection request is pending. * @param extra Available for use by any underlying network stack. * - * @return A new CoAP session or NULL if failed. Call coap_session_release to + * @return A new CoAP session or NULL if failed. Call coap_session_release_lkd to * add to unused queue. */ coap_session_t *coap_new_server_session(coap_context_t *ctx, @@ -334,6 +356,27 @@ coap_session_t *coap_new_server_session(coap_context_t *ctx, */ void coap_session_establish(coap_session_t *session); +/** + * Increment reference counter on a session. + * + * Note: This function must be called in the locked state. + * + * @param session The CoAP session. + * @return same as session + */ +coap_session_t *coap_session_reference_lkd(coap_session_t *session); + +/** + * Decrement reference counter on a session. + * Note that the session may be deleted as a result and should not be used + * after this call. + * + * Note: This function must be called in the locked state. + * + * @param session The CoAP session. + */ +void coap_session_release_lkd(coap_session_t *session); + /** * Send a pdu according to the session's protocol. This function returns * the number of bytes that have been transmitted, or a value less than zero @@ -366,6 +409,8 @@ coap_session_t *coap_endpoint_get_session(coap_endpoint_t *endpoint, /** * Create a new endpoint for communicating with peers. * + * Note: This function must be called in the locked state. + * * @param context The coap context that will own the new endpoint, * @param listen_addr Address the endpoint will listen for incoming requests * on or originate outgoing requests from. Use NULL to @@ -378,6 +423,15 @@ coap_session_t *coap_endpoint_get_session(coap_endpoint_t *endpoint, coap_endpoint_t *coap_new_endpoint_lkd(coap_context_t *context, const coap_address_t *listen_addr, coap_proto_t proto); +/** + * Release an endpoint and all the structures associated with it. + * + * Note: This function must be called in the locked state. + * + * @param endpoint The endpoint to release. + */ +void coap_free_endpoint_lkd(coap_endpoint_t *endpoint); + #endif /* COAP_SERVER_SUPPORT */ /** @@ -388,6 +442,17 @@ coap_endpoint_t *coap_new_endpoint_lkd(coap_context_t *context, const coap_addre */ size_t coap_session_max_pdu_rcv_size(const coap_session_t *session); +/** + * Get maximum acceptable PDU size + * + * Note: This function must be called in the locked state. + * + * @param session The CoAP session. + * + * @return maximum PDU size, not including header (but including token). + */ +size_t coap_session_max_pdu_size_lkd(const coap_session_t *session); + /** * Creates a new client session to the designated server. * @@ -402,7 +467,7 @@ size_t coap_session_max_pdu_rcv_size(const coap_session_t *session); * for the protocol will be used. * @param proto Protocol. * - * @return A new CoAP session or NULL if failed. Call coap_session_release to free. + * @return A new CoAP session or NULL if failed. Call coap_session_release_lkd to free. */ coap_session_t *coap_new_client_session_lkd( coap_context_t *ctx, @@ -426,7 +491,7 @@ coap_session_t *coap_new_client_session_lkd( * @param proto CoAP Protocol. * @param setup_data PKI parameters. * - * @return A new CoAP session or NULL if failed. Call coap_session_release() + * @return A new CoAP session or NULL if failed. Call coap_session_release_lkd() * to free. */ coap_session_t *coap_new_client_session_pki_lkd(coap_context_t *ctx, @@ -455,7 +520,7 @@ coap_session_t *coap_new_client_session_pki_lkd(coap_context_t *ctx, * @param key PSK shared key * @param key_len PSK shared key length * - * @return A new CoAP session or NULL if failed. Call coap_session_release to free. + * @return A new CoAP session or NULL if failed. Call coap_session_release_lkd to free. */ coap_session_t *coap_new_client_session_psk_lkd(coap_context_t *ctx, const coap_address_t *local_if, @@ -481,7 +546,7 @@ coap_session_t *coap_new_client_session_psk_lkd(coap_context_t *ctx, * @param proto CoAP Protocol. * @param setup_data PSK parameters. * - * @return A new CoAP session or NULL if failed. Call coap_session_release() + * @return A new CoAP session or NULL if failed. Call coap_session_release_lkd() * to free. */ coap_session_t *coap_new_client_session_psk2_lkd(coap_context_t *ctx, diff --git a/include/coap3/coap_subscribe.h b/include/coap3/coap_subscribe.h index 220665e486..8c5005fbba 100644 --- a/include/coap3/coap_subscribe.h +++ b/include/coap3/coap_subscribe.h @@ -213,12 +213,12 @@ void coap_persist_track_funcs(coap_context_t *context, * * @return ptr to subscription if success else @c NULL. */ -coap_subscription_t *coap_persist_observe_add(coap_context_t *context, - coap_proto_t e_proto, - const coap_address_t *e_listen_addr, - const coap_addr_tuple_t *s_addr_info, - const coap_bin_const_t *raw_packet, - const coap_bin_const_t *oscore_info); +COAP_API coap_subscription_t *coap_persist_observe_add(coap_context_t *context, + coap_proto_t e_proto, + const coap_address_t *e_listen_addr, + const coap_addr_tuple_t *s_addr_info, + const coap_bin_const_t *raw_packet, + const coap_bin_const_t *oscore_info); /** * Start up persist tracking using the libcoap module. If the files already @@ -237,11 +237,11 @@ coap_subscription_t *coap_persist_observe_add(coap_context_t *context, * * @return @c 1 if success else @c 0. */ -int coap_persist_startup(coap_context_t *context, - const char *dyn_resource_save_file, - const char *observe_save_file, - const char *obs_cnt_save_file, - uint32_t save_freq); +COAP_API int coap_persist_startup(coap_context_t *context, + const char *dyn_resource_save_file, + const char *observe_save_file, + const char *obs_cnt_save_file, + uint32_t save_freq); /** * Stop tracking persist information, leaving the current persist information @@ -255,7 +255,7 @@ int coap_persist_startup(coap_context_t *context, * * @param context The context that tracking information is to be stopped on. */ -void coap_persist_stop(coap_context_t *context); +COAP_API void coap_persist_stop(coap_context_t *context); /** * Sets the current observe number value. diff --git a/include/coap3/coap_subscribe_internal.h b/include/coap3/coap_subscribe_internal.h index 59d0984b0c..ef3e00e812 100644 --- a/include/coap3/coap_subscribe_internal.h +++ b/include/coap3/coap_subscribe_internal.h @@ -178,6 +178,74 @@ void coap_check_notify_lkd(coap_context_t *context); */ void coap_persist_cleanup(coap_context_t *context); +/** + * Set up an active subscription for an observe that was previously active + * over a coap-server inadvertant restart. + * + * Only UDP sessions currently supported. + * + * Note: This function must be called in the locked state. + * + * @param context The context that the session is to be associated with. + * @param e_proto The CoAP protocol in use for the session / endpoint. + * @param e_listen_addr The IP/port that the endpoint is listening on. + * @param s_addr_info Local / Remote IP addresses. ports etc. of previous + * session. + * @param raw_packet L7 packet as seen on the wire (could be concatenated if + * Block1 FETCH is being used). + * @param oscore_info Has OSCORE information if OSCORE is protecting the + * session or NULL if OSCORE is not in use. + * + * @return ptr to subscription if success else @c NULL. + */ +coap_subscription_t *coap_persist_observe_add_lkd(coap_context_t *context, + coap_proto_t e_proto, + const coap_address_t *e_listen_addr, + const coap_addr_tuple_t *s_addr_info, + const coap_bin_const_t *raw_packet, + const coap_bin_const_t *oscore_info); + +/** + * Start up persist tracking using the libcoap module. If the files already + * exist with saved data, then this information is used in building back + * up the persist information. + * + * Note: This function must be called in the locked state. + * + * @param context The current CoAP context. + * @param dyn_resource_save_file File where dynamically created resource + * information is stored or NULL if not required. + * @param observe_save_file File where observe information is stored or NULL + * if not required. + * @param obs_cnt_save_file File where resource observe counter information + * is stored or NULL if not required. + * @param save_freq Frequency of change of observe value for calling + * the save observe counter logic. + * + * @return @c 1 if success else @c 0. + */ +int coap_persist_startup_lkd(coap_context_t *context, + const char *dyn_resource_save_file, + const char *observe_save_file, + const char *obs_cnt_save_file, + uint32_t save_freq); + +/** + * Stop tracking persist information, leaving the current persist information + * in the files defined in coap_persist_startup(). It is then safe to call + * coap_free_context() to close the application down cleanly. + * + * Note: This function must be called in the locked state. + * + * Alternatively, if coap_persist_track_funcs() was called, then this will + * disable all the callbacks, as well as making sure that no 4.04 is sent out + * for any active observe subscriptions when the resource is deleted after + * subsequently calling coap_free_context(). + * + * @param context The context that tracking information is to be stopped on. + */ +void coap_persist_stop_lkd(coap_context_t *context); + #endif /* COAP_SERVER_SUPPORT */ #if COAP_CLIENT_SUPPORT diff --git a/include/coap3/coap_threadsafe_internal.h b/include/coap3/coap_threadsafe_internal.h index fcafd951fa..9234634f95 100644 --- a/include/coap3/coap_threadsafe_internal.h +++ b/include/coap3/coap_threadsafe_internal.h @@ -17,91 +17,232 @@ #ifndef COAP_THREADSAFE_INTERNAL_H_ #define COAP_THREADSAFE_INTERNAL_H_ +/* + * Support thread safe access into libcoap + * + * Locking at different component levels (i.e context and session) is + * problematic in that coap_process_io() needs to lock the context as + * it scans for all the sessions and then could lock the session being + * processed as well - but context needs to remain locked as a list is + * being scanned. + * + * Then if the session process needs to update context ( e.g. delayqueue), + * context needs to be locked. So, if coap_send() is done on a session, + * it has to be locked, but a retransmission of a PDU by coap_process_io() + * has the context already locked. + * + * So the initial support for thread safe is done at the context level. + * + * Any public API call needs to potentially lock context, as there may be + * multiple contexts. If a public API needs thread safe protection, the + * coap_X() function locks the context lock, calls the coap_X_lkd() function + * that does all the work and on return unlocks the context before returning + * to the caller of coap_X(). + * + * Any internal libcoap calls that are to the public API coap_X() must call + * coap_X_lkd() if the calling code is already locked. + * + * Any call-back into app space must be done by using the coap_lock_callback() + * (or coap_lock_callback_ret()) wrapper where the context remains locked. + * + * Note: + * libcoap may call a handler, which may in turn call into libcoap, which may + * then call a handler. context will remain locked thoughout this process. + * + * Alternatively, coap_lock_callback_release() (or + * coap_lock_callback_ret_release()), is used where the context is unlocked + * for the duration of the call-back. Used for things like a request + * handler which could be busy for some time. + * + * Note: On return from the call-back, the code has to be careful not to + * use memory locations that make have been updated in the call-back by + * calling a Public API. + * + * Any wait on select() or equivalent when a thread is waiting on an event + * must be preceded by unlock context, and then context re-locked after + * return; + * + * To check for recursive deadlocks, COAP_THREAD_RECURSIVE_CHECK needs to be + * defined. + * + * If thread safe is not enabled, then locking of the context does not take + * place. + */ #if COAP_THREAD_SAFE +# if COAP_THREAD_RECURSIVE_CHECK + +/* + * Locking, with deadlock detection + */ +typedef struct coap_lock_t { + coap_mutex_t mutex; + coap_thread_pid_t pid; + coap_thread_pid_t freeing_pid; + const char *lock_file; + unsigned int lock_line; + unsigned int unlock_line; + const char *unlock_file; + const char *callback_file; + unsigned int callback_line; + unsigned int being_freed; + unsigned int in_callback; + unsigned int lock_count; +} coap_lock_t; + +void coap_lock_unlock_func(coap_lock_t *lock, const char *file, int line); +int coap_lock_lock_func(coap_lock_t *lock, const char *file, int line); + +#define coap_lock_lock(s,failed) do { \ + assert(s); \ + if (!coap_lock_lock_func(&(s)->lock, __FILE__, __LINE__)) { \ + failed; \ + } \ + } while (0) + +#define coap_lock_unlock(s) do { \ + assert(s); \ + coap_lock_unlock_func(&(s)->lock, __FILE__, __LINE__); \ + } while (0) + +#define coap_lock_callback(s,func) do { \ + coap_lock_check_locked(s); \ + (s)->lock.in_callback++; \ + (s)->lock.callback_file = __FILE__; \ + (s)->lock.callback_line = __LINE__; \ + func; \ + (s)->lock.in_callback--; \ + } while (0) + +#define coap_lock_callback_ret(r,s,func) do { \ + coap_lock_check_locked(s); \ + (s)->lock.in_callback++; \ + (s)->lock.callback_file = __FILE__; \ + (s)->lock.callback_line = __LINE__; \ + r = func; \ + (s)->lock.in_callback--; \ + } while (0) + +#define coap_lock_callback_release(s,func,fail) do { \ + coap_lock_check_locked(s); \ + coap_lock_unlock(s); \ + func; \ + coap_lock_lock(s,fail); \ + } while (0) + +#define coap_lock_callback_ret_release(r,s,func,fail) do { \ + coap_lock_check_locked(s); \ + coap_lock_unlock(s); \ + r = func; \ + coap_lock_lock(s,fail); \ + } while (0) + +# else /* ! COAP_THREAD_RECURSIVE_CHECK */ + +/* + * Locking, but no deadlock detection + */ +typedef struct coap_lock_t { + coap_mutex_t mutex; + coap_thread_pid_t pid; + coap_thread_pid_t freeing_pid; + uint32_t being_freed; + uint32_t in_callback; + volatile uint32_t lock_count; +} coap_lock_t; + +void coap_lock_unlock_func(coap_lock_t *lock); +int coap_lock_lock_func(coap_lock_t *lock); + +#define coap_lock_lock(s,failed) do { \ + assert(s); \ + if (!coap_lock_lock_func(&(s)->lock)) { \ + failed; \ + } \ + } while (0) + +#define coap_lock_unlock(s) do { \ + assert(s); \ + coap_lock_unlock_func(&(s)->lock); \ + } while (0) + +#define coap_lock_callback(s,func) do { \ + coap_lock_check_locked(s); \ + (s)->lock.in_callback++; \ + func; \ + (s)->lock.in_callback--; \ + } while (0) + +#define coap_lock_callback_ret(r,s,func) do { \ + coap_lock_check_locked(s); \ + (s)->lock.in_callback++; \ + r = func; \ + (s)->lock.in_callback--; \ + } while (0) + +#define coap_lock_callback_release(s,func,fail) do { \ + coap_lock_check_locked(s); \ + coap_lock_unlock(s); \ + func; \ + coap_lock_lock(s,fail); \ + } while (0) + +#define coap_lock_callback_ret_release(r,s,func,fail) do { \ + coap_lock_check_locked(s); \ + coap_lock_unlock(s); \ + r = func; \ + coap_lock_lock(s,fail); \ + } while (0) + +# endif /* ! COAP_THREAD_RECURSIVE_CHECK */ + +#define coap_lock_init(s) do { \ + assert(s); \ + memset(&((s)->lock), 0, sizeof((s)->lock)); \ + coap_mutex_init(&(s)->lock.mutex); \ + } while (0) + +#define coap_lock_being_freed(s,failed) do { \ + coap_lock_lock(s,failed); \ + (s)->lock.being_freed = 1; \ + (s)->lock.freeing_pid = coap_thread_pid; \ + coap_lock_unlock(s); \ + } while (0) + +#define coap_lock_check_locked(s) do { \ + assert((s) && \ + coap_thread_pid == ((s)->lock.being_freed ? (s)->lock.freeing_pid : \ + (s)->lock.pid)); \ + } while (0) + +#define coap_lock_invert(s,func,f) do { \ + coap_lock_check_locked(s); \ + if (!(s)->lock.being_freed) { \ + coap_lock_unlock(s); \ + func; \ + coap_lock_lock(s,f); \ + } else { \ + func; \ + } \ + } while (0) + +#else /* ! COAP_THREAD_SAFE */ + +/* + * No locking - single thread + */ +typedef coap_mutex_t coap_lock_t; + +#define coap_lock_lock(s,failed) +#define coap_lock_unlock(s) +#define coap_lock_init(s) +#define coap_lock_being_freed(s,failed) +#define coap_lock_check_locked(s) {} +#define coap_lock_callback(s,func) func +#define coap_lock_callback_ret(r,s,func) ret = func +#define coap_lock_callback_release(s,func,fail) func +#define coap_lock_callback_ret_release(r,s,func,fail) ret = func +#define coap_lock_invert(s,func,f) func -/* *INDENT-OFF* */ -#ifndef COAP_THREAD_IGNORE_LOCKED_MAPPING - -#define coap_context_set_block_mode(c,b) coap_context_set_block_mode_locked(c,b) -#define coap_context_set_max_block_size(c,m) coap_context_set_max_block_size_locked(c,m) -#define coap_context_set_pki(c,s) coap_context_set_pki_locked(c,s) -#define coap_context_set_pki_root_cas(c,f,d) coap_context_set_pki_root_cas_locked(c,f,d) -#define coap_context_set_psk(c,h,k,l) coap_context_set_psk_locked(c,h,k,l) -#define coap_context_set_psk2(c,s) coap_context_set_psk2_locked(c,s) -#define coap_free_endpoint(e) coap_free_endpoint_locked(e) -#define coap_join_mcast_group_intf(c,g,i) coap_join_mcast_group_intf_locked(c,g,i) -#define coap_persist_observe_add(c,p,l,a,r,o) coap_persist_observe_add_locked(c,p,l,a,r,o) -#define coap_persist_startup(c,d,o,m,s) coap_persist_startup_locked(c,d,o,m,s) -#define coap_persist_stop(c) coap_persist_stop_locked(c) -#define coap_pdu_duplicate(o,s,l,t,d) coap_pdu_duplicate_locked(o,s,l,t,d) -#define coap_register_option(c,t) coap_register_option_locked(c,t) -#define coap_send(s,p) coap_send_locked(s,p) -#define coap_send_ack(s,r) coap_send_ack_locked(s,r) -#define coap_send_error(s,r,c,o) coap_send_error_locked(s,r,c,o) -#define coap_send_message_type(s,r,t) coap_send_message_type_locked(s,r,t) -#define coap_send_rst(s,r) coap_send_rst_locked(s,r) -#define coap_session_max_pdu_size(s) coap_session_max_pdu_size_locked(s) -#define coap_session_reference(s) coap_session_reference_locked(s) -#define coap_session_release(s) coap_session_release_locked(s) -#define coap_session_disconnected(s,r) coap_session_disconnected_locked(s,r) -#define coap_session_send_ping(s) coap_session_send_ping_locked(s) - -#endif /* ! COAP_THREAD_IGNORE_LOCKED_MAPPING */ - -/* Locked equivalend functions */ - -void coap_context_set_block_mode_locked(coap_context_t *context, - uint32_t block_mode); -int coap_context_set_max_block_size_locked(coap_context_t *context, - size_t max_block_size); -int coap_context_set_pki_locked(coap_context_t *ctx, - const coap_dtls_pki_t *setup_data); -int coap_context_set_pki_root_cas_locked(coap_context_t *ctx, - const char *ca_file, const char *ca_dir); -int coap_context_set_psk_locked(coap_context_t *ctx, const char *hint, - const uint8_t *key, size_t key_len); -int coap_context_set_psk2_locked(coap_context_t *ctx, - coap_dtls_spsk_t *setup_data); -void coap_free_endpoint_locked(coap_endpoint_t *ep); -int coap_join_mcast_group_intf_locked(coap_context_t *ctx, const char *group_name, - const char *ifname); -coap_subscription_t *coap_persist_observe_add_locked(coap_context_t *context, - coap_proto_t e_proto, - const coap_address_t *e_listen_addr, - const coap_addr_tuple_t *s_addr_info, - const coap_bin_const_t *raw_packet, - const coap_bin_const_t *oscore_info); -int coap_persist_startup_locked(coap_context_t *context, - const char *dyn_resource_save_file, - const char *observe_save_file, - const char *obs_cnt_save_file, - uint32_t save_freq); -void coap_persist_stop_locked(coap_context_t *context); -size_t coap_session_max_pdu_size_locked(const coap_session_t *session); -coap_pdu_t *coap_pdu_duplicate_locked(const coap_pdu_t *old_pdu, - coap_session_t *session, - size_t token_length, - const uint8_t *token, - coap_opt_filter_t *drop_options); -void coap_register_option_locked(coap_context_t *ctx, uint16_t type); -int coap_resource_set_dirty_locked(coap_resource_t *r, - const coap_string_t *query); -coap_mid_t coap_send_locked(coap_session_t *session, coap_pdu_t *pdu); -coap_mid_t coap_send_ack_locked(coap_session_t *session, const coap_pdu_t *request); -coap_mid_t coap_send_error_locked(coap_session_t *session, const coap_pdu_t *request, - coap_pdu_code_t code, coap_opt_filter_t *opts); -coap_mid_t coap_send_message_type_locked(coap_session_t *session, - const coap_pdu_t *request, - coap_pdu_type_t type); -coap_mid_t coap_send_rst_locked(coap_session_t *session, const coap_pdu_t *request); -void coap_session_disconnected_locked(coap_session_t *session, - coap_nack_reason_t reason); -coap_session_t *coap_session_reference_locked(coap_session_t *session); -void coap_session_release_locked(coap_session_t *session); -coap_mid_t coap_session_send_ping_locked(coap_session_t *session); - -/* *INDENT-ON* */ - -#endif /* COAP_THREAD_SAFE */ +#endif /* ! COAP_THREAD_SAFE */ #endif /* COAP_THREADSAFE_INTERNAL_H_ */ diff --git a/man/coap_locking.txt.in b/man/coap_locking.txt.in index 7fe42ba61b..96fdb2e57e 100644 --- a/man/coap_locking.txt.in +++ b/man/coap_locking.txt.in @@ -85,30 +85,29 @@ not multi-thread access safe. COAP_THREAD_RECURSIVE_CHECK If set, and COAP_THREAD_SAFE is set, checks that if a lock is locked, it reports that the same lock is being (re-)locked. -Currently, locking is only done at the _context_ level for the public API +Currently, locking is only done at the _context_ level for the Public API functions where appropriate. Per _session_ was also considered, but things became complicated with one thread locking _context_ / _session_ and another thread trying to lock _session_ / _context_ in a different order. In principal, libcoap code internally should only unlock _context_ when waiting -on a *select*() or equivalent, and then lock up again on function return. - -_context_ needs to remain locked whenever a callback handler is called, and it is -possible / likely that the handler will call a public API which potentially could -try to re-lock the same lock. By using *coap_lock_callback*() (or -*coap_lock_callback_ret*()), the locking logic can detect that this lock request -is from a callback handler and so continue without any deadlocks. - -If COAP_THREAD_SAFE is set, then all the necessary public APIs are defined in -src/coap_threadsafe.c. These public APIs then call the same function after -locking, but with _locked appended to the function name. In otherwords, -*coap_X*() calls *coap_lock_lock*(), then calls *coap_X_locked*(), and finally -calls *coap_lock_unlock*() before returning. - -The internal renaming of *coap_X*() functions to *coap_X_locked*() is done by -macros in include/coap3/coap_threadsafe_internal.h, which also provides the -*coap_X_locked*() function definitions. - +on a *select*() or equivalent, or when calling a request handler, and then lock +up again on function return. Any other unlock - app call-back - lock needs to +be carefully analyzed as to any potential issues being created by the +app call-back if it calls any Public API, updating any data that is relied on +after lock takes place. + +coap_lock_callback() (or coap_lock_callback_ret()) wrapper leaves the _context_ +locked when calling app call-back, but allows the app call-back to call a +Public API when in the locked state. + +coap_lock_callback_release() (or coap_lock_callback_ret_release()) unlocks +_context_ when calling app call-back. The allows the app call-back to go off +and do other slow/blocking activity. Any calls to a Public API then locks up +_context_ before preceding. + +Any libcoap code that runs with _context_ locked should not call a Public API, +but call the _lkd equivalent (if available). FUNCTIONS --------- diff --git a/src/coap_async.c b/src/coap_async.c index 75de18ae4a..60115ab11f 100644 --- a/src/coap_async.c +++ b/src/coap_async.c @@ -89,8 +89,8 @@ coap_register_async_lkd(coap_session_t *session, LL_PREPEND(session->context->async_state, s); /* Note that this generates a new MID */ - s->pdu = coap_pdu_duplicate(request, session, request->actual_token.length, - request->actual_token.s, NULL); + s->pdu = coap_pdu_duplicate_lkd(request, session, request->actual_token.length, + request->actual_token.s, NULL); if (s->pdu == NULL) { coap_free_async_lkd(session, s); coap_log_crit("coap_register_async: insufficient memory\n"); @@ -101,7 +101,7 @@ coap_register_async_lkd(coap_session_t *session, coap_add_data(s->pdu, len, data); } - s->session = coap_session_reference(session); + s->session = coap_session_reference_lkd(session); coap_async_set_delay_lkd(s, delay); @@ -183,7 +183,7 @@ coap_free_async_sub(coap_context_t *context, coap_async_t *s) { if (s) { LL_DELETE(context->async_state,s); if (s->session) { - coap_session_release(s->session); + coap_session_release_lkd(s->session); } if (s->pdu) { coap_delete_pdu(s->pdu); diff --git a/src/coap_block.c b/src/coap_block.c index 1df3e77752..d61e1f4e2c 100644 --- a/src/coap_block.c +++ b/src/coap_block.c @@ -375,9 +375,17 @@ coap_add_data_blocked_response(const coap_pdu_t *request, (const unsigned char *)coap_response_phrase(response->code)); } -void +COAP_API void coap_context_set_block_mode(coap_context_t *context, uint32_t block_mode) { + coap_lock_lock(context, return); + coap_context_set_block_mode_lkd(context, block_mode); + coap_lock_unlock(context); +} + +void +coap_context_set_block_mode_lkd(coap_context_t *context, + uint32_t block_mode) { coap_lock_check_locked(context); if (!(block_mode & COAP_BLOCK_USE_LIBCOAP)) block_mode = 0; @@ -389,8 +397,19 @@ coap_context_set_block_mode(coap_context_t *context, #endif /* ! COAP_Q_BLOCK_SUPPORT */ } +COAP_API int +coap_context_set_max_block_size(coap_context_t *context, + size_t max_block_size) { + int ret; + + coap_lock_lock(context, return 0); + ret = coap_context_set_max_block_size_lkd(context, max_block_size); + coap_lock_unlock(context); + return ret; +} + int -coap_context_set_max_block_size(coap_context_t *context, size_t max_block_size) { +coap_context_set_max_block_size_lkd(coap_context_t *context, size_t max_block_size) { switch (max_block_size) { case 0: case 16: @@ -466,11 +485,11 @@ coap_cancel_observe_lkd(coap_session_t *session, coap_binary_t *token, lg_crcv->obs_token[0] : (coap_bin_const_t *)lg_crcv->app_token : (coap_bin_const_t *)lg_crcv->app_token; - coap_pdu_t *pdu = coap_pdu_duplicate(&lg_crcv->pdu, - session, - otoken->length, - otoken->s, - NULL); + coap_pdu_t *pdu = coap_pdu_duplicate_lkd(&lg_crcv->pdu, + session, + otoken->length, + otoken->s, + NULL); lg_crcv->observe_set = 0; if (pdu == NULL) @@ -558,8 +577,8 @@ coap_retransmit_oscore_pdu(coap_session_t *session, ++lg_crcv->retry_counter); ltoken_len = coap_encode_var_safe8(ltoken, sizeof(token), token); /* There could be a Block option in pdu */ - resend_pdu = coap_pdu_duplicate(pdu, session, ltoken_len, - ltoken, NULL); + resend_pdu = coap_pdu_duplicate_lkd(pdu, session, ltoken_len, + ltoken, NULL); if (!resend_pdu) goto error; if (echo) { @@ -1319,8 +1338,8 @@ coap_build_missing_pdu(coap_session_t *session, coap_lg_crcv_t *p) { memset(&drop_options, 0, sizeof(coap_opt_filter_t)); coap_option_filter_set(&drop_options, COAP_OPTION_Q_BLOCK2); coap_option_filter_set(&drop_options, COAP_OPTION_OBSERVE); - pdu = coap_pdu_duplicate(&p->pdu, session, len, buf, - &drop_options); + pdu = coap_pdu_duplicate_lkd(&p->pdu, session, len, buf, + &drop_options); if (!pdu) return NULL; pdu->type = p->last_type; @@ -1509,7 +1528,7 @@ pdu_408_build(coap_session_t *session, coap_lg_srcv_t *p) { pdu = coap_pdu_init(COAP_MESSAGE_NON, COAP_RESPONSE_CODE(408), coap_new_message_id_lkd(session), - coap_session_max_pdu_size(session)); + coap_session_max_pdu_size_lkd(session)); if (!pdu) return NULL; if (p->last_token) @@ -1770,7 +1789,7 @@ coap_block_check_lg_srcv_timeouts(coap_session_t *session, coap_tick_t now, pdu = coap_pdu_init(COAP_MESSAGE_NON, COAP_RESPONSE_CODE(408), coap_new_message_id_lkd(session), - coap_session_max_pdu_size(session)); + coap_session_max_pdu_size_lkd(session)); if (pdu) { if (p->last_token) coap_add_token(pdu, p->last_token->length, p->last_token->s); @@ -1849,9 +1868,9 @@ coap_send_q_blocks(coap_session_t *session, memset(&drop_options, 0, sizeof(coap_opt_filter_t)); coap_option_filter_set(&drop_options, lg_xmit->option); - block_pdu = coap_pdu_duplicate(pdu, session, - ltoken_length, - ptoken, &drop_options); + block_pdu = coap_pdu_duplicate_lkd(pdu, session, + ltoken_length, + ptoken, &drop_options); if (block_pdu->type == COAP_MESSAGE_ACK) block_pdu->type = COAP_MESSAGE_CON; } @@ -1892,8 +1911,8 @@ coap_send_q_blocks(coap_session_t *session, ltoken_length = coap_encode_var_safe8(ltoken, sizeof(token), token); ptoken = ltoken; } - t_pdu = coap_pdu_duplicate(block_pdu, session, - ltoken_length, ptoken, &drop_options); + t_pdu = coap_pdu_duplicate_lkd(block_pdu, session, + ltoken_length, ptoken, &drop_options); } if (!coap_update_option(block_pdu, lg_xmit->option, coap_encode_var_safe(buf, @@ -2166,7 +2185,7 @@ coap_block_test_q_block(coap_session_t *session, coap_pdu_t *actual) { /* RFC9177 Section 4.1 when checking if available */ pdu = coap_pdu_init(COAP_MESSAGE_CON, COAP_REQUEST_CODE_GET, coap_new_message_id_lkd(session), - coap_session_max_pdu_size(session)); + coap_session_max_pdu_size_lkd(session)); if (!pdu) { return COAP_INVALID_MID; } @@ -2583,11 +2602,11 @@ coap_handle_request_send_block(coap_session_t *session, if (block.num != 0) coap_option_filter_set(&drop_options, COAP_OPTION_OBSERVE); if (out_blocks[i].is_continue) { - out_pdu = coap_pdu_duplicate(&p->pdu, session, p->pdu.actual_token.length, - p->pdu.actual_token.s, &drop_options); + out_pdu = coap_pdu_duplicate_lkd(&p->pdu, session, p->pdu.actual_token.length, + p->pdu.actual_token.s, &drop_options); } else { - out_pdu = coap_pdu_duplicate(&p->pdu, session, pdu->actual_token.length, - pdu->actual_token.s, &drop_options); + out_pdu = coap_pdu_duplicate_lkd(&p->pdu, session, pdu->actual_token.length, + pdu->actual_token.s, &drop_options); } if (!out_pdu) { goto internal_issue; @@ -3071,11 +3090,11 @@ coap_handle_request_put_block(coap_context_t *context, response->code = COAP_RESPONSE_CODE(231); } else { /* Need to separately respond to this request */ - coap_pdu_t *tmp_pdu = coap_pdu_duplicate(response, - session, - response->actual_token.length, - response->actual_token.s, - NULL); + coap_pdu_t *tmp_pdu = coap_pdu_duplicate_lkd(response, + session, + response->actual_token.length, + response->actual_token.s, + NULL); if (tmp_pdu) { tmp_pdu->code = COAP_RESPONSE_CODE(231); coap_send_internal(session, tmp_pdu); @@ -3227,7 +3246,7 @@ check_freshness(coap_session_t *session, coap_pdu_t *rcvd, coap_pdu_t *sent, ++lg_crcv->retry_counter); } ltoken_len = coap_encode_var_safe8(ltoken, sizeof(token), token); - echo_pdu = coap_pdu_duplicate(sent, session, ltoken_len, ltoken, NULL); + echo_pdu = coap_pdu_duplicate_lkd(sent, session, ltoken_len, ltoken, NULL); if (!echo_pdu) return 0; if (!coap_insert_option(echo_pdu, COAP_OPTION_ECHO, @@ -3396,7 +3415,7 @@ coap_handle_response_send_block(coap_session_t *session, coap_pdu_t *sent, } } } - pdu = coap_pdu_duplicate(&p->pdu, session, len, buf, NULL); + pdu = coap_pdu_duplicate_lkd(&p->pdu, session, len, buf, NULL); if (!pdu) goto fail_body; @@ -3493,8 +3512,8 @@ coap_handle_response_send_block(coap_session_t *session, coap_pdu_t *sent, /* Build the next PDU request based off the skeletal PDU */ token = STATE_TOKEN_FULL(p->b.b1.state_token,++p->b.b1.count); ltoken_length = coap_encode_var_safe8(ltoken, sizeof(token), token); - pdu = coap_pdu_duplicate(&p->pdu, session, ltoken_length, - ltoken, NULL); + pdu = coap_pdu_duplicate_lkd(&p->pdu, session, ltoken_length, + ltoken, NULL); if (!pdu) goto fail_body; @@ -3779,7 +3798,7 @@ coap_handle_response_get_block(coap_context_t *context, coap_session_new_token(session, &len, buf); memset(&drop_options, 0, sizeof(coap_opt_filter_t)); coap_option_filter_set(&drop_options, COAP_OPTION_OBSERVE); - pdu = coap_pdu_duplicate(&p->pdu, session, len, buf, &drop_options); + pdu = coap_pdu_duplicate_lkd(&p->pdu, session, len, buf, &drop_options); if (!pdu) goto fail_resp; @@ -3906,7 +3925,7 @@ coap_handle_response_get_block(coap_context_t *context, /* Ask for the next block */ token = STATE_TOKEN_FULL(p->state_token, ++p->retry_counter); len = coap_encode_var_safe8(buf, sizeof(token), token); - pdu = coap_pdu_duplicate(&p->pdu, session, len, buf, NULL); + pdu = coap_pdu_duplicate_lkd(&p->pdu, session, len, buf, NULL); if (!pdu) goto fail_resp; @@ -4003,12 +4022,12 @@ coap_handle_response_get_block(coap_context_t *context, /* context is being freed off */ assert(0)); if (ret == COAP_RESPONSE_FAIL) { - coap_send_rst(session, rcvd); + coap_send_rst_lkd(session, rcvd); } else { - coap_send_ack(session, rcvd); + coap_send_ack_lkd(session, rcvd); } } else { - coap_send_ack(session, rcvd); + coap_send_ack_lkd(session, rcvd); } ack_rst_sent = 1; if (p->observe_set == 0) { @@ -4166,7 +4185,7 @@ coap_handle_response_get_block(coap_context_t *context, skip_app_handler: if (!ack_rst_sent) - coap_send_ack(session, rcvd); + coap_send_ack_lkd(session, rcvd); return 1; } #endif /* COAP_CLIENT_SUPPORT */ diff --git a/src/coap_dtls.c b/src/coap_dtls.c index 3cff97092e..46ee15bdb6 100644 --- a/src/coap_dtls.c +++ b/src/coap_dtls.c @@ -275,7 +275,7 @@ coap_dtls_establish(coap_session_t *session) { #endif /* COAP_SERVER_SUPPORT */ if (!session->tls) { - coap_session_disconnected(session, COAP_NACK_TLS_LAYER_FAILED); + coap_session_disconnected_lkd(session, COAP_NACK_TLS_LAYER_FAILED); return; } coap_ticks(&session->last_rx_tx); @@ -304,7 +304,7 @@ coap_tls_establish(coap_session_t *session) { #endif /* COAP_SERVER_SUPPORT */ if (!session->tls) { - coap_session_disconnected(session, COAP_NACK_TLS_LAYER_FAILED); + coap_session_disconnected_lkd(session, COAP_NACK_TLS_LAYER_FAILED); return; } coap_ticks(&session->last_rx_tx); diff --git a/src/coap_gnutls.c b/src/coap_gnutls.c index 75a8860222..f3325f733d 100644 --- a/src/coap_gnutls.c +++ b/src/coap_gnutls.c @@ -2341,7 +2341,7 @@ coap_dtls_send(coap_session_t *c_session, coap_handle_event_lkd(c_session->context, c_session->dtls_event, c_session); if (c_session->dtls_event == COAP_EVENT_DTLS_ERROR || c_session->dtls_event == COAP_EVENT_DTLS_CLOSED) { - coap_session_disconnected(c_session, COAP_NACK_TLS_FAILED); + coap_session_disconnected_lkd(c_session, COAP_NACK_TLS_FAILED); ret = -1; } } @@ -2407,7 +2407,7 @@ coap_dtls_handle_timeout(coap_session_t *c_session) { (do_gnutls_handshake(c_session, g_env) < 0)) { /* Too many retries */ g_env->doing_dtls_timeout = 0; - coap_session_disconnected(c_session, COAP_NACK_TLS_FAILED); + coap_session_disconnected_lkd(c_session, COAP_NACK_TLS_FAILED); return 1; } else { g_env->doing_dtls_timeout = 0; @@ -2488,12 +2488,12 @@ coap_dtls_receive(coap_session_t *c_session, const uint8_t *data, } if (c_session->dtls_event >= 0) { - /* COAP_EVENT_DTLS_CLOSED event reported in coap_session_disconnected() */ + /* COAP_EVENT_DTLS_CLOSED event reported in coap_session_disconnected_lkd() */ if (c_session->dtls_event != COAP_EVENT_DTLS_CLOSED) coap_handle_event_lkd(c_session->context, c_session->dtls_event, c_session); if (c_session->dtls_event == COAP_EVENT_DTLS_ERROR || c_session->dtls_event == COAP_EVENT_DTLS_CLOSED) { - coap_session_disconnected(c_session, COAP_NACK_TLS_FAILED); + coap_session_disconnected_lkd(c_session, COAP_NACK_TLS_FAILED); ssl_data = NULL; ret = -1; } @@ -2815,12 +2815,12 @@ coap_tls_write(coap_session_t *c_session, const uint8_t *data, } if (c_session->dtls_event >= 0) { - /* COAP_EVENT_DTLS_CLOSED event reported in coap_session_disconnected() */ + /* COAP_EVENT_DTLS_CLOSED event reported in coap_session_disconnected_lkd() */ if (c_session->dtls_event != COAP_EVENT_DTLS_CLOSED) coap_handle_event_lkd(c_session->context, c_session->dtls_event, c_session); if (c_session->dtls_event == COAP_EVENT_DTLS_ERROR || c_session->dtls_event == COAP_EVENT_DTLS_CLOSED) { - coap_session_disconnected(c_session, COAP_NACK_TLS_FAILED); + coap_session_disconnected_lkd(c_session, COAP_NACK_TLS_FAILED); ret = -1; } } @@ -2896,12 +2896,12 @@ coap_tls_read(coap_session_t *c_session, uint8_t *data, size_t data_len) { } if (c_session->dtls_event >= 0) { - /* COAP_EVENT_DTLS_CLOSED event reported in coap_session_disconnected() */ + /* COAP_EVENT_DTLS_CLOSED event reported in coap_session_disconnected_lkd() */ if (c_session->dtls_event != COAP_EVENT_DTLS_CLOSED) coap_handle_event_lkd(c_session->context, c_session->dtls_event, c_session); if (c_session->dtls_event == COAP_EVENT_DTLS_ERROR || c_session->dtls_event == COAP_EVENT_DTLS_CLOSED) { - coap_session_disconnected(c_session, COAP_NACK_TLS_FAILED); + coap_session_disconnected_lkd(c_session, COAP_NACK_TLS_FAILED); ret = -1; } } diff --git a/src/coap_io.c b/src/coap_io.c index 7a3e1d9642..533af38f6c 100644 --- a/src/coap_io.c +++ b/src/coap_io.c @@ -1350,7 +1350,7 @@ coap_io_prepare_io_lkd(coap_context_t *ctx, timeout = s_timeout; } /* Make sure the session object is not deleted in any callbacks */ - coap_session_reference(s); + coap_session_reference_lkd(s); /* Check any DTLS timeouts and expire if appropriate */ if (check_dtls_timeouts && s->state == COAP_SESSION_STATE_HANDSHAKE && s->proto == COAP_PROTO_DTLS && s->tls) { @@ -1403,7 +1403,7 @@ coap_io_prepare_io_lkd(coap_context_t *ctx, } #endif /* COAP_Q_BLOCK_SUPPORT */ release_1: - coap_session_release(s); + coap_session_release_lkd(s); } } } @@ -1415,7 +1415,7 @@ coap_io_prepare_io_lkd(coap_context_t *ctx, ctx->ping_timeout > 0) { if (s->last_rx_tx + ctx->ping_timeout * COAP_TICKS_PER_SECOND <= now) { /* Time to send a ping */ - if ((s->last_ping_mid = coap_session_send_ping(s)) == COAP_INVALID_MID) + if ((s->last_ping_mid = coap_session_send_ping_lkd(s)) == COAP_INVALID_MID) /* Some issue - not safe to continue processing */ continue; if (s->last_ping > 0 && s->last_pong < s->last_ping) { @@ -1447,7 +1447,7 @@ coap_io_prepare_io_lkd(coap_context_t *ctx, #endif /* !COAP_DISABLE_TCP */ /* Make sure the session object is not deleted in any callbacks */ - coap_session_reference(s); + coap_session_reference_lkd(s); /* Check any DTLS timeouts and expire if appropriate */ if (s->state == COAP_SESSION_STATE_HANDSHAKE && s->proto == COAP_PROTO_DTLS && s->tls) { @@ -1504,7 +1504,7 @@ coap_io_prepare_io_lkd(coap_context_t *ctx, } #endif /* ! COAP_EPOLL_SUPPORT && ! WITH_LWIP && ! RIOT_VERSION */ release_2: - coap_session_release(s); + coap_session_release_lkd(s); } #endif /* COAP_CLIENT_SUPPORT */ diff --git a/src/coap_io_lwip.c b/src/coap_io_lwip.c index 9f09f15407..4d93377b04 100644 --- a/src/coap_io_lwip.c +++ b/src/coap_io_lwip.c @@ -185,7 +185,7 @@ coap_recvc(void *arg, struct udp_pcb *upcb, struct pbuf *p, * https://rfc-editor.org/rfc/rfc7252#section-4.3 MAY send RST */ if (session) - coap_send_rst(session, pdu); + coap_send_rst_lkd(session, pdu); coap_delete_pdu(pdu); return; } @@ -280,7 +280,7 @@ coap_udp_recvs(void *arg, struct udp_pcb *upcb, struct pbuf *p, * https://rfc-editor.org/rfc/rfc7252#section-4.3 MAY send RST */ if (session && pdu) - coap_send_rst(session, pdu); + coap_send_rst_lkd(session, pdu); coap_delete_pdu(pdu); coap_free_packet(packet); coap_lock_unlock(ep->context); @@ -450,10 +450,10 @@ do_tcp_err(void *arg, err_t err) { /* * as per tcp_err() documentation, the corresponding pcb is already freed * when this callback is called. So, stop a double free when - * coap_session_disconnected() eventually coap_socket_close() is called. + * coap_session_disconnected_lkd() eventually coap_socket_close() is called. */ session->sock.tcp_pcb = NULL; - coap_session_disconnected(session, COAP_NACK_NOT_DELIVERABLE); + coap_session_disconnected_lkd(session, COAP_NACK_NOT_DELIVERABLE); } /** Callback from lwIP when a TCP packet is received. @@ -474,7 +474,7 @@ coap_tcp_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err) { tcp_recv(sock->tcp_pcb, NULL); tcp_close(sock->tcp_pcb); sock->tcp_pcb = NULL; - coap_session_disconnected(session, COAP_NACK_NOT_DELIVERABLE); + coap_session_disconnected_lkd(session, COAP_NACK_NOT_DELIVERABLE); return ERR_OK; } else if (err != ERR_OK) { /* cleanup, for unknown reason */ diff --git a/src/coap_mbedtls.c b/src/coap_mbedtls.c index 6c70f4f875..10560aaae5 100644 --- a/src/coap_mbedtls.c +++ b/src/coap_mbedtls.c @@ -2039,12 +2039,12 @@ coap_dtls_send(coap_session_t *c_session, } if (c_session->dtls_event >= 0) { - /* COAP_EVENT_DTLS_CLOSED event reported in coap_session_disconnected() */ + /* COAP_EVENT_DTLS_CLOSED event reported in coap_session_disconnected_lkd() */ if (c_session->dtls_event != COAP_EVENT_DTLS_CLOSED) coap_handle_event_lkd(c_session->context, c_session->dtls_event, c_session); if (c_session->dtls_event == COAP_EVENT_DTLS_ERROR || c_session->dtls_event == COAP_EVENT_DTLS_CLOSED) { - coap_session_disconnected(c_session, COAP_NACK_TLS_FAILED); + coap_session_disconnected_lkd(c_session, COAP_NACK_TLS_FAILED); ret = -1; } } @@ -2121,7 +2121,7 @@ coap_dtls_handle_timeout(coap_session_t *c_session) { if ((++c_session->dtls_timeout_count > c_session->max_retransmit) || (do_mbedtls_handshake(c_session, m_env) < 0)) { /* Too many retries */ - coap_session_disconnected(c_session, COAP_NACK_TLS_FAILED); + coap_session_disconnected_lkd(c_session, COAP_NACK_TLS_FAILED); return 1; } return 0; @@ -2214,12 +2214,12 @@ coap_dtls_receive(coap_session_t *c_session, } } if (c_session->dtls_event >= 0) { - /* COAP_EVENT_DTLS_CLOSED event reported in coap_session_disconnected() */ + /* COAP_EVENT_DTLS_CLOSED event reported in coap_session_disconnected_lkd() */ if (c_session->dtls_event != COAP_EVENT_DTLS_CLOSED) coap_handle_event_lkd(c_session->context, c_session->dtls_event, c_session); if (c_session->dtls_event == COAP_EVENT_DTLS_ERROR || c_session->dtls_event == COAP_EVENT_DTLS_CLOSED) { - coap_session_disconnected(c_session, COAP_NACK_TLS_FAILED); + coap_session_disconnected_lkd(c_session, COAP_NACK_TLS_FAILED); ssl_data = NULL; ret = -1; } @@ -2457,12 +2457,12 @@ coap_tls_write(coap_session_t *c_session, const uint8_t *data, } if (c_session->dtls_event >= 0) { - /* COAP_EVENT_DTLS_CLOSED event reported in coap_session_disconnected() */ + /* COAP_EVENT_DTLS_CLOSED event reported in coap_session_disconnected_lkd() */ if (c_session->dtls_event != COAP_EVENT_DTLS_CLOSED) coap_handle_event_lkd(c_session->context, c_session->dtls_event, c_session); if (c_session->dtls_event == COAP_EVENT_DTLS_ERROR || c_session->dtls_event == COAP_EVENT_DTLS_CLOSED) { - coap_session_disconnected(c_session, COAP_NACK_TLS_FAILED); + coap_session_disconnected_lkd(c_session, COAP_NACK_TLS_FAILED); ret = -1; } } @@ -2535,12 +2535,12 @@ coap_tls_read(coap_session_t *c_session, uint8_t *data, size_t data_len) { } if (c_session->dtls_event >= 0) { - /* COAP_EVENT_DTLS_CLOSED event reported in coap_session_disconnected() */ + /* COAP_EVENT_DTLS_CLOSED event reported in coap_session_disconnected_lkd() */ if (c_session->dtls_event != COAP_EVENT_DTLS_CLOSED) coap_handle_event_lkd(c_session->context, c_session->dtls_event, c_session); if (c_session->dtls_event == COAP_EVENT_DTLS_ERROR || c_session->dtls_event == COAP_EVENT_DTLS_CLOSED) { - coap_session_disconnected(c_session, COAP_NACK_TLS_FAILED); + coap_session_disconnected_lkd(c_session, COAP_NACK_TLS_FAILED); ret = -1; } } diff --git a/src/coap_net.c b/src/coap_net.c index e18df96f46..0e19c4f5d7 100644 --- a/src/coap_net.c +++ b/src/coap_net.c @@ -235,7 +235,7 @@ coap_delete_node_lkd(coap_queue_t *node) { if (node->session->context->sendqueue) { LL_DELETE(node->session->context->sendqueue, node); } - coap_session_release(node->session); + coap_session_release_lkd(node->session); } coap_free_node(node); @@ -344,11 +344,24 @@ coap_get_session_server_psk_hint(const coap_session_t *session) { return NULL; } -int +COAP_API int coap_context_set_psk(coap_context_t *ctx, const char *hint, const uint8_t *key, size_t key_len) { + int ret; + + coap_lock_lock(ctx, return 0); + ret = coap_context_set_psk_lkd(ctx, hint, key, key_len); + coap_lock_unlock(ctx); + return ret; +} + +int +coap_context_set_psk_lkd(coap_context_t *ctx, + const char *hint, + const uint8_t *key, + size_t key_len) { coap_dtls_spsk_t setup_data; coap_lock_check_locked(ctx); @@ -363,11 +376,21 @@ coap_context_set_psk(coap_context_t *ctx, setup_data.psk_info.key.length = key_len; } - return coap_context_set_psk2(ctx, &setup_data); + return coap_context_set_psk2_lkd(ctx, &setup_data); } -int +COAP_API int coap_context_set_psk2(coap_context_t *ctx, coap_dtls_spsk_t *setup_data) { + int ret; + + coap_lock_lock(ctx, return 0); + ret = coap_context_set_psk2_lkd(ctx, setup_data); + coap_lock_unlock(ctx); + return ret; +} + +int +coap_context_set_psk2_lkd(coap_context_t *ctx, coap_dtls_spsk_t *setup_data) { if (!setup_data) return 0; @@ -380,9 +403,20 @@ coap_context_set_psk2(coap_context_t *ctx, coap_dtls_spsk_t *setup_data) { return 0; } -int +COAP_API int coap_context_set_pki(coap_context_t *ctx, const coap_dtls_pki_t *setup_data) { + int ret; + + coap_lock_lock(ctx, return 0); + ret = coap_context_set_pki_lkd(ctx, setup_data); + coap_lock_unlock(ctx); + return ret; +} + +int +coap_context_set_pki_lkd(coap_context_t *ctx, + const coap_dtls_pki_t *setup_data) { coap_lock_check_locked(ctx); if (!setup_data) return 0; @@ -397,10 +431,22 @@ coap_context_set_pki(coap_context_t *ctx, } #endif /* ! COAP_SERVER_SUPPORT */ -int +COAP_API int coap_context_set_pki_root_cas(coap_context_t *ctx, const char *ca_file, const char *ca_dir) { + int ret; + + coap_lock_lock(ctx, return 0); + ret = coap_context_set_pki_root_cas_lkd(ctx, ca_file, ca_dir); + coap_lock_unlock(ctx); + return ret; +} + +int +coap_context_set_pki_root_cas_lkd(coap_context_t *ctx, + const char *ca_file, + const char *ca_dir) { if (coap_dtls_is_supported() || coap_tls_is_supported()) { return coap_dtls_context_set_pki_root_cas(ctx, ca_file, ca_dir); } @@ -679,7 +725,7 @@ coap_free_context_lkd(coap_context_t *context) { coap_endpoint_t *ep, *tmp; LL_FOREACH_SAFE(context->endpoint, ep, tmp) { - coap_free_endpoint(ep); + coap_free_endpoint_lkd(ep); } #endif /* COAP_SERVER_SUPPORT */ @@ -687,7 +733,7 @@ coap_free_context_lkd(coap_context_t *context) { coap_session_t *sp, *rtmp; SESSIONS_ITER_SAFE(context->sessions, sp, rtmp) { - coap_session_release(sp); + coap_session_release_lkd(sp); } #endif /* COAP_CLIENT_SUPPORT */ @@ -838,13 +884,33 @@ coap_option_check_critical(coap_session_t *session, return ok; } -coap_mid_t +COAP_API coap_mid_t coap_send_rst(coap_session_t *session, const coap_pdu_t *request) { - return coap_send_message_type(session, request, COAP_MESSAGE_RST); + coap_mid_t mid; + + coap_lock_lock(session->context, return COAP_INVALID_MID); + mid = coap_send_rst_lkd(session, request); + coap_lock_unlock(session->context); + return mid; } coap_mid_t +coap_send_rst_lkd(coap_session_t *session, const coap_pdu_t *request) { + return coap_send_message_type_lkd(session, request, COAP_MESSAGE_RST); +} + +COAP_API coap_mid_t coap_send_ack(coap_session_t *session, const coap_pdu_t *request) { + coap_mid_t mid; + + coap_lock_lock(session->context, return COAP_INVALID_MID); + mid = coap_send_ack_lkd(session, request); + coap_lock_unlock(session->context); + return mid; +} + +coap_mid_t +coap_send_ack_lkd(coap_session_t *session, const coap_pdu_t *request) { coap_pdu_t *response; coap_mid_t result = COAP_INVALID_MID; @@ -910,11 +976,24 @@ coap_send_pdu(coap_session_t *session, coap_pdu_t *pdu, coap_queue_t *node) { return bytes_written; } -coap_mid_t +COAP_API coap_mid_t coap_send_error(coap_session_t *session, const coap_pdu_t *request, coap_pdu_code_t code, coap_opt_filter_t *opts) { + coap_mid_t mid; + + coap_lock_lock(session->context, return COAP_INVALID_MID); + mid = coap_send_error_lkd(session, request, code, opts); + coap_lock_unlock(session->context); + return mid; +} + +coap_mid_t +coap_send_error_lkd(coap_session_t *session, + const coap_pdu_t *request, + coap_pdu_code_t code, + coap_opt_filter_t *opts) { coap_pdu_t *response; coap_mid_t result = COAP_INVALID_MID; @@ -928,9 +1007,20 @@ coap_send_error(coap_session_t *session, return result; } -coap_mid_t +COAP_API coap_mid_t coap_send_message_type(coap_session_t *session, const coap_pdu_t *request, coap_pdu_type_t type) { + coap_mid_t mid; + + coap_lock_lock(session->context, return COAP_INVALID_MID); + mid = coap_send_message_type_lkd(session, request, type); + coap_lock_unlock(session->context); + return mid; +} + +coap_mid_t +coap_send_message_type_lkd(coap_session_t *session, const coap_pdu_t *request, + coap_pdu_type_t type) { coap_pdu_t *response; coap_mid_t result = COAP_INVALID_MID; @@ -987,7 +1077,7 @@ coap_wait_ack(coap_context_t *context, coap_session_t *session, coap_queue_t *node) { coap_tick_t now; - node->session = coap_session_reference(session); + node->session = coap_session_reference_lkd(session); /* Set timer for pdu retransmission. If this is the first element in * the retransmission queue, the base time is set to the current @@ -1034,7 +1124,7 @@ coap_send_test_extended_token(coap_session_t *session) { /* https://rfc-editor.org/rfc/rfc8974#section-2.2.2 */ pdu = coap_pdu_init(COAP_MESSAGE_CON, COAP_REQUEST_CODE_GET, coap_new_message_id_lkd(session), - coap_session_max_pdu_size(session)); + coap_session_max_pdu_size_lkd(session)); if (!pdu) return COAP_INVALID_MID; @@ -1076,14 +1166,14 @@ coap_client_delay_first(coap_session_t *session) { * Need to wait for first request to get out and response back before * continuing.. Response handler has to clear doing_first if not an error. */ - coap_session_reference(session); + coap_session_reference_lkd(session); while (session->doing_first != 0) { int result = coap_io_process_lkd(session->context, 1000); if (result < 0) { session->doing_first = 0; session->delay_recursive = 0; - coap_session_release(session); + coap_session_release_lkd(session); return 0; } @@ -1115,7 +1205,7 @@ coap_client_delay_first(coap_session_t *session) { } } session->delay_recursive = 0; - coap_session_release(session); + coap_session_release_lkd(session); } #else /* ! COAP_CLIENT_SUPPORT */ (void)session; @@ -1151,8 +1241,18 @@ coap_check_code_class(coap_session_t *session, coap_pdu_t *pdu) { return 1; } -coap_mid_t +COAP_API coap_mid_t coap_send(coap_session_t *session, coap_pdu_t *pdu) { + coap_mid_t mid; + + coap_lock_lock(session->context, return COAP_INVALID_MID); + mid = coap_send_lkd(session, pdu); + coap_lock_unlock(session->context); + return mid; +} + +coap_mid_t +coap_send_lkd(coap_session_t *session, coap_pdu_t *pdu) { coap_mid_t mid = COAP_INVALID_MID; #if COAP_CLIENT_SUPPORT coap_lg_crcv_t *lg_crcv = NULL; @@ -1865,7 +1965,7 @@ coap_connect_session(coap_session_t *session, coap_tick_t now) { session->sock.lfunc[COAP_LAYER_SESSION].l_establish(session); } else { coap_handle_event_lkd(session->context, COAP_EVENT_TCP_FAILED, session); - coap_session_disconnected(session, COAP_NACK_NOT_DELIVERABLE); + coap_session_disconnected_lkd(session, COAP_NACK_NOT_DELIVERABLE); } #endif /* !COAP_DISABLE_TCP */ } @@ -1928,7 +2028,7 @@ coap_read_session(coap_context_t *ctx, coap_session_t *session, coap_tick_t now) if (bytes_read < 0) { if (bytes_read == -2) /* Reset the session back to startup defaults */ - coap_session_disconnected(session, COAP_NACK_ICMP_ISSUE); + coap_session_disconnected_lkd(session, COAP_NACK_ICMP_ISSUE); } else if (bytes_read > 0) { session->last_rx_tx = now; /* coap_netif_dgrm_read() updates session->addr_info from packet->addr_info */ @@ -1944,7 +2044,7 @@ coap_read_session(coap_context_t *ctx, coap_session_t *session, coap_tick_t now) packet->payload, packet->length); if (bytes_read < 0) { - coap_session_disconnected(session, COAP_NACK_NOT_DELIVERABLE); + coap_session_disconnected_lkd(session, COAP_NACK_NOT_DELIVERABLE); } else if (bytes_read > 2) { coap_pdu_t *pdu; @@ -2082,7 +2182,7 @@ coap_read_session(coap_context_t *ctx, coap_session_t *session, coap_tick_t now) } } while (bytes_read == 0 && retry); if (bytes_read < 0) - coap_session_disconnected(session, COAP_NACK_NOT_DELIVERABLE); + coap_session_disconnected_lkd(session, COAP_NACK_NOT_DELIVERABLE); #endif /* !COAP_DISABLE_TCP */ } #if COAP_CONSTRAINED_STACK @@ -2190,14 +2290,14 @@ coap_io_do_io_lkd(coap_context_t *ctx, coap_tick_t now) { #endif /* !COAP_DISABLE_TCP */ SESSIONS_ITER_SAFE(ep->sessions, s, rtmp) { /* Make sure the session object is not deleted in one of the callbacks */ - coap_session_reference(s); + coap_session_reference_lkd(s); if ((s->sock.flags & COAP_SOCKET_CAN_READ) != 0) { coap_read_session(ctx, s, now); } if ((s->sock.flags & COAP_SOCKET_CAN_WRITE) != 0) { coap_write_session(ctx, s, now); } - coap_session_release(s); + coap_session_release_lkd(s); } } #endif /* COAP_SERVER_SUPPORT */ @@ -2205,7 +2305,7 @@ coap_io_do_io_lkd(coap_context_t *ctx, coap_tick_t now) { #if COAP_CLIENT_SUPPORT SESSIONS_ITER_SAFE(ctx->sessions, s, rtmp) { /* Make sure the session object is not deleted in one of the callbacks */ - coap_session_reference(s); + coap_session_reference_lkd(s); if ((s->sock.flags & COAP_SOCKET_CAN_CONNECT) != 0) { coap_connect_session(s, now); } @@ -2215,7 +2315,7 @@ coap_io_do_io_lkd(coap_context_t *ctx, coap_tick_t now) { if ((s->sock.flags & COAP_SOCKET_CAN_WRITE) != 0 && s->ref > 1) { coap_write_session(ctx, s, now); } - coap_session_release(s); + coap_session_release_lkd(s); } #endif /* COAP_CLIENT_SUPPORT */ #endif /* ! COAP_EPOLL_SUPPORT */ @@ -2285,7 +2385,7 @@ coap_io_do_epoll_lkd(coap_context_t *ctx, struct epoll_event *events, size_t nev /* Make sure the session object is not deleted in one of the callbacks */ - coap_session_reference(session); + coap_session_reference_lkd(session); #if COAP_CLIENT_SUPPORT if ((sock->flags & COAP_SOCKET_WANT_CONNECT) && (events[j].events & (EPOLLOUT|EPOLLERR|EPOLLHUP|EPOLLRDHUP))) { @@ -2315,7 +2415,7 @@ coap_io_do_epoll_lkd(coap_context_t *ctx, struct epoll_event *events, size_t nev coap_write_session(session->context, session, now); } /* Now dereference session so it can go away if needed */ - coap_session_release(session); + coap_session_release_lkd(session); } } else if (ctx->eptimerfd != -1) { /* @@ -2377,7 +2477,7 @@ coap_handle_dgram(coap_context_t *ctx, coap_session_t *session, * https://rfc-editor.org/rfc/rfc7252#section-4.2 MUST send RST * https://rfc-editor.org/rfc/rfc7252#section-4.3 MAY send RST */ - coap_send_rst(session, pdu); + coap_send_rst_lkd(session, pdu); coap_delete_pdu(pdu); return -1; } @@ -2941,7 +3041,7 @@ handle_request(coap_context_t *context, coap_session_t *session, coap_pdu_t *pdu if (async->delay == 0 || async->delay > now) { /* re-transmit missing ACK (only if CON) */ coap_log_info("Retransmit async response\n"); - coap_send_ack(session, pdu); + coap_send_ack_lkd(session, pdu); /* and do not pass on to the upper layers */ return; } @@ -3189,7 +3289,7 @@ handle_request(coap_context_t *context, coap_session_t *session, coap_pdu_t *pdu response = coap_pdu_init(pdu->type == COAP_MESSAGE_CON ? COAP_MESSAGE_ACK : COAP_MESSAGE_NON, - 0, pdu->mid, coap_session_max_pdu_size(session)); + 0, pdu->mid, coap_session_max_pdu_size_lkd(session)); if (!response) { coap_log_err("could not create response PDU\n"); resp = 500; @@ -3295,7 +3395,7 @@ handle_request(coap_context_t *context, coap_session_t *session, coap_pdu_t *pdu send_early_empty_ack = 1; } if (send_early_empty_ack) { - coap_send_ack(session, pdu); + coap_send_ack_lkd(session, pdu); if (pdu->mid == session->last_con_mid) { /* request has already been processed - do not process it again */ coap_log_debug("Duplicate request with mid=0x%04x - not processed\n", @@ -3507,9 +3607,9 @@ handle_response(coap_context_t *context, coap_session_t *session, if (rcvd->mid == session->last_con_mid) { /* Duplicate response: send ACK/RST, but don't process */ if (session->last_con_handler_res == COAP_RESPONSE_OK) - coap_send_ack(session, rcvd); + coap_send_ack_lkd(session, rcvd); else - coap_send_rst(session, rcvd); + coap_send_rst_lkd(session, rcvd); return; } session->last_con_mid = rcvd->mid; @@ -3564,7 +3664,7 @@ handle_response(coap_context_t *context, coap_session_t *session, /* See if need to send next block to server */ if (coap_handle_response_send_block(session, sent, rcvd)) { /* Next block transmitted, no need to inform app */ - coap_send_ack(session, rcvd); + coap_send_ack_lkd(session, rcvd); return; } @@ -3588,14 +3688,14 @@ handle_response(coap_context_t *context, coap_session_t *session, /* context is being freed off */ return); if (ret == COAP_RESPONSE_FAIL && rcvd->type != COAP_MESSAGE_ACK) { - coap_send_rst(session, rcvd); + coap_send_rst_lkd(session, rcvd); session->last_con_handler_res = COAP_RESPONSE_FAIL; } else { - coap_send_ack(session, rcvd); + coap_send_ack_lkd(session, rcvd); session->last_con_handler_res = COAP_RESPONSE_OK; } } else { - coap_send_ack(session, rcvd); + coap_send_ack_lkd(session, rcvd); session->last_con_handler_res = COAP_RESPONSE_OK; } } @@ -3670,7 +3770,7 @@ handle_signaling(coap_context_t *context, coap_session_t *session, } } else if (pdu->code == COAP_SIGNALING_CODE_RELEASE || pdu->code == COAP_SIGNALING_CODE_ABORT) { - coap_session_disconnected(session, COAP_NACK_RST); + coap_session_disconnected_lkd(session, COAP_NACK_RST); } } #endif /* !COAP_DISABLE_TCP */ @@ -3701,7 +3801,7 @@ check_token_size(coap_session_t *session, const coap_pdu_t *pdu) { } } else { /* Indicate no extended token support */ - coap_send_rst(session, pdu); + coap_send_rst_lkd(session, pdu); } return 0; } @@ -3732,7 +3832,7 @@ coap_dispatch(coap_context_t *context, coap_session_t *session, pdu->code & 0x1f); packet_is_bad = 1; if (pdu->type == COAP_MESSAGE_CON) { - coap_send_message_type(session, pdu, COAP_MESSAGE_RST); + coap_send_message_type_lkd(session, pdu, COAP_MESSAGE_RST); } /* find message id in sendqueue to stop retransmission */ coap_remove_from_queue(&context->sendqueue, session, pdu->mid, &sent); @@ -3745,7 +3845,7 @@ coap_dispatch(coap_context_t *context, coap_session_t *session, if (!COAP_PDU_IS_SIGNALING(pdu) && coap_option_check_critical(session, pdu, &opt_filter) == 0) { if (pdu->type == COAP_MESSAGE_NON) { - coap_send_rst(session, pdu); + coap_send_rst_lkd(session, pdu); goto cleanup; } else if (pdu->type == COAP_MESSAGE_CON) { if (COAP_PDU_IS_REQUEST(pdu)) { @@ -3759,7 +3859,7 @@ coap_dispatch(coap_context_t *context, coap_session_t *session, coap_log_warn("coap_dispatch: error sending response\n"); } } else { - coap_send_rst(session, pdu); + coap_send_rst_lkd(session, pdu); } } goto cleanup; @@ -3951,14 +4051,14 @@ coap_dispatch(coap_context_t *context, coap_session_t *session, LL_FOREACH_SAFE(r->subscribers, obs, tmp) { if (obs->pdu->mid == pdu->mid && obs->session == session) { /* Need to do this now as session may get de-referenced */ - coap_session_reference(session); + coap_session_reference_lkd(session); coap_delete_observer(r, session, &obs->pdu->actual_token); if (context->nack_handler) { coap_lock_callback(context, context->nack_handler(session, NULL, COAP_NACK_RST, pdu->mid)); } - coap_session_release(session); + coap_session_release_lkd(session); goto cleanup; } } @@ -3977,7 +4077,7 @@ coap_dispatch(coap_context_t *context, coap_session_t *session, /* check for unknown critical options */ if (coap_option_check_critical(session, pdu, &opt_filter) == 0) { packet_is_bad = 1; - coap_send_rst(session, pdu); + coap_send_rst_lkd(session, pdu); goto cleanup; } if (!check_token_size(session, pdu)) { @@ -4000,7 +4100,7 @@ coap_dispatch(coap_context_t *context, coap_session_t *session, coap_log_warn("coap_dispatch: error sending response\n"); } } else { - coap_send_rst(session, pdu); + coap_send_rst_lkd(session, pdu); } goto cleanup; } @@ -4048,13 +4148,13 @@ coap_dispatch(coap_context_t *context, coap_session_t *session, coap_tick_t now; coap_ticks(&now); if (session->last_tx_rst + COAP_TICKS_PER_SECOND/4 < now) { - coap_send_message_type(session, pdu, COAP_MESSAGE_RST); + coap_send_message_type_lkd(session, pdu, COAP_MESSAGE_RST); session->last_tx_rst = now; } } } else { if (pdu->type == COAP_MESSAGE_CON) - coap_send_message_type(session, pdu, COAP_MESSAGE_RST); + coap_send_message_type_lkd(session, pdu, COAP_MESSAGE_RST); } } } @@ -4337,16 +4437,34 @@ coap_register_pong_handler(coap_context_t *context, context->pong_handler = handler; } -void +COAP_API void coap_register_option(coap_context_t *ctx, uint16_t type) { + coap_lock_lock(ctx, return); + coap_register_option_lkd(ctx, type); + coap_lock_unlock(ctx); +} + +void +coap_register_option_lkd(coap_context_t *ctx, uint16_t type) { coap_option_filter_set(&ctx->known_options, type); } #if ! defined WITH_CONTIKI && ! defined WITH_LWIP && ! defined RIOT_VERSION #if COAP_SERVER_SUPPORT -int +COAP_API int coap_join_mcast_group_intf(coap_context_t *ctx, const char *group_name, const char *ifname) { + int ret; + + coap_lock_lock(ctx, return -1); + ret = coap_join_mcast_group_intf_lkd(ctx, group_name, ifname); + coap_lock_unlock(ctx); + return ret; +} + +int +coap_join_mcast_group_intf_lkd(coap_context_t *ctx, const char *group_name, + const char *ifname) { #if COAP_IPV4_SUPPORT struct ip_mreq mreq4; #endif /* COAP_IPV4_SUPPORT */ diff --git a/src/coap_openssl.c b/src/coap_openssl.c index d795faebc9..23e5e1c639 100644 --- a/src/coap_openssl.c +++ b/src/coap_openssl.c @@ -3496,12 +3496,12 @@ coap_dtls_send(coap_session_t *session, } if (session->dtls_event >= 0) { - /* COAP_EVENT_DTLS_CLOSED event reported in coap_session_disconnected() */ + /* COAP_EVENT_DTLS_CLOSED event reported in coap_session_disconnected_lkd() */ if (session->dtls_event != COAP_EVENT_DTLS_CLOSED) coap_handle_event_lkd(session->context, session->dtls_event, session); if (session->dtls_event == COAP_EVENT_DTLS_ERROR || session->dtls_event == COAP_EVENT_DTLS_CLOSED) { - coap_session_disconnected(session, COAP_NACK_TLS_FAILED); + coap_session_disconnected_lkd(session, COAP_NACK_TLS_FAILED); r = -1; } } @@ -3550,7 +3550,7 @@ coap_dtls_handle_timeout(coap_session_t *session) { if ((++session->dtls_timeout_count > session->max_retransmit) || (DTLSv1_handle_timeout(ssl) < 0)) { /* Too many retries */ - coap_session_disconnected(session, COAP_NACK_TLS_FAILED); + coap_session_disconnected_lkd(session, COAP_NACK_TLS_FAILED); return 1; } return 0; @@ -3638,12 +3638,12 @@ coap_dtls_receive(coap_session_t *session, const uint8_t *data, size_t data_len) r = -1; } if (session->dtls_event >= 0) { - /* COAP_EVENT_DTLS_CLOSED event reported in coap_session_disconnected() */ + /* COAP_EVENT_DTLS_CLOSED event reported in coap_session_disconnected_lkd() */ if (session->dtls_event != COAP_EVENT_DTLS_CLOSED) coap_handle_event_lkd(session->context, session->dtls_event, session); if (session->dtls_event == COAP_EVENT_DTLS_ERROR || session->dtls_event == COAP_EVENT_DTLS_CLOSED) { - coap_session_disconnected(session, COAP_NACK_TLS_FAILED); + coap_session_disconnected_lkd(session, COAP_NACK_TLS_FAILED); ssl_data = NULL; r = -1; } @@ -3931,12 +3931,12 @@ coap_tls_write(coap_session_t *session, const uint8_t *data, size_t data_len) { } if (session->dtls_event >= 0) { - /* COAP_EVENT_DTLS_CLOSED event reported in coap_session_disconnected() */ + /* COAP_EVENT_DTLS_CLOSED event reported in coap_session_disconnected_lkd() */ if (session->dtls_event != COAP_EVENT_DTLS_CLOSED) coap_handle_event_lkd(session->context, session->dtls_event, session); if (session->dtls_event == COAP_EVENT_DTLS_ERROR || session->dtls_event == COAP_EVENT_DTLS_CLOSED) { - coap_session_disconnected(session, COAP_NACK_TLS_FAILED); + coap_session_disconnected_lkd(session, COAP_NACK_TLS_FAILED); r = -1; } } @@ -4007,12 +4007,12 @@ coap_tls_read(coap_session_t *session, uint8_t *data, size_t data_len) { } if (session->dtls_event >= 0) { - /* COAP_EVENT_DTLS_CLOSED event reported in coap_session_disconnected() */ + /* COAP_EVENT_DTLS_CLOSED event reported in coap_session_disconnected_lkd() */ if (session->dtls_event != COAP_EVENT_DTLS_CLOSED) coap_handle_event_lkd(session->context, session->dtls_event, session); if (session->dtls_event == COAP_EVENT_DTLS_ERROR || session->dtls_event == COAP_EVENT_DTLS_CLOSED) { - coap_session_disconnected(session, COAP_NACK_TLS_FAILED); + coap_session_disconnected_lkd(session, COAP_NACK_TLS_FAILED); r = -1; } } diff --git a/src/coap_oscore.c b/src/coap_oscore.c index 1c6c80e161..dc66010775 100644 --- a/src/coap_oscore.c +++ b/src/coap_oscore.c @@ -89,7 +89,7 @@ coap_new_client_session_oscore_lkd(coap_context_t *ctx, return NULL; if (coap_oscore_initiate(session, oscore_conf) == 0) { - coap_session_release(session); + coap_session_release_lkd(session); return NULL; } return session; @@ -127,7 +127,7 @@ coap_new_client_session_oscore_psk_lkd(coap_context_t *ctx, return NULL; if (coap_oscore_initiate(session, oscore_conf) == 0) { - coap_session_release(session); + coap_session_release_lkd(session); return NULL; } return session; @@ -165,7 +165,7 @@ coap_new_client_session_oscore_pki_lkd(coap_context_t *ctx, return NULL; if (coap_oscore_initiate(session, oscore_conf) == 0) { - coap_session_release(session); + coap_session_release_lkd(session); return NULL; } return session; @@ -752,9 +752,9 @@ coap_oscore_new_pdu_encrypted_lkd(coap_session_t *session, if (session->b_2_step != COAP_OSCORE_B_2_NONE && !session->done_b_1_2) { size_t size; - association->sent_pdu = coap_pdu_duplicate(pdu, session, - pdu_token.length, - pdu_token.s, NULL); + association->sent_pdu = coap_pdu_duplicate_lkd(pdu, session, + pdu_token.length, + pdu_token.s, NULL); if (association->sent_pdu == NULL) goto error; if (coap_get_data(pdu, &size, &data)) { @@ -1494,7 +1494,7 @@ coap_oscore_decrypt_pdu(coap_session_t *session, &pdu->actual_token); if (session->con_active) session->con_active--; - coap_send_ack(session, pdu); + coap_send_ack_lkd(session, pdu); if (sent_pdu) { coap_log_oscore("Appendix B.2 retransmit pdu\n"); if (coap_retransmit_oscore_pdu(session, sent_pdu, NULL) == @@ -1644,7 +1644,7 @@ coap_oscore_decrypt_pdu(coap_session_t *session, if (session->con_active) session->con_active--; if (sent_pdu) { - coap_send_ack(session, pdu); + coap_send_ack_lkd(session, pdu); coap_log_debug("PDU requesting re-transmit\n"); coap_show_pdu(COAP_LOG_DEBUG, decrypt_pdu); coap_log_oscore("RFC9175 retransmit pdu\n"); @@ -1659,7 +1659,7 @@ coap_oscore_decrypt_pdu(coap_session_t *session, return decrypt_pdu; error: - coap_send_ack(session, pdu); + coap_send_ack_lkd(session, pdu); error_no_ack: if (association && association->is_observe == 0) oscore_delete_association(session, association); diff --git a/src/coap_pdu.c b/src/coap_pdu.c index b8341e5100..e116a1abfd 100644 --- a/src/coap_pdu.c +++ b/src/coap_pdu.c @@ -169,7 +169,7 @@ coap_new_pdu_lkd(coap_pdu_type_t type, coap_pdu_code_t code, coap_lock_check_locked(session->context); pdu = coap_pdu_init(type, code, coap_new_message_id_lkd(session), - coap_session_max_pdu_size(session)); + coap_session_max_pdu_size_lkd(session)); if (!pdu) coap_log_crit("coap_new_pdu: cannot allocate memory for new PDU\n"); return pdu; @@ -188,21 +188,40 @@ coap_delete_pdu(coap_pdu_t *pdu) { } } -/* - * Note: This does not include any data, just the token and options - */ -coap_pdu_t * +COAP_API coap_pdu_t * coap_pdu_duplicate(const coap_pdu_t *old_pdu, coap_session_t *session, size_t token_length, const uint8_t *token, coap_opt_filter_t *drop_options) { + coap_pdu_t *new_pdu; + + coap_lock_lock(session->context, return NULL); + new_pdu = coap_pdu_duplicate_lkd(old_pdu, + session, + token_length, + token, + drop_options); + coap_lock_unlock(session->context); + return new_pdu; +} + + +/* + * Note: This does not include any data, just the token and options + */ +coap_pdu_t * +coap_pdu_duplicate_lkd(const coap_pdu_t *old_pdu, + coap_session_t *session, + size_t token_length, + const uint8_t *token, + coap_opt_filter_t *drop_options) { uint8_t doing_first = session->doing_first; coap_pdu_t *pdu; coap_lock_check_locked(session->context); /* - * Need to make sure that coap_session_max_pdu_size() immediately + * Need to make sure that coap_session_max_pdu_size_lkd() immediately * returns, rather than wait for the first CSM response from remote * that indicates BERT size (TCP/TLS only) as this may be called early * the OSCORE logic. @@ -211,7 +230,7 @@ coap_pdu_duplicate(const coap_pdu_t *old_pdu, pdu = coap_pdu_init(old_pdu->type, old_pdu->code, coap_new_message_id_lkd(session), max(old_pdu->max_size, - coap_session_max_pdu_size(session))); + coap_session_max_pdu_size_lkd(session))); /* Restore any pending waits */ session->doing_first = doing_first; if (pdu == NULL) diff --git a/src/coap_resource.c b/src/coap_resource.c index e452908acf..fe34acd183 100644 --- a/src/coap_resource.c +++ b/src/coap_resource.c @@ -489,7 +489,7 @@ coap_free_resource(coap_resource_t *resource) { if (resource->context->observe_deleted) resource->context->observe_deleted(obs->session, obs, resource->context->observe_user_data); - coap_session_release(obs->session); + coap_session_release_lkd(obs->session); coap_delete_pdu(obs->pdu); coap_delete_cache_key(obs->cache_key); coap_free_type(COAP_SUBSCRIPTION, obs); @@ -822,8 +822,8 @@ coap_add_observer(coap_resource_t *resource, } coap_subscription_init(s); - s->pdu = coap_pdu_duplicate(request, session, token->length, - token->s, NULL); + s->pdu = coap_pdu_duplicate_lkd(request, session, token->length, + token->s, NULL); if (s->pdu == NULL) { coap_delete_cache_key(cache_key); coap_free_type(COAP_SUBSCRIPTION, s); @@ -847,7 +847,7 @@ coap_add_observer(coap_resource_t *resource, } } s->cache_key = cache_key; - s->session = coap_session_reference(session); + s->session = coap_session_reference_lkd(session); /* add subscriber to resource */ LL_PREPEND(resource->subscribers, s); @@ -995,7 +995,7 @@ coap_delete_observer(coap_resource_t *resource, coap_session_t *session, if (resource->subscribers && s) { LL_DELETE(resource->subscribers, s); - coap_session_release(session); + coap_session_release_lkd(session); coap_delete_pdu(s->pdu); coap_delete_cache_key(s->cache_key); coap_free_type(COAP_SUBSCRIPTION, s); @@ -1014,7 +1014,7 @@ coap_delete_observers(coap_context_t *context, coap_session_t *session) { context->observe_deleted(session, s, context->observe_user_data); assert(resource->subscribers); LL_DELETE(resource->subscribers, s); - coap_session_release(session); + coap_session_release_lkd(session); coap_delete_pdu(s->pdu); coap_delete_cache_key(s->cache_key); coap_free_type(COAP_SUBSCRIPTION, s); @@ -1071,7 +1071,8 @@ coap_notify_observers(coap_context_t *context, coap_resource_t *r, coap_mid_t mid = COAP_INVALID_MID; obs->dirty = 0; /* initialize response */ - response = coap_pdu_init(COAP_MESSAGE_CON, 0, 0, coap_session_max_pdu_size(obs->session)); + response = coap_pdu_init(COAP_MESSAGE_CON, 0, 0, + coap_session_max_pdu_size_lkd(obs->session)); if (!response) { obs->dirty = 1; r->partiallydirty = 1; diff --git a/src/coap_session.c b/src/coap_session.c index d00ea534ec..e73ead2e66 100644 --- a/src/coap_session.c +++ b/src/coap_session.c @@ -344,15 +344,35 @@ coap_session_get_non_receive_timeout(const coap_session_t *session) { #endif /* ! COAP_Q_BLOCK_SUPPORT */ } -coap_session_t * +COAP_API coap_session_t * coap_session_reference(coap_session_t *session) { - coap_lock_check_locked(session->context); + coap_lock_lock(session->context, return NULL); + coap_session_reference_lkd(session); + coap_lock_unlock(session->context); + return session; +} + +coap_session_t * +coap_session_reference_lkd(coap_session_t *session) { ++session->ref; return session; } -void +COAP_API void coap_session_release(coap_session_t *session) { + if (session) { +#if COAP_THREAD_SAFE + coap_context_t *context = session->context; +#endif /* COAP_THREAD_SAFE */ + + coap_lock_lock(context, return); + coap_session_release_lkd(session); + coap_lock_unlock(context); + } +} + +void +coap_session_release_lkd(coap_session_t *session) { if (session) { coap_lock_check_locked(session->context); #ifndef __COVERITY__ @@ -554,7 +574,7 @@ coap_session_free(coap_session_t *session) { if (session->ref) return; /* Make sure nothing gets deleted under our feet */ - coap_session_reference(session); + coap_session_reference_lkd(session); coap_session_mfree(session); #if COAP_SERVER_SUPPORT if (session->endpoint) { @@ -610,8 +630,24 @@ coap_session_max_pdu_rcv_size(const coap_session_t *session) { (size_t)(session->mtu - session->tls_overhead)); } -size_t +COAP_API size_t coap_session_max_pdu_size(const coap_session_t *session) { + size_t size; + coap_session_t *session_rw; + + /* + * Need to do this to not get a compiler warning about const parameters + * but need to maintain source code backward compatibility + */ + memcpy(&session_rw, &session, sizeof(session_rw)); + coap_lock_lock(session_rw->context, return 0); + size = coap_session_max_pdu_size_lkd(session_rw); + coap_lock_unlock(session_rw->context); + return size; +} + +size_t +coap_session_max_pdu_size_lkd(const coap_session_t *session) { size_t max_with_header; coap_lock_check_locked(session->context); @@ -660,7 +696,7 @@ coap_session_delay_pdu(coap_session_t *session, coap_pdu_t *pdu, coap_queue_t *removed = NULL; coap_remove_from_queue(&session->context->sendqueue, session, node->id, &removed); assert(removed == node); - coap_session_release(node->session); + coap_session_release_lkd(node->session); node->session = NULL; node->t = 0; } else { @@ -720,14 +756,14 @@ coap_session_send_csm(coap_session_t *session) { buf) == 0) || coap_pdu_encode_header(pdu, session->proto) == 0 ) { - coap_session_disconnected(session, COAP_NACK_NOT_DELIVERABLE); + coap_session_disconnected_lkd(session, COAP_NACK_NOT_DELIVERABLE); } else { ssize_t bytes_written; pdu->session = session; bytes_written = coap_session_send_pdu(session, pdu); if (bytes_written != (ssize_t)pdu->used_size + pdu->hdr_size) { - coap_session_disconnected(session, COAP_NACK_NOT_DELIVERABLE); + coap_session_disconnected_lkd(session, COAP_NACK_NOT_DELIVERABLE); } else { session->csm_rcv_mtu = session->context->csm_max_message_size; if (session->csm_rcv_mtu > COAP_BERT_BASE) @@ -741,8 +777,18 @@ coap_session_send_csm(coap_session_t *session) { } #endif /* !COAP_DISABLE_TCP */ -coap_mid_t +COAP_API coap_mid_t coap_session_send_ping(coap_session_t *session) { + coap_mid_t mid; + + coap_lock_lock(session->context, return COAP_INVALID_MID); + mid = coap_session_send_ping_lkd(session); + coap_lock_unlock(session->context); + return mid; +} + +coap_mid_t +coap_session_send_ping_lkd(coap_session_t *session) { coap_pdu_t *ping = NULL; coap_lock_check_locked(session->context); @@ -852,8 +898,15 @@ coap_nack_name(coap_nack_reason_t reason) { } #endif /* COAP_MAX_LOGGING_LEVEL >= _COAP_LOG_DEBUG */ -void +COAP_API void coap_session_disconnected(coap_session_t *session, coap_nack_reason_t reason) { + coap_lock_lock(session->context, return); + coap_session_disconnected_lkd(session, reason); + coap_lock_unlock(session->context); +} + +void +coap_session_disconnected_lkd(coap_session_t *session, coap_nack_reason_t reason) { #if !COAP_DISABLE_TCP coap_session_state_t state = session->state; #endif /* !COAP_DISABLE_TCP */ @@ -1204,7 +1257,7 @@ coap_session_create_client(coap_context_t *ctx, if (!session) goto error; - coap_session_reference(session); + coap_session_reference_lkd(session); session->sock.session = session; memcpy(&session->sock.lfunc, coap_layers_coap[proto], sizeof(session->sock.lfunc)); @@ -1258,12 +1311,12 @@ coap_session_create_client(coap_context_t *ctx, error: /* - * Need to add in the session as coap_session_release() + * Need to add in the session as coap_session_release_lkd() * will call SESSIONS_DELETE in coap_session_free(). */ if (session) SESSIONS_ADD(ctx->sessions, session); - coap_session_release(session); + coap_session_release_lkd(session); return NULL; } @@ -1408,12 +1461,12 @@ coap_new_client_session_psk2_lkd(coap_context_t *ctx, setup_data->psk_info.identity.length); if (!session->psk_identity) { coap_log_warn("Cannot store session Identity (PSK)\n"); - coap_session_release(session); + coap_session_release_lkd(session); return NULL; } } else if (coap_dtls_is_supported() || coap_tls_is_supported()) { coap_log_warn("Identity (PSK) not defined\n"); - coap_session_release(session); + coap_session_release_lkd(session); return NULL; } @@ -1422,18 +1475,18 @@ coap_new_client_session_psk2_lkd(coap_context_t *ctx, setup_data->psk_info.key.length); if (!session->psk_key) { coap_log_warn("Cannot store session pre-shared key (PSK)\n"); - coap_session_release(session); + coap_session_release_lkd(session); return NULL; } } else if (coap_dtls_is_supported() || coap_tls_is_supported()) { coap_log_warn("Pre-shared key (PSK) not defined\n"); - coap_session_release(session); + coap_session_release_lkd(session); return NULL; } if (coap_dtls_is_supported() || coap_tls_is_supported()) { if (!coap_dtls_context_set_cpsk(ctx, setup_data)) { - coap_session_release(session); + coap_session_release_lkd(session); return NULL; } } @@ -1602,7 +1655,7 @@ coap_new_client_session_pki_lkd(coap_context_t *ctx, if (coap_dtls_is_supported() || coap_tls_is_supported()) { /* we know that setup_data is not NULL */ if (!coap_dtls_context_set_pki(ctx, setup_data, COAP_DTLS_ROLE_CLIENT)) { - coap_session_release(session); + coap_session_release_lkd(session); return NULL; } } @@ -1648,7 +1701,7 @@ coap_new_server_session(coap_context_t *ctx, coap_endpoint_t *ep, void *extra) { error: /* - * Need to add in the session as coap_session_release() + * Need to add in the session as coap_session_release_lkd() * will call SESSIONS_DELETE in coap_session_free(). */ if (session) { @@ -1749,7 +1802,7 @@ int coap_session_set_type_client(coap_session_t *session) { #if COAP_SERVER_SUPPORT if (session && session->type == COAP_SESSION_TYPE_SERVER) { - coap_session_reference(session); + coap_session_reference_lkd(session); session->type = COAP_SESSION_TYPE_CLIENT; return 1; } @@ -1916,7 +1969,7 @@ coap_new_endpoint_lkd(coap_context_t *context, const coap_address_t *listen_addr return ep; error: - coap_free_endpoint(ep); + coap_free_endpoint_lkd(ep); return NULL; } @@ -1925,8 +1978,22 @@ coap_endpoint_set_default_mtu(coap_endpoint_t *ep, unsigned mtu) { ep->default_mtu = (uint16_t)mtu; } -void +COAP_API void coap_free_endpoint(coap_endpoint_t *ep) { + if (ep) { + coap_context_t *context = ep->context; + if (context) { + coap_lock_lock(context, return); + } + coap_free_endpoint_lkd(ep); + if (context) { + coap_lock_unlock(context); + } + } +} + +void +coap_free_endpoint_lkd(coap_endpoint_t *ep) { if (ep) { coap_session_t *session, *rtmp; diff --git a/src/coap_subscribe.c b/src/coap_subscribe.c index 87216cad6b..b4e6e2d004 100644 --- a/src/coap_subscribe.c +++ b/src/coap_subscribe.c @@ -45,13 +45,33 @@ coap_persist_track_funcs(coap_context_t *context, context->resource_deleted = resource_deleted; } -coap_subscription_t * +COAP_API coap_subscription_t * coap_persist_observe_add(coap_context_t *context, coap_proto_t e_proto, const coap_address_t *e_listen_addr, const coap_addr_tuple_t *s_addr_info, const coap_bin_const_t *raw_packet, const coap_bin_const_t *oscore_info) { + coap_subscription_t *subs; + + coap_lock_lock(context, return NULL); + subs = coap_persist_observe_add_lkd(context, + e_proto, + e_listen_addr, + s_addr_info, + raw_packet, + oscore_info); + coap_lock_unlock(context); + return subs; +} + +coap_subscription_t * +coap_persist_observe_add_lkd(coap_context_t *context, + coap_proto_t e_proto, + const coap_address_t *e_listen_addr, + const coap_addr_tuple_t *s_addr_info, + const coap_bin_const_t *raw_packet, + const coap_bin_const_t *oscore_info) { coap_session_t *session = NULL; const uint8_t *data; size_t data_len; @@ -439,11 +459,11 @@ coap_op_observe_load_disk(coap_context_t *ctx) { &s_addr_info, &raw_packet, &oscore_info)) break; coap_log_debug("persist: New session/observe being created\n"); - observe_key = coap_persist_observe_add(ctx, e_proto, - &e_listen_addr, - &s_addr_info, - raw_packet, - oscore_info); + observe_key = coap_persist_observe_add_lkd(ctx, e_proto, + &e_listen_addr, + &s_addr_info, + raw_packet, + oscore_info); if (observe_key) { if (!coap_op_observe_write(fp_new, observe_key, e_proto, e_listen_addr, s_addr_info, raw_packet, oscore_info)) @@ -1114,12 +1134,30 @@ coap_op_resource_deleted(coap_context_t *context, return 0; } -int +COAP_API int coap_persist_startup(coap_context_t *context, const char *dyn_resource_save_file, const char *observe_save_file, const char *obs_cnt_save_file, uint32_t save_freq) { + int ret; + + coap_lock_lock(context, return 0); + ret = coap_persist_startup_lkd(context, + dyn_resource_save_file, + observe_save_file, + obs_cnt_save_file, + save_freq); + coap_lock_unlock(context); + return ret; +} + +int +coap_persist_startup_lkd(coap_context_t *context, + const char *dyn_resource_save_file, + const char *observe_save_file, + const char *obs_cnt_save_file, + uint32_t save_freq) { coap_lock_check_locked(context); if (dyn_resource_save_file) { context->dyn_resource_save_file = @@ -1169,8 +1207,17 @@ coap_persist_cleanup(coap_context_t *context) { NULL, 0, NULL); } -void +COAP_API void coap_persist_stop(coap_context_t *context) { + if (!context) + return; + coap_lock_lock(context, return); + coap_persist_stop_lkd(context); + coap_lock_unlock(context); +} + +void +coap_persist_stop_lkd(coap_context_t *context) { if (context == NULL) return; coap_lock_check_locked(context); @@ -1178,7 +1225,7 @@ coap_persist_stop(coap_context_t *context) { coap_persist_cleanup(context); } #else /* ! COAP_WITH_OBSERVE_PERSIST */ -int +COAP_API int coap_persist_startup(coap_context_t *context, const char *dyn_resource_save_file, const char *observe_save_file, @@ -1192,7 +1239,7 @@ coap_persist_startup(coap_context_t *context, return 0; } -void +COAP_API void coap_persist_stop(coap_context_t *context) { context->observe_no_clear = 1; /* Close down any tracking */ diff --git a/src/coap_threadsafe.c b/src/coap_threadsafe.c index fa06dec7e7..db99461449 100644 --- a/src/coap_threadsafe.c +++ b/src/coap_threadsafe.c @@ -10,302 +10,12 @@ /** * @file coap_threadsafe.c - * @brief CoAP multithreading safe functions + * @brief CoAP multithreading locking check functions */ -/* - * Public API functions are being migrated across to just ahead of where - * the _locked() functions are for ease of maintenance, debugging and - * documentation. - * - * The internal equivalent of the public API function will get _locked appended - * to the function name, and all calls to this function within the libcoap - * library have the function updated with the _locked suffix. Appropriate - * entries for this function are removed from coap_threadsafe_internal.h. - */ -#include "coap_config.h" +#include "coap3/coap_libcoap_build.h" #if COAP_THREAD_SAFE -#define COAP_THREAD_IGNORE_LOCKED_MAPPING - -#include "coap3/coap_internal.h" - -#if COAP_SERVER_SUPPORT - -/* Server only wrapper functions */ - -int -coap_context_set_pki(coap_context_t *ctx, - const coap_dtls_pki_t *setup_data) { - int ret; - - coap_lock_lock(ctx, return 0); - ret = coap_context_set_pki_locked(ctx, setup_data); - coap_lock_unlock(ctx); - return ret; -} - -int -coap_context_set_psk(coap_context_t *ctx, - const char *hint, - const uint8_t *key, - size_t key_len) { - int ret; - - coap_lock_lock(ctx, return 0); - ret = coap_context_set_psk_locked(ctx, hint, key, key_len); - coap_lock_unlock(ctx); - return ret; -} - -int -coap_context_set_psk2(coap_context_t *ctx, coap_dtls_spsk_t *setup_data) { - int ret; - - coap_lock_lock(ctx, return 0); - ret = coap_context_set_psk2_locked(ctx, setup_data); - coap_lock_unlock(ctx); - return ret; -} - -void -coap_free_endpoint(coap_endpoint_t *ep) { - if (ep) { - coap_context_t *context = ep->context; - if (context) - coap_lock_lock(context, return); - coap_free_endpoint_locked(ep); - if (context) - coap_lock_unlock(context); - } -} - -int -coap_join_mcast_group_intf(coap_context_t *ctx, const char *group_name, - const char *ifname) { - int ret; - - coap_lock_lock(ctx, return -1); - ret = coap_join_mcast_group_intf_locked(ctx, group_name, ifname); - coap_lock_unlock(ctx); - return ret; -} - -coap_subscription_t * -coap_persist_observe_add(coap_context_t *context, - coap_proto_t e_proto, - const coap_address_t *e_listen_addr, - const coap_addr_tuple_t *s_addr_info, - const coap_bin_const_t *raw_packet, - const coap_bin_const_t *oscore_info) { - coap_subscription_t *subs; - - coap_lock_lock(context, return NULL); - subs = coap_persist_observe_add_locked(context, - e_proto, - e_listen_addr, - s_addr_info, - raw_packet, - oscore_info); - coap_lock_unlock(context); - return subs; -} - -int -coap_persist_startup(coap_context_t *context, - const char *dyn_resource_save_file, - const char *observe_save_file, - const char *obs_cnt_save_file, - uint32_t save_freq) { - int ret; - - coap_lock_lock(context, return 0); - ret = coap_persist_startup_locked(context, - dyn_resource_save_file, - observe_save_file, - obs_cnt_save_file, - save_freq); - coap_lock_unlock(context); - return ret; -} - -void -coap_persist_stop(coap_context_t *context) { - if (!context) - return; - coap_lock_lock(context, return); - coap_persist_stop_locked(context); - coap_lock_unlock(context); -} - -#endif /* COAP_SERVER_SUPPORT */ - -/* Both Client and Server wrapper functions */ - -void -coap_context_set_block_mode(coap_context_t *context, - uint32_t block_mode) { - coap_lock_lock(context, return); - coap_context_set_block_mode_locked(context, block_mode); - coap_lock_unlock(context); -} - -int -coap_context_set_max_block_size(coap_context_t *context, - size_t max_block_size) { - int ret; - - coap_lock_lock(context, return 0); - ret = coap_context_set_max_block_size_locked(context, max_block_size); - coap_lock_unlock(context); - return ret; -} - -int -coap_context_set_pki_root_cas(coap_context_t *ctx, - const char *ca_file, - const char *ca_dir) { - int ret; - - coap_lock_lock(ctx, return 0); - ret = coap_context_set_pki_root_cas_locked(ctx, ca_file, ca_dir); - coap_lock_unlock(ctx); - return ret; -} - -coap_pdu_t * -coap_pdu_duplicate(const coap_pdu_t *old_pdu, - coap_session_t *session, - size_t token_length, - const uint8_t *token, - coap_opt_filter_t *drop_options) { - coap_pdu_t *new_pdu; - - coap_lock_lock(session->context, return NULL); - new_pdu = coap_pdu_duplicate_locked(old_pdu, - session, - token_length, - token, - drop_options); - coap_lock_unlock(session->context); - return new_pdu; -} - - -void -coap_register_option(coap_context_t *ctx, uint16_t type) { - coap_lock_lock(ctx, return); - coap_register_option_locked(ctx, type); - coap_lock_unlock(ctx); -} - -coap_mid_t -coap_send(coap_session_t *session, coap_pdu_t *pdu) { - coap_mid_t mid; - - coap_lock_lock(session->context, return COAP_INVALID_MID); - mid = coap_send_locked(session, pdu); - coap_lock_unlock(session->context); - return mid; -} - -coap_mid_t -coap_send_ack(coap_session_t *session, const coap_pdu_t *request) { - coap_mid_t mid; - - coap_lock_lock(session->context, return COAP_INVALID_MID); - mid = coap_send_ack_locked(session, request); - coap_lock_unlock(session->context); - return mid; -} - -coap_mid_t -coap_send_error(coap_session_t *session, - const coap_pdu_t *request, - coap_pdu_code_t code, - coap_opt_filter_t *opts) { - coap_mid_t mid; - - coap_lock_lock(session->context, return COAP_INVALID_MID); - mid = coap_send_error_locked(session, request, code, opts); - coap_lock_unlock(session->context); - return mid; -} - - -coap_mid_t -coap_send_message_type(coap_session_t *session, const coap_pdu_t *request, - coap_pdu_type_t type) { - coap_mid_t mid; - - coap_lock_lock(session->context, return COAP_INVALID_MID); - mid = coap_send_message_type_locked(session, request, type); - coap_lock_unlock(session->context); - return mid; -} - -coap_mid_t -coap_send_rst(coap_session_t *session, const coap_pdu_t *request) { - coap_mid_t mid; - - coap_lock_lock(session->context, return COAP_INVALID_MID); - mid = coap_send_rst_locked(session, request); - coap_lock_unlock(session->context); - return mid; -} - -void -coap_session_disconnected(coap_session_t *session, coap_nack_reason_t reason) { - coap_lock_lock(session->context, return); - coap_session_disconnected_locked(session, reason); - coap_lock_unlock(session->context); -} - -size_t -coap_session_max_pdu_size(const coap_session_t *session) { - size_t size; - coap_session_t *session_rw; - - /* - * Need to do this to not get a compiler warning about const parameters - * but need to maintain source code backward compatibility - */ - memcpy(&session_rw, &session, sizeof(session_rw)); - coap_lock_lock(session_rw->context, return 0); - size = coap_session_max_pdu_size_locked(session_rw); - coap_lock_unlock(session_rw->context); - return size; -} - -coap_session_t * -coap_session_reference(coap_session_t *session) { - coap_lock_lock(session->context, return NULL); - coap_session_reference_locked(session); - coap_lock_unlock(session->context); - return session; -} - -void -coap_session_release(coap_session_t *session) { - if (session) { - coap_context_t *context = session->context; - - coap_lock_lock(context, return); - coap_session_release_locked(session); - coap_lock_unlock(context); - } -} - -coap_mid_t -coap_session_send_ping(coap_session_t *session) { - coap_mid_t mid; - - coap_lock_lock(session->context, return COAP_INVALID_MID); - mid = coap_session_send_ping_locked(session); - coap_lock_unlock(session->context); - return mid; -} - #if COAP_THREAD_RECURSIVE_CHECK void coap_lock_unlock_func(coap_lock_t *lock, const char *file, int line) { diff --git a/src/coap_tinydtls.c b/src/coap_tinydtls.c index 1dd57cab1a..bf699374ec 100644 --- a/src/coap_tinydtls.c +++ b/src/coap_tinydtls.c @@ -786,13 +786,13 @@ coap_dtls_send(coap_session_t *session, coap_log_warn("coap_dtls_send: cannot send PDU\n"); if (coap_event_dtls >= 0) { - /* COAP_EVENT_DTLS_CLOSED event reported in coap_session_disconnected() */ + /* COAP_EVENT_DTLS_CLOSED event reported in coap_session_disconnected_lkd() */ if (coap_event_dtls != COAP_EVENT_DTLS_CLOSED) coap_handle_event_lkd(session->context, coap_event_dtls, session); if (coap_event_dtls == COAP_EVENT_DTLS_CONNECTED) coap_session_connected(session); else if (coap_event_dtls == COAP_EVENT_DTLS_CLOSED || coap_event_dtls == COAP_EVENT_DTLS_ERROR) - coap_session_disconnected(session, COAP_NACK_TLS_FAILED); + coap_session_disconnected_lkd(session, COAP_NACK_TLS_FAILED); } return res; @@ -855,13 +855,13 @@ coap_dtls_receive(coap_session_t *session, } if (coap_event_dtls >= 0) { - /* COAP_EVENT_DTLS_CLOSED event reported in coap_session_disconnected() */ + /* COAP_EVENT_DTLS_CLOSED event reported in coap_session_disconnected_lkd() */ if (coap_event_dtls != COAP_EVENT_DTLS_CLOSED) coap_handle_event_lkd(session->context, coap_event_dtls, session); if (coap_event_dtls == COAP_EVENT_DTLS_CONNECTED) coap_session_connected(session); else if (coap_event_dtls == COAP_EVENT_DTLS_CLOSED || coap_event_dtls == COAP_EVENT_DTLS_ERROR) { - coap_session_disconnected(session, COAP_NACK_TLS_FAILED); + coap_session_disconnected_lkd(session, COAP_NACK_TLS_FAILED); err = -1; } } diff --git a/src/coap_wolfssl.c b/src/coap_wolfssl.c index 4960fd181d..e62cade802 100644 --- a/src/coap_wolfssl.c +++ b/src/coap_wolfssl.c @@ -2122,12 +2122,12 @@ coap_dtls_send(coap_session_t *session, } if (session->dtls_event >= 0) { - /* COAP_EVENT_DTLS_CLOSED event reported in coap_session_disconnected() */ + /* COAP_EVENT_DTLS_CLOSED event reported in coap_session_disconnected_lkd() */ if (session->dtls_event != COAP_EVENT_DTLS_CLOSED) coap_handle_event_lkd(session->context, session->dtls_event, session); if (session->dtls_event == COAP_EVENT_DTLS_ERROR || session->dtls_event == COAP_EVENT_DTLS_CLOSED) { - coap_session_disconnected(session, COAP_NACK_TLS_FAILED); + coap_session_disconnected_lkd(session, COAP_NACK_TLS_FAILED); r = -1; } } @@ -2177,7 +2177,7 @@ coap_dtls_handle_timeout(coap_session_t *session) { w_env->retry_scalar++; if (++session->dtls_timeout_count > session->max_retransmit) { /* Too many retries */ - coap_session_disconnected(session, COAP_NACK_TLS_FAILED); + coap_session_disconnected_lkd(session, COAP_NACK_TLS_FAILED); return 1; } wolfSSL_dtls_retransmit(ssl); @@ -2285,12 +2285,12 @@ coap_dtls_receive(coap_session_t *session, const uint8_t *data, size_t data_len) r = -1; } if (session->dtls_event >= 0) { - /* COAP_EVENT_DTLS_CLOSED event reported in coap_session_disconnected() */ + /* COAP_EVENT_DTLS_CLOSED event reported in coap_session_disconnected_lkd() */ if (session->dtls_event != COAP_EVENT_DTLS_CLOSED) coap_handle_event_lkd(session->context, session->dtls_event, session); if (session->dtls_event == COAP_EVENT_DTLS_ERROR || session->dtls_event == COAP_EVENT_DTLS_CLOSED) { - coap_session_disconnected(session, COAP_NACK_TLS_FAILED); + coap_session_disconnected_lkd(session, COAP_NACK_TLS_FAILED); ssl_data = NULL; r = -1; } @@ -2630,12 +2630,12 @@ coap_tls_write(coap_session_t *session, const uint8_t *data, size_t data_len) { } if (session->dtls_event >= 0) { - /* COAP_EVENT_DTLS_CLOSED event reported in coap_session_disconnected() */ + /* COAP_EVENT_DTLS_CLOSED event reported in coap_session_disconnected_lkd() */ if (session->dtls_event != COAP_EVENT_DTLS_CLOSED) coap_handle_event_lkd(session->context, session->dtls_event, session); if (session->dtls_event == COAP_EVENT_DTLS_ERROR || session->dtls_event == COAP_EVENT_DTLS_CLOSED) { - coap_session_disconnected(session, COAP_NACK_TLS_FAILED); + coap_session_disconnected_lkd(session, COAP_NACK_TLS_FAILED); r = -1; } } @@ -2720,12 +2720,12 @@ coap_tls_read(coap_session_t *session, uint8_t *data, size_t data_len) { } if (session->dtls_event >= 0) { - /* COAP_EVENT_DTLS_CLOSED event reported in coap_session_disconnected() */ + /* COAP_EVENT_DTLS_CLOSED event reported in coap_session_disconnected_lkd() */ if (session->dtls_event != COAP_EVENT_DTLS_CLOSED) coap_handle_event_lkd(session->context, session->dtls_event, session); if (session->dtls_event == COAP_EVENT_DTLS_ERROR || session->dtls_event == COAP_EVENT_DTLS_CLOSED) { - coap_session_disconnected(session, COAP_NACK_TLS_FAILED); + coap_session_disconnected_lkd(session, COAP_NACK_TLS_FAILED); r = -1; } } diff --git a/src/coap_ws.c b/src/coap_ws.c index 7e08939d2b..9d7f4f6cb5 100644 --- a/src/coap_ws.c +++ b/src/coap_ws.c @@ -209,7 +209,7 @@ coap_ws_write(coap_session_t *session, const uint8_t *data, size_t datalen) { if (!session->ws) { session->ws = coap_malloc_type(COAP_STRING, sizeof(coap_ws_state_t)); if (!session->ws) { - coap_session_disconnected(session, COAP_NACK_WS_LAYER_FAILED); + coap_session_disconnected_lkd(session, COAP_NACK_WS_LAYER_FAILED); return -1; } memset(session->ws, 0, sizeof(coap_ws_state_t)); @@ -579,7 +579,7 @@ coap_ws_read(coap_session_t *session, uint8_t *data, size_t datalen) { if (!session->ws) { session->ws = coap_malloc_type(COAP_STRING, sizeof(coap_ws_state_t)); if (!session->ws) { - coap_session_disconnected(session, COAP_NACK_WS_LAYER_FAILED); + coap_session_disconnected_lkd(session, COAP_NACK_WS_LAYER_FAILED); return -1; } memset(session->ws, 0, sizeof(coap_ws_state_t)); @@ -595,7 +595,7 @@ coap_ws_read(coap_session_t *session, uint8_t *data, size_t datalen) { session->sock.lfunc[COAP_LAYER_WS].l_write(session, (uint8_t *)buf, strlen(buf)); } - coap_session_disconnected(session, COAP_NACK_WS_LAYER_FAILED); + coap_session_disconnected_lkd(session, COAP_NACK_WS_LAYER_FAILED); return -1; } @@ -793,7 +793,7 @@ coap_ws_establish(coap_session_t *session) { if (!session->ws) { session->ws = coap_malloc_type(COAP_STRING, sizeof(coap_ws_state_t)); if (!session->ws) { - coap_session_disconnected(session, COAP_NACK_WS_LAYER_FAILED); + coap_session_disconnected_lkd(session, COAP_NACK_WS_LAYER_FAILED); return; } memset(session->ws, 0, sizeof(coap_ws_state_t)); @@ -807,7 +807,7 @@ coap_ws_establish(coap_session_t *session) { session->ws->state = COAP_SESSION_TYPE_CLIENT; if (!session->ws_host) { coap_log_err("WS Host not defined\n"); - coap_session_disconnected(session, COAP_NACK_WS_LAYER_FAILED); + coap_session_disconnected_lkd(session, COAP_NACK_WS_LAYER_FAILED); return; } coap_prng(session->ws->key, sizeof(session->ws->key)); diff --git a/src/oscore/oscore_context.c b/src/oscore/oscore_context.c index a0b024e0d0..4dd727c536 100644 --- a/src/oscore/oscore_context.c +++ b/src/oscore/oscore_context.c @@ -705,8 +705,8 @@ oscore_new_association(coap_session_t *session, size_t size; const uint8_t *data; - association->sent_pdu = coap_pdu_duplicate(sent_pdu, session, - token->length, token->s, NULL); + association->sent_pdu = coap_pdu_duplicate_lkd(sent_pdu, session, + token->length, token->s, NULL); if (association->sent_pdu == NULL) goto error; if (coap_get_data(sent_pdu, &size, &data)) { diff --git a/tests/test_common.h.in b/tests/test_common.h.in index 622bf9fbe5..b8d299a6c9 100644 --- a/tests/test_common.h.in +++ b/tests/test_common.h.in @@ -8,7 +8,4 @@ * README for terms of use. */ -/* We need to treat these tests as being an user application */ -#define COAP_THREAD_IGNORE_LOCKED_MAPPING - #include "coap@LIBCOAP_API_VERSION@/coap_internal.h"