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

sock_dtls: add timeout to sock_dtls_send()

This commit is contained in:
Aiman Ismail 2020-05-14 18:27:29 +02:00
parent cc44992abe
commit 7f883f4098
3 changed files with 44 additions and 30 deletions

View File

@ -74,7 +74,7 @@ static int client_send(char *addr_str, char *data, size_t datalen)
sock_udp_t udp_sock;
sock_dtls_t dtls_sock;
sock_dtls_session_t session;
sock_udp_ep_t remote;
sock_udp_ep_t remote = SOCK_IPV6_EP_ANY;
sock_udp_ep_t local = SOCK_IPV6_EP_ANY;
local.port = 12345;
remote.port = DTLS_DEFAULT_PORT;

View File

@ -24,15 +24,6 @@
#include "debug.h"
#include "dtls_debug.h"
#define DTLS_HANDSHAKE_BUFSIZE (256) /**< Size buffer used in handshake
to hold credentials */
/* ECC handshake takes more time */
#ifdef CONFIG_DTLS_ECC
#define DTLS_HANDSHAKE_TIMEOUT (30 * US_PER_SEC)
#else
#define DTLS_HANDSHAKE_TIMEOUT (1 * US_PER_SEC)
#endif /* CONFIG_DTLS_ECC */
#ifdef CONFIG_DTLS_PSK
static int _get_psk_info(struct dtls_context_t *ctx, const session_t *session,
dtls_credentials_type_t type,
@ -61,6 +52,7 @@ static int _event(struct dtls_context_t *ctx, session_t *session,
static void _session_to_ep(const session_t *session, sock_udp_ep_t *ep);
static void _ep_to_session(const sock_udp_ep_t *ep, session_t *session);
static uint32_t _update_timeout(uint32_t start, uint32_t timeout);
static dtls_handler_t _dtls_handler = {
.event = _event,
@ -112,7 +104,7 @@ static int _event(struct dtls_context_t *ctx, session_t *session,
sock_dtls_t *sock = dtls_get_app_data(ctx);
msg_t msg = { .type = code };
#ifdef ENABLE_DEBUG
switch(code) {
switch (code) {
case DTLS_EVENT_CONNECT:
DEBUG("sock_dtls: event connect\n");
break;
@ -155,7 +147,7 @@ static int _get_psk_info(struct dtls_context_t *ctx, const session_t *session,
const void *c = NULL;
size_t c_len = 0;
switch(type) {
switch (type) {
case DTLS_PSK_HINT:
DEBUG("sock_dtls: psk hint request\n");
/* Ignored. See https://tools.ietf.org/html/rfc4279#section-5.2 */
@ -325,7 +317,7 @@ void sock_dtls_session_destroy(sock_dtls_t *sock, sock_dtls_session_t *remote)
}
ssize_t sock_dtls_send(sock_dtls_t *sock, sock_dtls_session_t *remote,
const void *data, size_t len)
const void *data, size_t len, uint32_t timeout)
{
assert(sock);
assert(remote);
@ -335,6 +327,10 @@ ssize_t sock_dtls_send(sock_dtls_t *sock, sock_dtls_session_t *remote,
if (!dtls_get_peer(sock->dtls_ctx, &remote->dtls_session)) {
int res;
if (timeout == 0) {
return -ENOTCONN;
}
/* no session with remote, creating new session.
* This will also create new peer for this session */
res = dtls_connect(sock->dtls_ctx, &remote->dtls_session);
@ -346,17 +342,25 @@ ssize_t sock_dtls_send(sock_dtls_t *sock, sock_dtls_session_t *remote,
/* handshake initiated, wait until connected or timed out */
msg_t msg;
bool is_timed_out = false;
do {
res = xtimer_msg_receive_timeout(&msg, 3 * DTLS_HANDSHAKE_TIMEOUT);
uint32_t start = xtimer_now_usec();
res = xtimer_msg_receive_timeout(&msg, timeout);
if (timeout != SOCK_NO_TIMEOUT) {
timeout = _update_timeout(start, timeout);
is_timed_out = (res < 0) || (timeout == 0);
}
}
while ((res != -1) && (msg.type != DTLS_EVENT_CONNECTED));
if (res == -1) {
while (!is_timed_out && (msg.type != DTLS_EVENT_CONNECTED));
if (is_timed_out && (msg.type != DTLS_EVENT_CONNECTED)) {
DEBUG("sock_dtls: handshake process timed out\n");
/* deletes peer created in dtls_connect() before */
dtls_peer_t *peer = dtls_get_peer(sock->dtls_ctx, &remote->dtls_session);
dtls_peer_t *peer = dtls_get_peer(sock->dtls_ctx,
&remote->dtls_session);
dtls_reset_peer(sock->dtls_ctx, peer);
return -EHOSTUNREACH;
return -ETIMEDOUT;
}
}
}
@ -392,7 +396,7 @@ ssize_t sock_dtls_recv(sock_dtls_t *sock, sock_dtls_session_t *remote,
}
/* loop breaks when timeout or application data read */
while(1) {
while (1) {
uint32_t start_recv = xtimer_now_usec();
ssize_t res = sock_udp_recv(sock->udp_sock, data, max_len, timeout,
&remote->ep);
@ -448,4 +452,10 @@ static void _session_to_ep(const session_t *session, sock_udp_ep_t *ep)
memcpy(&ep->addr.ipv6, &session->addr, sizeof(ipv6_addr_t));
}
static inline uint32_t _update_timeout(uint32_t start, uint32_t timeout)
{
uint32_t diff = (xtimer_now_usec() - start);
return (diff > timeout) ? 0: timeout - diff;
}
/** @} */

View File

@ -345,7 +345,7 @@
* }
*
* const char data[] = "HELLO";
* int res = sock_dtls_send(&dtls_sock, &session, data, sizeof(data));
* int res = sock_dtls_send(&dtls_sock, &session, data, sizeof(data), 0);
* if (res >= 0) {
* printf("Sent %d bytes\n", res);
* res = sock_dtls_recv(&dtls_sock, &session, rcv, sizeof(rcv), SOCK_NO_TIMEOUT);
@ -423,7 +423,7 @@
* }
*
* const char data[] = "HELLO";
* int res = sock_dtls_send(&dtls_sock, &session, data, sizeof(data));
* int res = sock_dtls_send(&dtls_sock, &session, data, sizeof(data), 0);
* if (res >= 0) {
* printf("Sent %d bytes: %*.s\n", res, res, data);
* res = sock_dtls_recv(&dtls_sock, &session, rcv, sizeof(rcv), SOCK_NO_TIMEOUT);
@ -657,28 +657,32 @@ ssize_t sock_dtls_recv_buf(sock_dtls_t *sock, sock_dtls_session_t *remote,
* if no session exist between client and server.
* @param[in] data Pointer where the data to be send are stored
* @param[in] len Length of @p data to be send
* @param[in] timeout Handshake timeout in microseconds.
* If `timeout > 0`, will start a new handshake if no
* session exists yet. The function will block until
* handshake completed or timed out.
* May be SOCK_NO_TIMEOUT to block indefinitely until
* handshake complete.
*
* @note Function may block until a session is created if there is no
* existing session with @p remote.
*
* @note Initiating a session through this function will require
* @ref sock_dtls_recv() called from another thread to receive the handshake
* messages.
* @note When blocking, we will need an extra thread to call
* @ref sock_dtls_recv() function to handle the incoming handshake
* messages.
*
* @return The number of bytes sent on success
* @return -ENOTCONN, if `timeout == 0` and no existing session exists with
* @p remote
* @return -EADDRINUSE, if sock_dtls_t::udp_sock has no local end-point.
* @return -EAFNOSUPPORT, if `remote->ep != NULL` and
* sock_dtls_session_t::ep::family of @p remote is != AF_UNSPEC and
* not supported.
* @return -EHOSTUNREACH, if sock_dtls_session_t::ep of @p remote is not
* reachable.
* @return -EINVAL, if sock_udp_ep_t::addr of @p remote->ep is an
* invalid address.
* @return -EINVAL, if sock_udp_ep_t::port of @p remote->ep is 0.
* @return -ENOMEM, if no memory was available to send @p data.
* @return -ETIMEDOUT, `0 < timeout < SOCK_NO_TIMEOUT` and timed out.
*/
ssize_t sock_dtls_send(sock_dtls_t *sock, sock_dtls_session_t *remote,
const void *data, size_t len);
const void *data, size_t len, uint32_t timeout);
/**
* @brief Closes a DTLS sock