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_udp_t udp_sock;
sock_dtls_t dtls_sock; sock_dtls_t dtls_sock;
sock_dtls_session_t session; 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; sock_udp_ep_t local = SOCK_IPV6_EP_ANY;
local.port = 12345; local.port = 12345;
remote.port = DTLS_DEFAULT_PORT; remote.port = DTLS_DEFAULT_PORT;

View File

@ -24,15 +24,6 @@
#include "debug.h" #include "debug.h"
#include "dtls_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 #ifdef CONFIG_DTLS_PSK
static int _get_psk_info(struct dtls_context_t *ctx, const session_t *session, static int _get_psk_info(struct dtls_context_t *ctx, const session_t *session,
dtls_credentials_type_t type, 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 _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 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 = { static dtls_handler_t _dtls_handler = {
.event = _event, .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); sock_dtls_t *sock = dtls_get_app_data(ctx);
msg_t msg = { .type = code }; msg_t msg = { .type = code };
#ifdef ENABLE_DEBUG #ifdef ENABLE_DEBUG
switch(code) { switch (code) {
case DTLS_EVENT_CONNECT: case DTLS_EVENT_CONNECT:
DEBUG("sock_dtls: event connect\n"); DEBUG("sock_dtls: event connect\n");
break; break;
@ -155,7 +147,7 @@ static int _get_psk_info(struct dtls_context_t *ctx, const session_t *session,
const void *c = NULL; const void *c = NULL;
size_t c_len = 0; size_t c_len = 0;
switch(type) { switch (type) {
case DTLS_PSK_HINT: case DTLS_PSK_HINT:
DEBUG("sock_dtls: psk hint request\n"); DEBUG("sock_dtls: psk hint request\n");
/* Ignored. See https://tools.ietf.org/html/rfc4279#section-5.2 */ /* 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, 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(sock);
assert(remote); 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)) { if (!dtls_get_peer(sock->dtls_ctx, &remote->dtls_session)) {
int res; int res;
if (timeout == 0) {
return -ENOTCONN;
}
/* no session with remote, creating new session. /* no session with remote, creating new session.
* This will also create new peer for this session */ * This will also create new peer for this session */
res = dtls_connect(sock->dtls_ctx, &remote->dtls_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 */ /* handshake initiated, wait until connected or timed out */
msg_t msg; msg_t msg;
bool is_timed_out = false;
do { 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)); while (!is_timed_out && (msg.type != DTLS_EVENT_CONNECTED));
if (res == -1) { if (is_timed_out && (msg.type != DTLS_EVENT_CONNECTED)) {
DEBUG("sock_dtls: handshake process timed out\n"); DEBUG("sock_dtls: handshake process timed out\n");
/* deletes peer created in dtls_connect() before */ /* 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); 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 */ /* loop breaks when timeout or application data read */
while(1) { while (1) {
uint32_t start_recv = xtimer_now_usec(); uint32_t start_recv = xtimer_now_usec();
ssize_t res = sock_udp_recv(sock->udp_sock, data, max_len, timeout, ssize_t res = sock_udp_recv(sock->udp_sock, data, max_len, timeout,
&remote->ep); &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)); 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"; * 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) { * if (res >= 0) {
* printf("Sent %d bytes\n", res); * printf("Sent %d bytes\n", res);
* res = sock_dtls_recv(&dtls_sock, &session, rcv, sizeof(rcv), SOCK_NO_TIMEOUT); * res = sock_dtls_recv(&dtls_sock, &session, rcv, sizeof(rcv), SOCK_NO_TIMEOUT);
@ -423,7 +423,7 @@
* } * }
* *
* const char data[] = "HELLO"; * 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) { * if (res >= 0) {
* printf("Sent %d bytes: %*.s\n", res, res, data); * printf("Sent %d bytes: %*.s\n", res, res, data);
* res = sock_dtls_recv(&dtls_sock, &session, rcv, sizeof(rcv), SOCK_NO_TIMEOUT); * 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. * if no session exist between client and server.
* @param[in] data Pointer where the data to be send are stored * @param[in] data Pointer where the data to be send are stored
* @param[in] len Length of @p data to be send * @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 * @note When blocking, we will need an extra thread to call
* existing session with @p remote. * @ref sock_dtls_recv() function to handle the incoming handshake
* * messages.
* @note Initiating a session through this function will require
* @ref sock_dtls_recv() called from another thread to receive the handshake
* messages.
* *
* @return The number of bytes sent on success * @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 -EADDRINUSE, if sock_dtls_t::udp_sock has no local end-point.
* @return -EAFNOSUPPORT, if `remote->ep != NULL` and * @return -EAFNOSUPPORT, if `remote->ep != NULL` and
* sock_dtls_session_t::ep::family of @p remote is != AF_UNSPEC and * sock_dtls_session_t::ep::family of @p remote is != AF_UNSPEC and
* not supported. * 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 * @return -EINVAL, if sock_udp_ep_t::addr of @p remote->ep is an
* invalid address. * invalid address.
* @return -EINVAL, if sock_udp_ep_t::port of @p remote->ep is 0. * @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 -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, 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 * @brief Closes a DTLS sock