Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

nanocoap_sock: implement DTLS socket #18724

Merged
merged 6 commits into from
Jan 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 65 additions & 0 deletions pkg/tinydtls/contrib/sock_dtls.c
Original file line number Diff line number Diff line change
Expand Up @@ -814,6 +814,71 @@ ssize_t sock_dtls_recv_aux(sock_dtls_t *sock, sock_dtls_session_t *remote,
}
}

ssize_t sock_dtls_recv_buf_aux(sock_dtls_t *sock, sock_dtls_session_t *remote,
void **data, void **buf_ctx, uint32_t timeout,
sock_dtls_aux_rx_t *aux)
{
assert(sock);
assert(data);
assert(buf_ctx);
assert(remote);

sock_udp_ep_t ep;

/* 2nd call to the function (with ctx set) will free the data */
if (*buf_ctx) {
int res = sock_udp_recv_buf_aux(sock->udp_sock, data, buf_ctx,
timeout, &ep, (sock_udp_aux_rx_t *)aux);
assert(res == 0);
return res;
}
Comment on lines +828 to +834
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I could not find this usage pattern (of sock_udp_recv_buf_aux to "free" the ctxand data) at another point, but i think if it is just a "free" call it should have a timeout of 0. (i might be wrong).

(I am also not sure why there is the assertion that there will be no data to be received (that therefor would need to be processed)

Copy link
Contributor Author

@benpicco benpicco Jan 12, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's also done in nanocoap_sock.

IMHO the sock_udp_recv_buf_aux() is just a bit clunky. If we would need to do application level re-assembly, that would void the point of the function as we would need a 2nd buffer for re-assembly again.

The timeout is just ignored in that case.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

seems like the documentation for sock_udp_recv_buf_aux and sock_udp_recv_buf need an update and/or the ctx thing removed (out of scope for this PR)


/* loop breaks when timeout or application data read */
while (1) {
ssize_t res;
uint32_t start_recv = ztimer_now(ZTIMER_USEC);
msg_t msg;

if (sock->buffer.data != NULL) {
*data = sock->buffer.data;
sock->buffer.data = NULL;
_copy_session(sock, remote);

return sock->buffer.datalen;
}
else if (mbox_try_get(&sock->mbox, &msg) &&
msg.type == DTLS_EVENT_CONNECTED) {
return _complete_handshake(sock, remote, msg.content.ptr);
}
/* Crude way to somewhat test that `sock_dtls_aux_rx_t` and
* `sock_udp_aux_rx_t` remain compatible: */
static_assert(sizeof(sock_dtls_aux_rx_t) == sizeof(sock_udp_aux_rx_t),
"sock_dtls_aux_rx_t became incompatible with "
"sock_udp_aux_rx_t");
res = sock_udp_recv_buf_aux(sock->udp_sock, data, buf_ctx,
timeout, &ep, (sock_udp_aux_rx_t *)aux);
if (res == 0) {
continue;
}
if (res < 0) {
DEBUG("sock_dtls: error receiving UDP packet: %d\n", (int)res);
return res;
}

_ep_to_session(&ep, &remote->dtls_session);
res = dtls_handle_message(sock->dtls_ctx, &remote->dtls_session,
*data, res);

if ((timeout != SOCK_NO_TIMEOUT) && (timeout != 0)) {
timeout = _update_timeout(start_recv, timeout);
}
if (timeout == 0) {
DEBUG("sock_dtls: timed out while decrypting message\n");
return -ETIMEDOUT;
}
}
}

void sock_dtls_close(sock_dtls_t *sock)
{
dtls_free_context(sock->dtls_ctx);
Expand Down
5 changes: 5 additions & 0 deletions sys/Makefile.dep
Original file line number Diff line number Diff line change
Expand Up @@ -713,6 +713,11 @@ ifneq (,$(filter luid,$(USEMODULE)))
FEATURES_OPTIONAL += periph_cpuid
endif

ifneq (,$(filter nanocoap_dtls,$(USEMODULE)))
USEMODULE += sock_dtls
USEPKG += tinydtls
endif

ifneq (,$(filter nanocoap_sock,$(USEMODULE)))
USEMODULE += sock_udp
USEMODULE += sock_util
Expand Down
5 changes: 5 additions & 0 deletions sys/include/net/coap.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@ extern "C" {
*/
#define COAP_PORT (5683)

/**
* @brief Default CoAP DTLS port
*/
#define COAPS_PORT (5684)

#define COAP_V1 (1) /**< Identifier for CoAP version 1 (RFC 7252) */

/**
Expand Down
81 changes: 75 additions & 6 deletions sys/include/net/nanocoap_sock.h
Original file line number Diff line number Diff line change
Expand Up @@ -135,16 +135,58 @@
#include "net/nanocoap.h"
#include "net/sock/udp.h"
#include "net/sock/util.h"
#if IS_USED(MODULE_NANOCOAP_DTLS)
#include "net/credman.h"
#include "net/sock/dtls.h"
#endif

#ifdef __cplusplus
extern "C" {
#endif

/**
* @brief nanocoap socket type
*
* @brief Timeout for CoAP over DTLS queries in milliseconds
*/
typedef sock_udp_t nanocoap_sock_t;
#ifndef CONFIG_NANOCOAP_SOCK_DTLS_TIMEOUT_MS
#define CONFIG_NANOCOAP_SOCK_DTLS_TIMEOUT_MS (1000U)
#endif

/**
* @brief Number of CoAP over DTLS handshake retries
*/
#ifndef CONFIG_NANOCOAP_SOCK_DTLS_RETRIES
#define CONFIG_NANOCOAP_SOCK_DTLS_RETRIES (2)
#endif

/**
* @brief Credman tag used for NanoCoAP
* Tag together with the credential type (PSK) needs to be unique
*/
#ifndef CONFIG_NANOCOAP_SOCK_DTLS_TAG
#define CONFIG_NANOCOAP_SOCK_DTLS_TAG (0xc0ab)
#endif

/**
* @brief NanoCoAP socket types
*/
typedef enum {
COAP_SOCKET_TYPE_UDP, /**< transport is plain UDP */
COAP_SOCKET_TYPE_DTLS, /**< transport is DTLS */
} nanocoap_socket_type_t;

/**
* @brief NanoCoAP socket struct
*/
typedef struct {
sock_udp_t udp; /**< UDP socket */
#if IS_USED(MODULE_NANOCOAP_DTLS) || defined(DOXYGEN)
sock_dtls_t dtls; /**< DTLS socket */
sock_dtls_session_t dtls_session; /**< Session object for the stored socket.
Used for exchanging a session between
functions. */
nanocoap_socket_type_t type; /**< Socket type (UDP, DTLS) */
#endif
} nanocoap_sock_t;

/**
* @brief Blockwise request helper struct
Expand Down Expand Up @@ -185,9 +227,30 @@ static inline int nanocoap_sock_connect(nanocoap_sock_t *sock,
const sock_udp_ep_t *local,
const sock_udp_ep_t *remote)
{
return sock_udp_create(sock, local, remote, 0);
#if IS_USED(MODULE_NANOCOAP_DTLS)
sock->type = COAP_SOCKET_TYPE_UDP;
#endif

return sock_udp_create(&sock->udp, local, remote, 0);
}

#if IS_USED(MODULE_NANOCOAP_DTLS) || DOXYGEN
/**
* @brief Create a DTLS secured CoAP client socket
*
* @param[out] sock CoAP UDP socket
* @param[in] local Local UDP endpoint, may be NULL
* @param[in] remote remote UDP endpoint
* @param[in] tag Tag of the PSK credential to use
* Has to be added with @ref credman_add
*
* @returns 0 on success
* @returns <0 on error
*/
int nanocoap_sock_dtls_connect(nanocoap_sock_t *sock, sock_udp_ep_t *local,
const sock_udp_ep_t *remote, credman_tag_t tag);
#endif

/**
* @brief Create a CoAP client socket by URL
*
Expand All @@ -206,7 +269,13 @@ int nanocoap_sock_url_connect(const char *url, nanocoap_sock_t *sock);
*/
static inline void nanocoap_sock_close(nanocoap_sock_t *sock)
{
sock_udp_close(sock);
#if IS_USED(MODULE_NANOCOAP_DTLS)
if (sock->type == COAP_SOCKET_TYPE_DTLS) {
sock_dtls_session_destroy(&sock->dtls, &sock->dtls_session);
sock_dtls_close(&sock->dtls);
}
#endif
sock_udp_close(&sock->udp);
}

/**
Expand Down Expand Up @@ -441,7 +510,7 @@ ssize_t nanocoap_sock_request(nanocoap_sock_t *sock, coap_pkt_t *pkt, size_t len
* @returns length of response on success
* @returns <0 on error
*/
ssize_t nanocoap_sock_request_cb(sock_udp_t *sock, coap_pkt_t *pkt,
ssize_t nanocoap_sock_request_cb(nanocoap_sock_t *sock, coap_pkt_t *pkt,
coap_request_cb_t cb, void *arg);

/**
Expand Down
13 changes: 13 additions & 0 deletions sys/include/ztimer.h
Original file line number Diff line number Diff line change
Expand Up @@ -776,6 +776,19 @@ void ztimer_set_wakeup(ztimer_clock_t *clock, ztimer_t *timer, uint32_t offset,
void ztimer_set_timeout_flag(ztimer_clock_t *clock, ztimer_t *timer,
uint32_t timeout);

/**
* @brief Unlock mutex after @p timeout
*
* This function will unlock the given mutex after the timeout has passed.
*
* @param[in] clock ztimer clock to operate on
* @param[in] timer timer struct to use
* @param[in] timeout timeout in ztimer_clock's ticks
* @param[in] mutex mutex to unlock after timeout
*/
void ztimer_mutex_unlock(ztimer_clock_t *clock, ztimer_t *timer,
uint32_t timeout, mutex_t *mutex);

/**
* @brief Try to lock the given mutex, but give up after @p timeout
*
Expand Down
Loading