diff --git a/pkg/tinydtls/Makefile b/pkg/tinydtls/Makefile index 1f4673019a..621dbf9615 100644 --- a/pkg/tinydtls/Makefile +++ b/pkg/tinydtls/Makefile @@ -1,6 +1,6 @@ PKG_NAME=tinydtls PKG_URL=https://github.com/eclipse/tinydtls.git -PKG_VERSION=bda40789a7c280f248eeca6d09ddd624cdaf5dc8 +PKG_VERSION=297fced854b652591b78113f0ba8d57ad9f934d9 PKG_LICENSE=EPL-1.0,EDL-1.0 include $(RIOTBASE)/pkg/pkg.mk diff --git a/pkg/tinydtls/contrib/sock_dtls.c b/pkg/tinydtls/contrib/sock_dtls.c index 1c42cda3a5..003d8609ff 100644 --- a/pkg/tinydtls/contrib/sock_dtls.c +++ b/pkg/tinydtls/contrib/sock_dtls.c @@ -592,16 +592,16 @@ void sock_dtls_session_set_udp_ep(sock_dtls_session_t *session, _ep_to_session(ep, &session->dtls_session); } -ssize_t sock_dtls_send_aux(sock_dtls_t *sock, sock_dtls_session_t *remote, - const void *data, size_t len, uint32_t timeout, - sock_dtls_aux_tx_t *aux) +ssize_t sock_dtls_sendv_aux(sock_dtls_t *sock, sock_dtls_session_t *remote, + const iolist_t *snips, uint32_t timeout, + sock_dtls_aux_tx_t *aux) { (void)aux; int res; assert(sock); assert(remote); - assert(data); + assert(snips); /* check if session exists, if not create session first then send */ if (!dtls_get_peer(sock->dtls_ctx, &remote->dtls_session)) { @@ -629,7 +629,8 @@ ssize_t sock_dtls_send_aux(sock_dtls_t *sock, sock_dtls_session_t *remote, timeout = _update_timeout(start, timeout); is_timed_out = (res < 0) || (timeout == 0); } - }while (!is_timed_out && (msg.type != DTLS_EVENT_CONNECTED)); + } 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"); @@ -642,8 +643,19 @@ ssize_t sock_dtls_send_aux(sock_dtls_t *sock, sock_dtls_session_t *remote, } } - res = dtls_write(sock->dtls_ctx, &remote->dtls_session, - (uint8_t *)data, len); + const unsigned snip_count = iolist_count(snips); + uint8_t *snip_bufs[snip_count]; + size_t snip_len[snip_count]; + + for (unsigned i = 0; snips; snips = snips->iol_next) { + snip_bufs[i] = snips->iol_base; + snip_len[i] = snips->iol_len; + ++i; + } + + res = dtls_writev(sock->dtls_ctx, &remote->dtls_session, + snip_bufs, snip_len, snip_count); + #ifdef SOCK_HAS_ASYNC if ((res >= 0) && (sock->async_cb != NULL)) { sock->async_cb(sock, SOCK_ASYNC_MSG_SENT, sock->async_cb_arg); diff --git a/sys/include/net/sock/dtls.h b/sys/include/net/sock/dtls.h index 3f19227898..a152386f6c 100644 --- a/sys/include/net/sock/dtls.h +++ b/sys/include/net/sock/dtls.h @@ -898,6 +898,44 @@ static inline ssize_t sock_dtls_recv_buf(sock_dtls_t *sock, return sock_dtls_recv_buf_aux(sock, remote, data, buf_ctx, timeout, NULL); } +/** + * @brief Encrypts and sends a message to a remote peer with non-continous payload + * + * @param[in] sock DTLS sock to use + * @param[in] remote DTLS session to use. A new session will be created + * if no session exist between client and server. + * @param[in] snips List of payload chunks, will be processed in order. + * May be `NULL`. + * @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. + * @param[out] aux Auxiliary data about the transmission. + * May be `NULL`, if it is not required by the application. + * + * @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 -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_sendv_aux(sock_dtls_t *sock, sock_dtls_session_t *remote, + const iolist_t *snips, uint32_t timeout, + sock_dtls_aux_tx_t *aux); + /** * @brief Encrypts and sends a message to a remote peer * @@ -932,9 +970,19 @@ static inline ssize_t sock_dtls_recv_buf(sock_dtls_t *sock, * @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_aux(sock_dtls_t *sock, sock_dtls_session_t *remote, - const void *data, size_t len, uint32_t timeout, - sock_dtls_aux_tx_t *aux); +static inline ssize_t sock_dtls_send_aux(sock_dtls_t *sock, + sock_dtls_session_t *remote, + const void *data, size_t len, + uint32_t timeout, + sock_dtls_aux_tx_t *aux) +{ + const iolist_t snip = { + .iol_base = (void *)data, + .iol_len = len, + }; + + return sock_dtls_sendv_aux(sock, remote, &snip, timeout, aux); +} /** * @brief Encrypts and sends a message to a remote peer @@ -984,6 +1032,54 @@ static inline ssize_t sock_dtls_send(sock_dtls_t *sock, return sock_dtls_send_aux(sock, remote, data, len, timeout, NULL); } +/** + * @brief Encrypts and sends a message to a remote peer with non-continous payload + * + * @param[in] sock DTLS sock to use + * @param[in] remote DTLS session to use. A new session will be created + * if no session exist between client and server. + * @param[in] snips List of payload chunks, will be processed in order. + * May be `NULL`. + * @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 When blocking, we will need an extra thread to call + * @ref sock_dtls_recv() function to handle the incoming handshake + * messages. + * An example for a blocking handshake is: + * 1. Create an empty @ref sock_dtls_session_t object. + * 2. Set the UDP endpoint of the peer you want to connect to in the + * session object with @ref sock_dtls_session_set_udp_ep(). + * 3. Call @ref sock_dtls_send() with a timeout greater than 0. + * The send function blocks until the handshake completes or the + * timeout expires. If the handshake was successful the data has + * been sent. + * + * @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 -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. + */ +static inline ssize_t sock_dtls_sendv(sock_dtls_t *sock, + sock_dtls_session_t *remote, + const iolist_t *snips, + uint32_t timeout) +{ + return sock_dtls_sendv_aux(sock, remote, snips, timeout, NULL); +} + /** * @brief Closes a DTLS sock *