1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00

net/gcoap: support DTLS

This commit is contained in:
János Brodbeck 2021-01-28 10:21:37 +01:00
parent 5567f13258
commit 23a8659bdf
No known key found for this signature in database
GPG Key ID: 65C193B0D8D1BCE6
5 changed files with 440 additions and 20 deletions

View File

@ -32,6 +32,7 @@ PSEUDOMODULES += event_timeout_ztimer
PSEUDOMODULES += evtimer_mbox
PSEUDOMODULES += evtimer_on_ztimer
PSEUDOMODULES += fmt_%
PSEUDOMODULES += gcoap_dtls
PSEUDOMODULES += gnrc_dhcpv6_%
PSEUDOMODULES += gnrc_dhcpv6_client_mud_url
PSEUDOMODULES += gnrc_ipv6_default

View File

@ -501,6 +501,15 @@ ifneq (,$(filter l2filter_%,$(USEMODULE)))
USEMODULE += l2filter
endif
ifneq (,$(filter gcoap_dtls,$(USEMODULE)))
USEMODULE += gcoap
USEMODULE += dsm
USEMODULE += sock_async_event
USEMODULE += sock_dtls
USEMODULE += event_thread
USEMODULE += event_timeout
endif
ifneq (,$(filter gcoap,$(USEMODULE)))
USEMODULE += nanocoap
USEMODULE += sock_async_event

View File

