diff --git a/examples/dtls-sock/dtls-client.c b/examples/dtls-sock/dtls-client.c index 76c524a86b..2ba9a83dd8 100644 --- a/examples/dtls-sock/dtls-client.c +++ b/examples/dtls-sock/dtls-client.c @@ -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; diff --git a/pkg/tinydtls/contrib/sock_dtls.c b/pkg/tinydtls/contrib/sock_dtls.c index 263e1f1c02..4ef70b7560 100644 --- a/pkg/tinydtls/contrib/sock_dtls.c +++ b/pkg/tinydtls/contrib/sock_dtls.c @@ -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; +} + /** @} */ diff --git a/sys/include/net/sock/dtls.h b/sys/include/net/sock/dtls.h index 96569723fc..b42d10b219 100644 --- a/sys/include/net/sock/dtls.h +++ b/sys/include/net/sock/dtls.h @@ -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