@ -38,6 +38,7 @@
* - Observe Server Operation
* - Block Operation
* - Proxy Operation
* - DTLS for transport security
* - Implementation Notes
* - Implementation Status
*
@ -338,6 +339,22 @@
*
* Not implemented yet.
*
* ## DTLS as transport security ##
*
* Gcoap allows to use DTLS for transport security by using the @ref net_sock_dtls
* "DTLS sock API". Using the module gcoap_dtls enables the support. Gcoap
* listens for requests on CONFIG_GCOAPS_PORT, 5684 by default when DTLS is enabled.
*
* Credentials have to been configured before use. See @ref net_credman "Credman"
* and @ref net_sock_dtls_creds "DTLS sock credentials API" for credential managing.
* Access to the DTLS socket is provided by gcoap_get_sock_dtls().
*
* Gcoap includes a DTLS session management component that stores active sessions.
* By default, it tries to have CONFIG_GCOAP_DTLS_MINIMUM_AVAILABLE_SESSIONS
* session slots available to keep the server responsive. If not enough sessions
* are available the server destroys the session that has not been used for the
* longest time after CONFIG_GCOAP_DTLS_MINIMUM_AVAILABLE_SESSIONS_TIMEOUT_USEC.
*
* ## Implementation Notes ##
*
* ### Waiting for a response ###
@ -384,6 +401,9 @@
#include "event/timeout.h"
#include "net/ipv6/addr.h"
#include "net/sock/udp.h"
#if IS_USED(MODULE_GCOAP_DTLS)
#include "net/sock/dtls.h"
#endif
#include "net/nanocoap.h"
#include "xtimer.h"
@ -403,6 +423,36 @@ extern "C" {
#ifndef CONFIG_GCOAP_PORT
#define CONFIG_GCOAP_PORT (5683)
#endif
/**
* @brief Secure Server port; use RFC 7252 default if not defined
*/
#ifndef CONFIG_GCOAPS_PORT
#define CONFIG_GCOAPS_PORT (5684)
#endif
/**
* @brief Timeout for the DTLS handshake process. Set to 0 for infinite time
*/
#ifndef CONFIG_GCOAP_DTLS_HANDSHAKE_TIMEOUT_USEC
#define CONFIG_GCOAP_DTLS_HANDSHAKE_TIMEOUT_USEC (3 * US_PER_SEC)
#endif
/**
* @brief Number of minimum available sessions. If the count of available
* sessions falls below this threshold, the oldest used session will be
* closed after a timeout time. Set to 0 to deactivate this feature.
*/
#ifndef CONFIG_GCOAP_DTLS_MINIMUM_AVAILABLE_SESSIONS
#define CONFIG_GCOAP_DTLS_MINIMUM_AVAILABLE_SESSIONS (1)
#endif
/**
* @brief Timeout for freeing up a session when minimum number of available
* sessions is not given.
*/
#ifndef CONFIG_GCOAP_DTLS_MINIMUM_AVAILABLE_SESSIONS_TIMEOUT_USEC
#define CONFIG_GCOAP_DTLS_MINIMUM_AVAILABLE_SESSIONS_TIMEOUT_USEC (15 * US_PER_SEC)
#endif
/**
* @brief Size of the buffer used to build a CoAP request or response
@ -565,12 +615,20 @@ extern "C" {
/**
* @brief Stack size for module thread
* @{
*/
#ifndef GCOAP_STACK_SIZE
#define GCOAP_STACK_SIZE (THREAD_STACKSIZE_DEFAULT + DEBUG_EXTRA_STACKSIZE \
+ sizeof(coap_pkt_t))
#if IS_USED(MODULE_GCOAP_DTLS)
#define GCOAP_DTLS_EXTRA_STACKSIZE (THREAD_STACKSIZE_DEFAULT)
#else
#define GCOAP_DTLS_EXTRA_STACKSIZE (0)
#endif
#define GCOAP_STACK_SIZE (THREAD_STACKSIZE_DEFAULT + DEBUG_EXTRA_STACKSIZE \
+ sizeof(coap_pkt_t) + GCOAP_DTLS_EXTRA_STACKSIZE)
#endif
/** @} */
/**
* @ingroup net_gcoap_conf
* @brief Count of PDU buffers available for resending confirmable messages
@ -586,6 +644,7 @@ extern "C" {
*/
#define COAP_LINK_FLAG_INIT_RESLIST (1) /**< initialize as for first resource
* in a list */
/** @} */
/**
@ -719,6 +778,33 @@ typedef struct {
unsigned token_len; /**< Actual length of token attribute */
} gcoap_observe_memo_t;
/**
* @brief Coap socket types
*/
typedef enum {
COAP_SOCKET_TYPE_UNDEF = 0,
COAP_SOCKET_TYPE_UDP,
COAP_SOCKET_TYPE_DTLS
} coap_socket_type_t;
/**
* @brief Coap socket to handle multiple transport types
*/
typedef struct {
coap_socket_type_t type; /**< Type of stored socket */
union {
sock_udp_t *udp;
#if IS_USED(MODULE_GCOAP_DTLS) || defined(DOXYGEN)
sock_dtls_t *dtls;
#endif
} socket; /**< Stored socket */
#if IS_USED(MODULE_GCOAP_DTLS) || defined(DOXYGEN)
sock_dtls_session_t ctx_dtls_session; /**< Session object for the stored socket.
Used for exchanging a session between
functions. */
#endif
} coap_socket_t;
/**
* @brief Initializes the gcoap thread and device
*
@ -798,6 +884,7 @@ static inline ssize_t gcoap_request(coap_pkt_t *pdu, uint8_t *buf, size_t len,
* @param[in] context User defined context passed to the response handler
*
* @return length of the packet
* @return -ENOTCONN, if DTLS was used and session establishment failed
* @return 0 if cannot send
*/
ssize_t gcoap_req_send(const uint8_t *buf, size_t len,
@ -917,6 +1004,17 @@ int gcoap_get_resource_list(void *buf, size_t maxlen, uint8_t cf);
ssize_t gcoap_encode_link(const coap_resource_t *resource, char *buf,
size_t maxlen, coap_link_encoder_ctx_t *context);
#if IS_USED(MODULE_GCOAP_DTLS) || defined(DOXYGEN)
/**
* @brief Get the underlying DTLS socket of gcoap.
*
* Useful for managing credentials of gcoap.
*
* @return pointer to the @ref sock_dtls_t object
*/
sock_dtls_t *gcoap_get_sock_dtls(void);
#endif
#ifdef __cplusplus
}
#endif

View File

@ -13,6 +13,42 @@ menuconfig KCONFIG_USEMODULE_GCOAP
if KCONFIG_USEMODULE_GCOAP
menu "DTLS options"
config GCOAP_DTLS_CREDENTIAL_TAG
int "Credential tag"
default 5
range 0 65535
help
DTLS credential tag to determine, which credential to use for
authentication.
config GCOAP_DTLS_HANDSHAKE_TIMEOUT_USEC
int "DTLS handshake timeout in microseconds"
default 4000000
help
Time, expressed in microseconds, that the DTLS send function waits for
a handshake process and the send process itself to complete.
config GCOAP_DTLS_MINIMUM_AVAILABLE_SESSIONS
int "Minimum number of available sessions"
default 1
help
Number of sessions that should be kept free. If the count of free
sessions falls below this threshold, oldest used sessions will be closed
after a timeout time.
config GCOAP_DTLS_MINIMUM_AVAILABLE_SESSIONS_TIMEOUT_USEC
int "DTLS session slot automatic free up timeout in microseconds"
default 3000000
help
Time, expressed in microseconds. When the last session slot is occupied
this time indicates when a session will be freed up automatically.
Prevents that the server can be blocked by lack of available session
slots and not properly closed sessions.
endmenu # DTLS options
config GCOAP_PDU_BUF_SIZE
int "Request or response buffer size"
default 128
@ -91,6 +127,13 @@ config GCOAP_PORT
help
Server port, the default is the one specified in RFC 7252.
config GCOAPS_PORT
int "Secured server port"
default 5684
help
Server port for secured connections, the default is the one specified in
RFC 7252.
config GCOAP_REQ_WAITING_MAX
int "Maximum awaiting requests"
default 2

View File

@ -33,6 +33,12 @@
#include "random.h"
#include "thread.h"
#if IS_USED(MODULE_GCOAP_DTLS)
#include "net/sock/dtls.h"
#include "net/credman.h"
#include "net/dsm.h"
#endif
#define ENABLE_DEBUG 0
#include "debug.h"
@ -44,9 +50,14 @@
/* Internal functions */
static void *_event_loop(void *arg);
static void _on_sock_evt(sock_udp_t *sock, sock_async_flags_t type, void *arg);
static void _process_coap_pdu(sock_udp_t *sock, sock_udp_ep_t *remote,
static void _on_sock_udp_evt(sock_udp_t *sock, sock_async_flags_t type, void *arg);
static void _process_coap_pdu(coap_socket_t *sock, sock_udp_ep_t *remote,
uint8_t *buf, size_t len);
static void _tl_init_coap_socket(coap_socket_t *sock);
static ssize_t _tl_send(coap_socket_t *sock, const void *data, size_t len,
const sock_udp_ep_t *remote);
static ssize_t _tl_authenticate(coap_socket_t *sock, const sock_udp_ep_t *remote,
uint32_t timeout);
static ssize_t _well_known_core_handler(coap_pkt_t* pdu, uint8_t *buf, size_t len, void *ctx);
static void _cease_retransmission(gcoap_request_memo_t *memo);
static size_t _handle_req(coap_pkt_t *pdu, uint8_t *buf, size_t len,
@ -67,6 +78,11 @@ static int _request_matcher_default(gcoap_listener_t *listener,
const coap_resource_t **resource,
const coap_pkt_t *pdu);
#if IS_USED(MODULE_GCOAP_DTLS)
static void _on_sock_dtls_evt(sock_dtls_t *sock, sock_async_flags_t type, void *arg);
static void _dtls_free_up_session(void *arg);
#endif
/* Internal variables */
const coap_resource_t _default_resources[] = {
{ "/.well-known/core", COAP_GET, _well_known_core_handler, NULL },
@ -110,6 +126,17 @@ static event_queue_t _queue;
static uint8_t _listen_buf[CONFIG_GCOAP_PDU_BUF_SIZE];
static sock_udp_t _sock_udp;
#if IS_USED(MODULE_GCOAP_DTLS)
/* DTLS variables and definitions */
#define SOCK_DTLS_CLIENT_TAG (2)
static sock_dtls_t _sock_dtls;
static kernel_pid_t _auth_waiting_thread;
static event_timeout_t _dtls_session_free_up_tmout;
static event_callback_t _dtls_session_free_up_tmout_cb;
#endif
/* Event loop for gcoap _pid thread. */
static void *_event_loop(void *arg)
{
@ -119,8 +146,11 @@ static void *_event_loop(void *arg)
memset(&local, 0, sizeof(sock_udp_ep_t));
local.family = AF_INET6;
local.netif = SOCK_ADDR_ANY_NETIF;
local.port = CONFIG_GCOAP_PORT;
if (IS_USED(MODULE_GCOAP_DTLS)) {
local.port = CONFIG_GCOAPS_PORT;
} else {
local.port = CONFIG_GCOAP_PORT;
}
int res = sock_udp_create(&_sock_udp, &local, NULL, 0);
if (res < 0) {
DEBUG("gcoap: cannot create sock: %d\n", res);
@ -128,14 +158,127 @@ static void *_event_loop(void *arg)
}
event_queue_init(&_queue);
sock_udp_event_init(&_sock_udp, &_queue, _on_sock_evt, NULL);
event_loop(&_queue);
if (IS_USED(MODULE_GCOAP_DTLS)) {
#if IS_USED(MODULE_GCOAP_DTLS)
if (sock_dtls_create(&_sock_dtls, &_sock_udp,
CREDMAN_TAG_EMPTY,
SOCK_DTLS_1_2, SOCK_DTLS_SERVER) < 0) {
DEBUG("gcoap: error creating DTLS sock");
sock_udp_close(&_sock_udp);
return 0;
}
sock_dtls_event_init(&_sock_dtls, &_queue, _on_sock_dtls_evt,
NULL);
#endif
} else {
sock_udp_event_init(&_sock_udp, &_queue, _on_sock_udp_evt, NULL);
}
event_loop(&_queue);
return 0;
}
#if IS_USED(MODULE_GCOAP_DTLS)
/* Handles DTLS socket events from the event queue */
static void _on_sock_dtls_evt(sock_dtls_t *sock, sock_async_flags_t type, void *arg) {
(void)arg;
coap_socket_t socket = { .type = COAP_SOCKET_TYPE_DTLS, .socket.dtls = sock};
if (type & SOCK_ASYNC_CONN_RECV) {
ssize_t res = sock_dtls_recv(sock, &socket.ctx_dtls_session,
_listen_buf, sizeof(_listen_buf),
CONFIG_GCOAP_DTLS_HANDSHAKE_TIMEOUT_USEC);
if (res != -SOCK_DTLS_HANDSHAKE) {
DEBUG("gcoap: could not establish DTLS session: %zd\n", res);
sock_dtls_session_destroy(sock, &socket.ctx_dtls_session);
return;
}
dsm_state_t prev_state = dsm_store(sock, &socket.ctx_dtls_session,
SESSION_STATE_ESTABLISHED, false);
/* If session is already stored and the state was SESSION_STATE_HANDSHAKE
before, the handshake has been initiated internally by a gcoap client request
and another thread is waiting for the handshake. Send message to the
waiting thread to inform about established session */
if (prev_state == SESSION_STATE_HANDSHAKE) {
msg_t msg = { .type = DTLS_EVENT_CONNECTED };
msg_send(&msg, _auth_waiting_thread);
} else if (prev_state == NO_SPACE) {
/* No space in session management. Should not happen. If it occurs,
we lost track of sessions */
DEBUG("gcoap: no space in session management. We lost track of sessions!")
sock_dtls_session_destroy(sock, &socket.ctx_dtls_session);
}
/* If not enough session slots left: set timeout to free up session */
uint8_t minimum_free = CONFIG_GCOAP_DTLS_MINIMUM_AVAILABLE_SESSIONS;
if (dsm_get_num_available_slots() < minimum_free)
{
uint32_t timeout = CONFIG_GCOAP_DTLS_MINIMUM_AVAILABLE_SESSIONS_TIMEOUT_USEC;
event_callback_init(&_dtls_session_free_up_tmout_cb,
_dtls_free_up_session, NULL);
event_timeout_init(&_dtls_session_free_up_tmout, &_queue,
&_dtls_session_free_up_tmout_cb.super);
event_timeout_set(&_dtls_session_free_up_tmout, timeout);
}
}
if (type & SOCK_ASYNC_CONN_FIN) {
if (sock_dtls_get_event_session(sock, &socket.ctx_dtls_session)) {
/* Session is already destroyed, only remove it from dsm */
dsm_remove(sock, &socket.ctx_dtls_session);
} else {
puts("gcoap: A session was closed, but the corresponding session " \
"could not be retrieved from the socket!");
return;
}
sock_udp_ep_t ep;
sock_dtls_session_get_udp_ep(&socket.ctx_dtls_session, &ep);
/* Remove all memos of the concerned session. TODO: oberservable memos! */
for (int i = 0; i < CONFIG_GCOAP_REQ_WAITING_MAX; i++) {
if (_coap_state.open_reqs[i].state == GCOAP_MEMO_UNUSED) {
continue;
}
gcoap_request_memo_t *memo = &_coap_state.open_reqs[i];
if (sock_udp_ep_equal(&memo->remote_ep, &ep)) {
_expire_request(memo);
event_timeout_clear(&memo->resp_evt_tmout);
}
}
}
if (type & SOCK_ASYNC_MSG_RECV) {
ssize_t res = sock_dtls_recv(sock, &socket.ctx_dtls_session, _listen_buf,
sizeof(_listen_buf), 0);
if (res <= 0) {
DEBUG("gcoap: DTLS recv failure: %d\n", (int)res);
return;
}
sock_udp_ep_t ep;
sock_dtls_session_get_udp_ep(&socket.ctx_dtls_session, &ep);
_process_coap_pdu(&socket, &ep, _listen_buf, res);
}
}
/* Timeout function to free up a session when too many session slots are occupied */
static void _dtls_free_up_session(void *arg) {
(void)arg;
sock_dtls_session_t session;
uint8_t minimum_free = CONFIG_GCOAP_DTLS_MINIMUM_AVAILABLE_SESSIONS;
if (dsm_get_num_available_slots() < minimum_free) {
if (dsm_get_least_recently_used_session(&_sock_dtls, &session) != -1) {
/* free up session */
dsm_remove(&_sock_dtls, &session);
sock_dtls_session_destroy(&_sock_dtls, &session);
}
}
}
#endif /* MODULE_GCOAP_DTLS */
/* Handles UDP socket events from the event queue. */
static void _on_sock_evt(sock_udp_t *sock, sock_async_flags_t type, void *arg)
static void _on_sock_udp_evt(sock_udp_t *sock, sock_async_flags_t type, void *arg)
{
(void)arg;
sock_udp_ep_t remote;
@ -147,12 +290,13 @@ static void _on_sock_evt(sock_udp_t *sock, sock_async_flags_t type, void *arg)
DEBUG("gcoap: udp recv failure: %d\n", (int)res);
return;
}
_process_coap_pdu(sock, &remote, _listen_buf, res);
coap_socket_t socket = { .type = COAP_SOCKET_TYPE_UDP, .socket.udp = sock };
_process_coap_pdu(&socket, &remote, _listen_buf, res);
}
}
/* Processes and evaluates the coap pdu */
static void _process_coap_pdu(sock_udp_t *sock, sock_udp_ep_t *remote,
static void _process_coap_pdu(coap_socket_t *sock, sock_udp_ep_t *remote,
uint8_t *buf, size_t len)
{
coap_pkt_t pdu;
@ -201,7 +345,7 @@ static void _process_coap_pdu(sock_udp_t *sock, sock_udp_ep_t *remote,
size_t pdu_len = _handle_req(&pdu, _listen_buf, sizeof(_listen_buf),
remote);
if (pdu_len > 0) {
ssize_t bytes = sock_udp_send(sock, _listen_buf, pdu_len,
ssize_t bytes = _tl_send(sock, _listen_buf, pdu_len,
remote);
if (bytes <= 0) {
DEBUG("gcoap: send response failed: %d\n", (int)bytes);
@ -262,7 +406,7 @@ static void _process_coap_pdu(sock_udp_t *sock, sock_udp_ep_t *remote,
* */
pdu.hdr->ver_t_tkl &= 0xf0;
ssize_t bytes = sock_udp_send(sock, buf,
ssize_t bytes = _tl_send(sock, buf,
sizeof(coap_hdr_t), remote);
if (bytes <= 0) {
DEBUG("gcoap: empty response failed: %d\n", (int)bytes);
@ -299,8 +443,10 @@ static void _on_resp_timeout(void *arg) {
return;
}
ssize_t bytes = sock_udp_send(&_sock_udp, memo->msg.data.pdu_buf,
memo->msg.data.pdu_len, &memo->remote_ep);
coap_socket_t socket;
_tl_init_coap_socket(&socket);
ssize_t bytes = _tl_send(&socket, memo->msg.data.pdu_buf,
memo->msg.data.pdu_len, &memo->remote_ep);
if (bytes <= 0) {
DEBUG("gcoap: sock resend failed: %d\n", (int)bytes);
_expire_request(memo);
@ -732,6 +878,109 @@ static void _find_obs_memo_resource(gcoap_observe_memo_t **memo,
}
}
/*
* Transport layer functions
*/
static void _tl_init_coap_socket(coap_socket_t *sock)
{
#if IS_USED(MODULE_GCOAP_DTLS)
sock->type = COAP_SOCKET_TYPE_DTLS;
sock->socket.dtls = &_sock_dtls;
#else
sock->type = COAP_SOCKET_TYPE_UDP;
sock->socket.udp = &_sock_udp;
#endif
}
static ssize_t _tl_send(coap_socket_t *sock, const void *data, size_t len,
const sock_udp_ep_t *remote)
{
ssize_t res = -1;
if (sock->type == COAP_SOCKET_TYPE_DTLS) {
#if IS_USED(MODULE_GCOAP_DTLS)
/* prepare session */
sock_dtls_session_set_udp_ep(&sock->ctx_dtls_session, remote);
dsm_state_t session_state = dsm_store(sock->socket.dtls, &sock->ctx_dtls_session,
SESSION_STATE_HANDSHAKE, true);
if (session_state == NO_SPACE) {
return -1;
}
/* send application data */
res = sock_dtls_send(sock->socket.dtls, &sock->ctx_dtls_session, data, len,
SOCK_NO_TIMEOUT);
if (res <= 0 ) {
dsm_remove(sock->socket.dtls, &sock->ctx_dtls_session);
sock_dtls_session_destroy(sock->socket.dtls, &sock->ctx_dtls_session);
}
#endif
} else if (sock->type == COAP_SOCKET_TYPE_UDP) {
res = sock_udp_send(sock->socket.udp, data, len, remote);
} else {
DEBUG("gcoap: undefined socket type\n");
}
return res;
}
static ssize_t _tl_authenticate(coap_socket_t *sock, const sock_udp_ep_t *remote,
uint32_t timeout)
{
#if !IS_USED(MODULE_GCOAP_DTLS)
(void)sock;
(void)remote;
(void)timeout;
return 0;
#else
int res;
/* prepare session */
sock_dtls_session_set_udp_ep(&sock->ctx_dtls_session, remote);
dsm_state_t session_state = dsm_store(sock->socket.dtls, &sock->ctx_dtls_session,
SESSION_STATE_HANDSHAKE, true);
if (session_state == SESSION_STATE_ESTABLISHED) {
return 0;
}
if (session_state == NO_SPACE) {
DEBUG("gcoap: no space in dsm\n")
return -ENOTCONN;
}
/* start handshake */
_auth_waiting_thread = thread_getpid();
res = sock_dtls_session_init(sock->socket.dtls, remote, &sock->ctx_dtls_session);
if (res == 0) {
/* session already exists */
_auth_waiting_thread = -1;
return res;
}
msg_t msg;
bool is_timed_out = false;
do {
uint32_t start = xtimer_now_usec();
res = xtimer_msg_receive_timeout(&msg, timeout);
/* ensure whole timeout time for the case we receive other messages than DTLS_EVENT_CONNECTED */
if (timeout != SOCK_NO_TIMEOUT) {
uint32_t diff = (xtimer_now_usec() - start);
timeout = (diff > timeout) ? 0: timeout - diff;
is_timed_out = (res < 0) || (timeout == 0);
}
}
while (!is_timed_out && (msg.type != DTLS_EVENT_CONNECTED));
if (is_timed_out && (msg.type != DTLS_EVENT_CONNECTED)) {
DEBUG("gcoap: authentication timed out\n");
dsm_remove(sock->socket.dtls, &sock->ctx_dtls_session);
sock_dtls_session_destroy(sock->socket.dtls, &sock->ctx_dtls_session);
return -ENOTCONN;
}
return 0;
#endif
}
/*
* gcoap interface functions
*/
@ -887,8 +1136,16 @@ ssize_t gcoap_req_send(const uint8_t *buf, size_t len,
}
}
ssize_t res = 0;
coap_socket_t socket = { 0 };
_tl_init_coap_socket(&socket);
if (IS_USED(MODULE_GCOAP_DTLS) && socket.type == COAP_SOCKET_TYPE_DTLS) {
res = _tl_authenticate(&socket, remote, CONFIG_GCOAP_DTLS_HANDSHAKE_TIMEOUT_USEC);
}
/* set response timeout; may be zero for non-confirmable */
if (memo != NULL) {
if (memo != NULL && res == 0) {
if (timeout > 0) {
event_callback_init(&memo->resp_tmout_cb, _on_resp_timeout, memo);
event_timeout_init(&memo->resp_evt_tmout, &_queue,
@ -900,7 +1157,9 @@ ssize_t gcoap_req_send(const uint8_t *buf, size_t len,
}
}
ssize_t res = sock_udp_send(&_sock_udp, buf, len, remote);
if (res == 0) {
res = _tl_send(&socket, buf, len, remote);
}
if (res <= 0) {
if (memo != NULL) {
if (msg_type == COAP_TYPE_CON) {
@ -913,7 +1172,7 @@ ssize_t gcoap_req_send(const uint8_t *buf, size_t len,
}
DEBUG("gcoap: sock send failed: %d\n", (int)res);
}
return ((res > 0) ? res : 0);
return ((res > 0 || res == -ENOTCONN) ? res : 0);
}
int gcoap_resp_init(coap_pkt_t *pdu, uint8_t *buf, size_t len, unsigned code)
@ -974,11 +1233,12 @@ size_t gcoap_obs_send(const uint8_t *buf, size_t len,
const coap_resource_t *resource)
{
gcoap_observe_memo_t *memo = NULL;
coap_socket_t socket;
_tl_init_coap_socket(&socket);
_find_obs_memo_resource(&memo, resource);
if (memo) {
ssize_t bytes = sock_udp_send(&_sock_udp, buf, len, memo->observer);
ssize_t bytes = _tl_send(&socket, buf, len, memo->observer);
return (size_t)((bytes > 0) ? bytes : 0);
}
else {
@ -1067,4 +1327,13 @@ ssize_t gcoap_encode_link(const coap_resource_t *resource, char *buf,
return exp_size;
}
#if IS_USED(MODULE_GCOAP_DTLS)
sock_dtls_t *gcoap_get_sock_dtls(void)
{
return &_sock_dtls;
}
#endif
/* */
/** @} */