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

Merge pull request #12907 from miri64/tinydtls/enh/async-sock

tinydtls: add `sock_async` support for `sock_dtls`
This commit is contained in:
Martine Lenders 2020-06-22 08:25:16 +02:00 committed by GitHub
commit 2b90d9b833
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 955 additions and 28 deletions

View File

@ -17,9 +17,15 @@
*/
#include "dtls.h"
#include "log.h"
#include "net/sock/dtls.h"
#include "net/credman.h"
#if SOCK_HAS_ASYNC
#include "net/sock/async.h"
#include "net/sock/async/event.h"
#endif
#define ENABLE_DEBUG (0)
#include "debug.h"
#include "dtls_debug.h"
@ -77,6 +83,11 @@ static int _read(struct dtls_context_t *ctx, session_t *session, uint8_t *buf,
sock->buffer.data = buf;
sock->buffer.datalen = len;
sock->buffer.session = session;
#ifdef SOCK_HAS_ASYNC
if (sock->async_cb != NULL) {
sock->async_cb(sock, SOCK_ASYNC_MSG_RECV, sock->async_cb_arg);
}
#endif
return len;
}
@ -103,7 +114,7 @@ static int _event(struct dtls_context_t *ctx, session_t *session,
(void)session;
sock_dtls_t *sock = dtls_get_app_data(ctx);
msg_t msg = { .type = code };
msg_t msg = { .type = code, .content.ptr = session };
#ifdef ENABLE_DEBUG
switch (code) {
case DTLS_EVENT_CONNECT:
@ -120,6 +131,23 @@ static int _event(struct dtls_context_t *ctx, session_t *session,
if (!level && (code != DTLS_EVENT_CONNECT)) {
mbox_put(&sock->mbox, &msg);
}
#ifdef SOCK_HAS_ASYNC
if (sock->async_cb != NULL) {
switch (code) {
case DTLS_ALERT_CLOSE_NOTIFY:
/* peer closed their session */
sock->async_cb(sock, SOCK_ASYNC_CONN_FIN, sock->async_cb_arg);
break;
case DTLS_EVENT_CONNECTED:
/* we received a session handshake initialization */
sock->async_cb(sock, SOCK_ASYNC_CONN_RECV,
sock->async_cb_arg);
break;
default:
break;
}
}
#endif
return 0;
}
@ -250,6 +278,10 @@ int sock_dtls_create(sock_dtls_t *sock, sock_udp_t *udp_sock,
sock->udp_sock = udp_sock;
sock->buffer.data = NULL;
#ifdef SOCK_HAS_ASYNC
sock->async_cb = NULL;
sock->buf_ctx = NULL;
#endif /* SOCK_HAS_ASYNC */
sock->role = role;
sock->tag = tag;
sock->dtls_ctx = dtls_new_context(sock);
@ -320,14 +352,14 @@ 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, uint32_t timeout)
{
int res;
assert(sock);
assert(remote);
assert(data);
/* check if session exists, if not create session first then send */
if (!dtls_get_peer(sock->dtls_ctx, &remote->dtls_session)) {
int res;
if (timeout == 0) {
return -ENOTCONN;
}
@ -366,8 +398,47 @@ ssize_t sock_dtls_send(sock_dtls_t *sock, sock_dtls_session_t *remote,
}
}
return dtls_write(sock->dtls_ctx, &remote->dtls_session,
(uint8_t *)data, len);
res = dtls_write(sock->dtls_ctx, &remote->dtls_session,
(uint8_t *)data, len);
#ifdef SOCK_HAS_ASYNC
if ((res >= 0) && (sock->async_cb != NULL)) {
sock->async_cb(sock, SOCK_ASYNC_MSG_SENT, sock->async_cb_arg);
}
#endif /* SOCK_HAS_ASYNC */
return res;
}
#if SOCK_HAS_ASYNC
/**
* @brief Checks for and iterates for more data chunks within the network
* stacks anternal packet buffer
*
* When no more chunks exists, `data_ctx` assures cleaning up the internal
* buffer state and `sock_udp_recv_buf()` returns 0.
*
* @see @ref sock_udp_recv_buf().
*/
static void _check_more_chunks(sock_udp_t *udp_sock, void **data,
void **data_ctx, sock_udp_ep_t *remote)
{
ssize_t res;
while ((res = sock_udp_recv_buf(udp_sock, data, data_ctx, 0, remote)) > 0) {
/* TODO: remove and adapt _copy_buffer() to add remaining data when
* tinydtls supports chunked datagram payload */
if (IS_ACTIVE(DEVELHELP)) {
LOG_ERROR("sock_dtls: Chunked datagram payload currently not "
"supported yet by tinydtls\n");
}
}
}
#endif
static inline void _copy_session(sock_dtls_t *sock, sock_dtls_session_t *remote)
{
memcpy(&remote->dtls_session, sock->buffer.session,
sizeof(remote->dtls_session));
_session_to_ep(&remote->dtls_session, &remote->ep);
}
static ssize_t _copy_buffer(sock_dtls_t *sock, sock_dtls_session_t *remote,
@ -380,15 +451,61 @@ static ssize_t _copy_buffer(sock_dtls_t *sock, sock_dtls_session_t *remote,
if (buflen > max_len) {
return -ENOBUFS;
}
#if SOCK_HAS_ASYNC
if (sock->buf_ctx != NULL) {
memcpy(data, buf, sock->buffer.datalen);
_copy_session(sock, remote);
_check_more_chunks(sock->udp_sock, (void **)&buf, &sock->buf_ctx,
&remote->ep);
if (sock->async_cb &&
/* is there a message in the sock's mbox? */
cib_avail(&sock->mbox.cib)) {
if (sock->buffer.data) {
sock->async_cb(sock, SOCK_ASYNC_MSG_RECV,
sock->async_cb_arg);
}
else {
sock->async_cb(sock, SOCK_ASYNC_CONN_RECV,
sock->async_cb_arg);
}
}
return buflen;
}
#else
(void)remote;
#endif
/* use `memmove()` as tinydtls reuses `data` to store decrypted data with an
* offset in `buf`. This prevents problems with overlapping buffers. */
memmove(data, buf, buflen);
memcpy(&remote->dtls_session, sock->buffer.session,
sizeof(remote->dtls_session));
_session_to_ep(&remote->dtls_session, &remote->ep);
_copy_session(sock, remote);
return buflen;
}
static ssize_t _complete_handshake(sock_dtls_t *sock,
sock_dtls_session_t *remote,
const session_t *session)
{
memcpy(&remote->dtls_session, session, sizeof(remote->dtls_session));
#ifdef SOCK_HAS_ASYNC
if (sock->async_cb) {
sock_async_flags_t flags = SOCK_ASYNC_CONN_RDY;
if (cib_avail(&sock->mbox.cib)) {
if (sock->buffer.data) {
flags |= SOCK_ASYNC_MSG_RECV;
}
else {
flags |= SOCK_ASYNC_CONN_RECV;
}
}
sock->async_cb(sock, flags, sock->async_cb_arg);
}
#else
(void)sock;
#endif
return -SOCK_DTLS_HANDSHAKE;
}
ssize_t sock_dtls_recv(sock_dtls_t *sock, sock_dtls_session_t *remote,
void *data, size_t max_len, uint32_t timeout)
{
@ -396,16 +513,21 @@ ssize_t sock_dtls_recv(sock_dtls_t *sock, sock_dtls_session_t *remote,
assert(data);
assert(remote);
if (sock->buffer.data != NULL) {
/* there is already decrypted data available */
return _copy_buffer(sock, remote, data, max_len);
}
/* loop breaks when timeout or application data read */
while (1) {
ssize_t res;
uint32_t start_recv = xtimer_now_usec();
ssize_t res = sock_udp_recv(sock->udp_sock, data, max_len, timeout,
&remote->ep);
msg_t msg;
if (sock->buffer.data != NULL) {
return _copy_buffer(sock, remote, data, max_len);
}
else if (mbox_try_get(&sock->mbox, &msg) &&
msg.type == DTLS_EVENT_CONNECTED) {
return _complete_handshake(sock, remote, msg.content.ptr);
}
res = sock_udp_recv(sock->udp_sock, data, max_len, timeout,
&remote->ep);
if (res <= 0) {
DEBUG("sock_dtls: error receiving UDP packet: %d\n", (int)res);
return res;
@ -418,21 +540,11 @@ ssize_t sock_dtls_recv(sock_dtls_t *sock, sock_dtls_session_t *remote,
if ((timeout != SOCK_NO_TIMEOUT) && (timeout != 0)) {
timeout = _update_timeout(start_recv, timeout);
}
msg_t msg;
if (sock->buffer.data != NULL) {
return _copy_buffer(sock, remote, data, max_len);
}
else if (mbox_try_get(&sock->mbox, &msg) &&
msg.type == DTLS_EVENT_CONNECTED) {
return -SOCK_DTLS_HANDSHAKE;
}
else if (timeout == 0) {
if (timeout == 0) {
DEBUG("sock_dtls: timed out while decrypting message\n");
return -ETIMEDOUT;
}
}
}
void sock_dtls_close(sock_dtls_t *sock)
@ -468,4 +580,64 @@ static inline uint32_t _update_timeout(uint32_t start, uint32_t timeout)
return (diff > timeout) ? 0: timeout - diff;
}
#ifdef SOCK_HAS_ASYNC
void _udp_cb(sock_udp_t *udp_sock, sock_async_flags_t flags, void *ctx)
{
sock_dtls_t *sock = ctx;
if (flags & SOCK_ASYNC_MSG_RECV) {
sock_dtls_session_t remote;
void *data = NULL;
void *data_ctx = NULL;
ssize_t res = sock_udp_recv_buf(udp_sock, &data, &data_ctx, 0,
&remote.ep);
if (res <= 0) {
DEBUG("sock_dtls: error receiving UDP packet: %d\n", (int)res);
return;
}
/* prevent overriding already set `buf_ctx` */
if (sock->buf_ctx != NULL) {
DEBUG("sock_dtls: unable to store buffer asynchronously\n");
_check_more_chunks(udp_sock, &data, &data_ctx, &remote.ep);
return;
}
_ep_to_session(&remote.ep, &remote.dtls_session);
sock->buf_ctx = data_ctx;
res = dtls_handle_message(sock->dtls_ctx, &remote.dtls_session,
data, res);
if (sock->buffer.data == NULL) {
_check_more_chunks(udp_sock, &data, &data_ctx, &remote.ep);
sock->buf_ctx = NULL;
}
}
if ((flags & SOCK_ASYNC_PATH_PROP) && sock->async_cb) {
/* just hand this event type up the stack */
sock->async_cb(sock, SOCK_ASYNC_PATH_PROP, sock->async_cb_arg);
}
}
void sock_dtls_set_cb(sock_dtls_t *sock, sock_dtls_cb_t cb, void *cb_arg)
{
sock->async_cb = cb;
sock->async_cb_arg = cb_arg;
if (IS_USED(MODULE_SOCK_ASYNC_EVENT)) {
sock_async_ctx_t *ctx = sock_dtls_get_async_ctx(sock);
if (ctx->queue) {
sock_udp_event_init(sock->udp_sock, ctx->queue, _udp_cb, sock);
return;
}
}
sock_udp_set_cb(sock->udp_sock, _udp_cb, sock);
}
#ifdef SOCK_HAS_ASYNC_CTX
sock_async_ctx_t *sock_dtls_get_async_ctx(sock_dtls_t *sock)
{
return &sock->async_ctx;
}
#endif /* SOCK_HAS_ASYNC_CTX */
#endif /* SOCK_HAS_ASYNC */
/** @} */

View File

@ -22,6 +22,9 @@
#include "dtls.h"
#include "net/sock/udp.h"
#include "net/credman.h"
#ifdef SOCK_HAS_ASYNC
#include "net/sock/async/types.h"
#endif
#ifdef __cplusplus
extern "C" {
@ -37,6 +40,27 @@ extern "C" {
struct sock_dtls {
dtls_context_t *dtls_ctx; /**< TinyDTLS context for sock */
sock_udp_t *udp_sock; /**< Underlying UDP sock to use */
#if defined(SOCK_HAS_ASYNC) || defined(DOXYGEN)
/**
* @brief Network stack internal buffer context.
*/
void *buf_ctx;
/**
* @brief Asynchronous event callback
*
* @note Only available if @ref SOCK_HAS_ASYNC is defined
*/
sock_dtls_cb_t async_cb;
void *async_cb_arg; /**< asynchronous callback arg */
#if defined(SOCK_HAS_ASYNC_CTX) || defined(DOXYGEN)
/**
* @brief Asynchronous event context
*
* @note Only available if @ref SOCK_HAS_ASYNC_CTX is defined
*/
sock_async_ctx_t async_ctx;
#endif
#endif
mbox_t mbox; /**< Mailbox for internal event
handling */
msg_t mbox_queue[SOCK_DTLS_MBOX_SIZE]; /**< Queue for struct

View File

@ -1,3 +1,11 @@
/*
* Copyright (C) 2019-20 Freie Universität Berlin
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @addtogroup net_sock_async Sock extension for asynchronous access
*
@ -47,9 +55,9 @@ typedef struct sock_dtls sock_dtls_t; /**< forward declare for async */
*
* @param[in] sock The sock the event happened on
* @param[in] flags The event flags. Expected values are
* - @ref SOCK_ASYNC_CONN_RDY (if a session you created becomes ready),
* - @ref SOCK_ASYNC_CONN_RDY (if a session becomes ready),
* - @ref SOCK_ASYNC_CONN_FIN (if a created session was destroyed),
* - @ref SOCK_ASYNC_CONN_RECV (if a peer tries to create a session),
* - @ref SOCK_ASYNC_CONN_RECV (if a handshake message needs to be completed)
* - @ref SOCK_ASYNC_MSG_RECV,
* - @ref SOCK_ASYNC_MSG_SENT,
* - @ref SOCK_ASYNC_PATH_PROP, or

View File

@ -0,0 +1,45 @@
include ../Makefile.tests_common
# TinyDTLS only has support for 32-bit architectures ATM
FEATURES_REQUIRED += arch_32bit
# Include packages that pull up and auto-init the link layer.
# NOTE: 6LoWPAN will be included if IEEE802.15.4 devices are present
USEMODULE += gnrc_netdev_default
USEMODULE += auto_init_gnrc_netif
# Specify the mandatory networking modules for IPv6 and UDP
USEMODULE += gnrc_ipv6_default
USEMODULE += gnrc_sock_async
USEMODULE += gnrc_sock_udp
USEMODULE += sock_async_event
USEMODULE += event_thread_medium
USEMODULE += event_timeout
# Use tinydtls for sock_dtls
USEMODULE += tinydtls_sock_dtls
# Add also the shell, some shell commands
USEMODULE += shell
USEMODULE += shell_commands
# Bitfield to log open sessions
USEMODULE += bitfield
# UDP Port to use (20220 is default for DTLS).
DTLS_PORT ?= 20220
CFLAGS += -DDTLS_DEFAULT_PORT=$(DTLS_PORT)
# NOTE: If no cipher suite is selected, CONFIG_DTLS_PSK is used by default.
# This section should be commented out if using Kconfig
# This adds support for TLS_PSK_WITH_AES_128_CCM_8
# CFLAGS += -DCONFIG_DTLS_PSK
# This adds support for TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8
# CFLAGS += -DCONFIG_DTLS_ECC
# Uncomment to enable debug logs
# CFLAGS += -DCONFIG_DTLS_DEBUG
# FIXME: This is a temporary patch
CFLAGS += -DTHREAD_STACKSIZE_MAIN=\(2*THREAD_STACKSIZE_LARGE\)
include $(RIOTBASE)/Makefile.include

View File

@ -0,0 +1,42 @@
BOARD_INSUFFICIENT_MEMORY := \
airfy-beacon \
b-l072z-lrwan1 \
blackpill \
blackpill-128kib \
bluepill \
bluepill-128kib \
calliope-mini \
cc2650-launchpad \
cc2650stk \
hifive1 \
hifive1b \
i-nucleo-lrwan1 \
im880b \
lsn50 \
maple-mini \
microbit \
nrf51dongle \
nrf6310 \
nucleo-f030r8 \
nucleo-f031k6 \
nucleo-f042k6 \
nucleo-f070rb \
nucleo-f072rb \
nucleo-f103rb \
nucleo-f302r8 \
nucleo-f303k8 \
nucleo-f334r8 \
nucleo-l031k6 \
nucleo-l053r8 \
nucleo-l073rz \
olimexino-stm32 \
opencm904 \
saml10-xpro \
saml11-xpro \
spark-core \
stm32f030f4-demo \
stm32f0discovery \
stm32l0538-disco \
stm32mindev \
yunjia-nrf51822 \
#

View File

@ -0,0 +1,42 @@
# DTLS sock async test application
This is a test application for DTLS sock `sock_dtls_t` with `sock_async`.
## Testing using RIOT `native`
For testing, we can use two RIOT `native` RIOT instances. For that first we
need to prepare the network interfaces:
```bash
$ ./../../dist/tools/tapsetup/tapsetup --create 2
```
For the server instance:
```
$ PORT=tap0 make all term
[...]
> dtlss start
ifconfig
```
For the client:
```
$ PORT=tap1 make all term
[...]
> dtlsc <server ip address> "DATA to send"
```
## Debug logs
To enable debug logs uncomment `CFLAGS += -DCONFIG_DTLS_DEBUG` in the Makefile.
Tinydtls supports setting the log level. See Makefile for more info.
## Configs and constraints
DTLS sock acts as a wrapper for the underlying DTLS stack and as such, the
constraints that applies specifically to the stack are also applied here.
For tinydtls, please refer to [dtls-echo README][1].
[1]: https://github.com/RIOT-OS/RIOT/blob/master/examples/dtls-echo/README.md

View File

@ -0,0 +1,243 @@
/*
* Copyright (C) 2019 HAW Hamburg
* Copyright (C) 2020 Freie Universität Berlin
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup tests
* @{
*
* @file
* @brief DTLS sock client test
*
* @author Aiman Ismail <muhammadaimanbin.ismail@haw-hamburg.de>
*/
#include <stdio.h>
#include "event/thread.h"
#include "event/timeout.h"
#include "net/sock/async/event.h"
#include "net/sock/udp.h"
#include "net/sock/dtls.h"
#include "net/ipv6/addr.h"
#include "net/credman.h"
#include "tinydtls_common.h"
#include "tinydtls_keys.h"
#ifndef CLIENT_SEND_TIMEOUT
/* timeout for client_send command */
#define CLIENT_SEND_TIMEOUT (1U * US_PER_SEC)
#endif
#define SOCK_DTLS_CLIENT_TAG (2)
#ifdef CONFIG_DTLS_ECC
static const ecdsa_public_key_t other_pubkeys[] = {
{ .x = ecdsa_pub_key_x, .y = ecdsa_pub_key_y },
};
static const credman_credential_t credential = {
.type = CREDMAN_TYPE_ECDSA,
.tag = SOCK_DTLS_CLIENT_TAG,
.params = {
.ecdsa = {
.private_key = ecdsa_priv_key,
.public_key = {
.x = ecdsa_pub_key_x,
.y = ecdsa_pub_key_y,
},
.client_keys = (ecdsa_public_key_t *)other_pubkeys,
.client_keys_size = ARRAY_SIZE(other_pubkeys),
}
},
};
#else /* ifdef CONFIG_DTLS_PSK */
static const uint8_t psk_id_0[] = PSK_DEFAULT_IDENTITY;
static const uint8_t psk_key_0[] = PSK_DEFAULT_KEY;
static const credman_credential_t credential = {
.type = CREDMAN_TYPE_PSK,
.tag = SOCK_DTLS_CLIENT_TAG,
.params = {
.psk = {
.key = { .s = psk_key_0, .len = sizeof(psk_key_0) - 1, },
.id = { .s = psk_id_0, .len = sizeof(psk_id_0) - 1, },
}
},
};
#endif
static void _timeout_handler(event_t *);
static uint8_t _recv_buf[512];
static sock_udp_t _udp_sock;
static sock_dtls_t _dtls_sock;
static event_timeout_t _timeouter;
static tinydtls_sock_event_t _timeout = {
.super.handler = _timeout_handler,
.sock = &_dtls_sock,
};
static bool _sending = false;
static void _close_sock(sock_dtls_t *sock)
{
sock_udp_t *udp_sock = sock_dtls_get_udp_sock(sock);
sock_dtls_close(sock);
sock_udp_close(udp_sock);
_sending = false;
}
static void _timeout_handler(event_t *ev)
{
tinydtls_sock_event_t *event = (tinydtls_sock_event_t *)ev;
puts("Session handshake timed out");
_close_sock(event->sock);
}
static void _dtls_handler(sock_dtls_t *sock, sock_async_flags_t type, void *arg)
{
sock_dtls_session_t session = { 0 };
event_timeout_clear(&_timeouter);
if (type & SOCK_ASYNC_CONN_RECV) {
char *send_data = arg;
puts("Session handshake received");
if (sock_dtls_recv(sock, &session, _recv_buf, sizeof(_recv_buf),
0) != -SOCK_DTLS_HANDSHAKE) {
puts("Error creating session");
return;
}
puts("Connection to server successful");
printf("Sending data \"%s\"\n", send_data);
if (sock_dtls_send(sock, &session, send_data, strlen(send_data),
0) < 0) {
puts("Error sending data");
sock_dtls_session_destroy(sock, &session);
_close_sock(sock);
}
else {
printf("Sent DTLS message\n");
event_timeout_set(&_timeouter, CLIENT_SEND_TIMEOUT);
}
}
if (type & SOCK_ASYNC_CONN_FIN) {
puts("Session was destroyed");
_close_sock(sock);
}
if (type & SOCK_ASYNC_CONN_RDY) {
puts("Session became ready");
}
if (type & SOCK_ASYNC_MSG_RECV) {
int res;
if ((res = sock_dtls_recv(sock, &session, _recv_buf, sizeof(_recv_buf),
0)) < 0) {
printf("Error receiving DTLS message\n");
}
else {
printf("Received %d bytes: \"%.*s\"\n", (int)res, (int)res,
(char *)_recv_buf);
}
puts("Terminating session");
sock_dtls_session_destroy(sock, &session);
_close_sock(sock);
}
else if (type & SOCK_ASYNC_MSG_SENT) {
puts("DTLS message was sent");
}
else if (type & SOCK_ASYNC_PATH_PROP) {
puts("Path property changed");
}
}
static int client_send(char *addr_str, char *data)
{
ssize_t res;
sock_dtls_session_t session;
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;
if (_sending) {
puts("Already in the process of sending");
}
event_timeout_init(&_timeouter, &event_queue_medium, &_timeout.super);
/* get interface */
char* iface = ipv6_addr_split_iface(addr_str);
if (iface) {
int pid = atoi(iface);
if (gnrc_netif_get_by_pid(pid) == NULL) {
puts("Invalid network interface");
return -1;
}
remote.netif = pid;
} else if (gnrc_netif_numof() == 1) {
/* assign the single interface found in gnrc_netif_numof() */
remote.netif = gnrc_netif_iter(NULL)->pid;
} else {
/* no interface is given, or given interface is invalid */
/* FIXME This probably is not valid with multiple interfaces */
remote.netif = SOCK_ADDR_ANY_NETIF;
}
if (!ipv6_addr_from_str((ipv6_addr_t *)remote.addr.ipv6, addr_str)) {
puts("Error parsing destination address");
return -1;
}
if (sock_udp_create(&_udp_sock, &local, NULL, 0) < 0) {
puts("Error creating UDP sock");
return -1;
}
if (sock_dtls_create(&_dtls_sock, &_udp_sock,
SOCK_DTLS_CLIENT_TAG,
SOCK_DTLS_1_2, SOCK_DTLS_CLIENT) < 0) {
puts("Error creating DTLS sock");
sock_udp_close(&_udp_sock);
return -1;
}
sock_dtls_event_init(&_dtls_sock, &event_queue_medium, _dtls_handler,
data);
res = credman_add(&credential);
if (res < 0 && res != CREDMAN_EXIST) {
/* ignore duplicate credentials */
printf("Error cannot add credential to system: %d\n", (int)res);
sock_dtls_close(&_dtls_sock);
sock_udp_close(&_udp_sock);
return -1;
}
_sending = true;
res = sock_dtls_session_init(&_dtls_sock, &remote, &session);
if (res <= 0) {
/* we have UDP sock, so we don't need to use _close_sock() */
sock_dtls_close(&_dtls_sock);
sock_udp_close(&_udp_sock);
_sending = false;
return res;
}
event_timeout_set(&_timeouter, CLIENT_SEND_TIMEOUT);
return 0;
}
int dtls_client_cmd(int argc, char **argv)
{
if (argc != 3) {
printf("usage %s <addr> <data>\n", argv[0]);
return 1;
}
return client_send(argv[1], argv[2]);
}

View File

@ -0,0 +1,203 @@
/*
* Copyright (C) 2019 HAW Hamburg
* Copyright (C) 2020 Freie Universität Berlin
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup tests
* @{
*
* @file
* @brief DTLS sock server test
*
* @author Aiman Ismail <muhammadaimanbin.ismail@haw-hamburg.de>
*/
#include <stdio.h>
#include "bitfield.h"
#include "event/thread.h"
#include "event/timeout.h"
#include "net/sock/async/event.h"
#include "net/sock/udp.h"
#include "net/sock/dtls.h"
#include "net/credman.h"
#include "msg.h"
#include "thread.h"
#include "tinydtls_common.h"
#include "tinydtls_keys.h"
#define SOCK_DTLS_SERVER_TAG (10)
#define READER_QUEUE_SIZE (8U)
#ifdef CONFIG_DTLS_ECC
static const ecdsa_public_key_t other_pubkeys[] = {
{ .x = ecdsa_pub_key_x, .y = ecdsa_pub_key_y },
};
static const credman_credential_t credential = {
.type = CREDMAN_TYPE_ECDSA,
.tag = SOCK_DTLS_SERVER_TAG,
.params = {
.ecdsa = {
.private_key = ecdsa_priv_key,
.public_key = {
.x = ecdsa_pub_key_x,
.y = ecdsa_pub_key_y,
},
.client_keys = (ecdsa_public_key_t *)other_pubkeys,
.client_keys_size = ARRAY_SIZE(other_pubkeys),
},
},
};
#else /* #ifdef CONFIG_DTLS_PSK */
static const uint8_t psk_key_0[] = PSK_DEFAULT_KEY;
static const credman_credential_t credential = {
.type = CREDMAN_TYPE_PSK,
.tag = SOCK_DTLS_SERVER_TAG,
.params = {
.psk = {
.key = { .s = psk_key_0, .len = sizeof(psk_key_0) - 1, },
},
},
};
#endif
static void _close_handler(event_t *);
static uint8_t _recv_buf[512];
static sock_udp_t _udp_sock;
static sock_dtls_t _dtls_sock;
static tinydtls_sock_event_t _close = {
.super.handler = _close_handler,
.sock = &_dtls_sock,
};
static bool _active = false;
static void _close_sock(sock_dtls_t *sock)
{
sock_udp_t *udp_sock = sock_dtls_get_udp_sock(sock);
sock_dtls_close(sock);
sock_udp_close(udp_sock);
_active = false;
puts("Terminated server");
}
static void _close_handler(event_t *ev)
{
tinydtls_sock_event_t *event = (tinydtls_sock_event_t *)ev;
puts("Terminating server");
_close_sock(event->sock);
}
static void _dtls_handler(sock_dtls_t *sock, sock_async_flags_t type, void *arg)
{
(void)arg;
if (!_active) {
puts("Error: DTLS server is not running");
return;
}
if (type & SOCK_ASYNC_CONN_RECV) {
sock_dtls_session_t session = { 0 };
puts("Session handshake received");
if (sock_dtls_recv(sock, &session, _recv_buf, sizeof(_recv_buf),
0) != -SOCK_DTLS_HANDSHAKE) {
puts("Error creating session");
return;
}
puts("New client connected");
}
if (type & SOCK_ASYNC_CONN_FIN) {
puts("Session was destroyed by peer");
}
if (type & SOCK_ASYNC_CONN_RDY) {
puts("Session became ready");
}
if (type & SOCK_ASYNC_MSG_RECV) {
sock_dtls_session_t session = { 0 };
ssize_t res;
res = sock_dtls_recv(sock, &session, _recv_buf, sizeof(_recv_buf), 0);
if (res >= 0) {
printf("Received %d bytes -- (echo)\n", (int)res);
res = sock_dtls_send(sock, &session, _recv_buf, (size_t)res, 0);
if (res < 0) {
printf("Error resending DTLS message: %d\n", (int)res);
}
}
}
}
static int start_server(void)
{
/* Only one instance of the server */
if (_active) {
puts("Error: server already running");
return 1;
}
/* Start the server */
ssize_t res;
sock_udp_ep_t local = SOCK_IPV6_EP_ANY;
local.port = DTLS_DEFAULT_PORT;
sock_udp_create(&_udp_sock, &local, NULL, 0);
res = credman_add(&credential);
if (res < 0 && res != CREDMAN_EXIST) {
/* ignore duplicate credentials */
printf("Error cannot add credential to system: %d\n", (int)res);
return 1;
}
res = sock_dtls_create(&_dtls_sock, &_udp_sock, SOCK_DTLS_SERVER_TAG,
SOCK_DTLS_1_2, SOCK_DTLS_SERVER);
if (res < 0) {
puts("Error creating DTLS sock");
return 1;
}
_active = true;
sock_dtls_event_init(&_dtls_sock, &event_queue_medium, _dtls_handler,
NULL);
return 0;
}
static int stop_server(void)
{
/* check if server is running at all */
if (!_active) {
puts("Error: DTLS server is not running");
return 1;
}
event_post(&event_queue_medium, &_close.super);
return 0;
}
int dtls_server_cmd(int argc, char **argv)
{
if (argc < 2) {
printf("usage: %s start | stop\n", argv[0]);
return 1;
}
if (strcmp(argv[1], "start") == 0) {
return start_server();
}
else if (strcmp(argv[1], "stop") == 0) {
return stop_server();
}
else {
printf("Error: invalid command. Usage: %s start | stop\n", argv[0]);
return 1;
}
return 0;
}

View File

@ -0,0 +1,43 @@
/*
* Copyright (C) 2019 HAW Hamburg
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup examples
* @{
*
* @file
* @brief Test application for DTLS sock
*
* @author Aiman Ismail <muhammadaimanbin.ismail@haw-hamburg.de>
*/
#include <stdio.h>
#include "shell.h"
extern int dtls_client_cmd(int argc, char **argv);
extern int dtls_server_cmd(int argc, char **argv);
static const shell_command_t shell_commands[] = {
{ "dtlsc", "Start a DTLS client", dtls_client_cmd },
{ "dtlss", "Start and stop a DTLS server", dtls_server_cmd },
{ NULL, NULL, NULL }
};
int main(void)
{
puts("DTLS sock example application");
/* start shell */
puts("All up, running the shell now");
char line_buf[SHELL_DEFAULT_BUFSIZE];
shell_run(shell_commands, line_buf, SHELL_DEFAULT_BUFSIZE);
/* should never be reached */
return 0;
}

View File

@ -0,0 +1,39 @@
/*
* Copyright (C) 2020 Freie Universität Berlin
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup tests
*
* @{
* @file
* @brief Common definitions for client and server in tinyDTLS `sock_async` test
*
* @author Martine Lenders <m.lenders@fu-berlin.de>
*/
#ifndef TINYDTLS_COMMON_H
#define TINYDTLS_COMMON_H
#include "event.h"
#ifdef __cplusplus
extern "C"
{
#endif
#ifndef DTLS_DEFAULT_PORT
#define DTLS_DEFAULT_PORT (20220) /* DTLS default port */
#endif
typedef struct {
event_t super;
sock_dtls_t *sock;
} tinydtls_sock_event_t;
#ifdef __cplusplus
}
#endif
#endif /* TINYDTLS_COMMON_H */

View File

@ -0,0 +1,66 @@
/*
* Copyright (C) 2018 Inria
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup examples
* @{
*
* @file
* @brief PSK and RPK keys for the dtls-sock example.
*
* @author Raul Fuentes <raul.fuentes-samaniego@inria.fr>
*
* @}
*/
#ifndef TINYDTLS_KEYS_H
#define TINYDTLS_KEYS_H
#ifdef __cplusplus
extern "C" {
#endif
/*
* Default keys examples for tinyDTLS (for RIOT, Linux and Contiki)
*/
#ifdef CONFIG_DTLS_PSK
#define PSK_DEFAULT_IDENTITY "Client_identity"
#define PSK_DEFAULT_KEY "secretPSK"
#define PSK_OPTIONS "i:k:"
#define PSK_ID_MAXLEN 32
#define PSK_MAXLEN 32
#endif /* CONFIG_DTLS_PSK */
#ifdef CONFIG_DTLS_ECC
static const unsigned char ecdsa_priv_key[] = {
0x41, 0xC1, 0xCB, 0x6B, 0x51, 0x24, 0x7A, 0x14,
0x43, 0x21, 0x43, 0x5B, 0x7A, 0x80, 0xE7, 0x14,
0x89, 0x6A, 0x33, 0xBB, 0xAD, 0x72, 0x94, 0xCA,
0x40, 0x14, 0x55, 0xA1, 0x94, 0xA9, 0x49, 0xFA
};
static const unsigned char ecdsa_pub_key_x[] = {
0x36, 0xDF, 0xE2, 0xC6, 0xF9, 0xF2, 0xED, 0x29,
0xDA, 0x0A, 0x9A, 0x8F, 0x62, 0x68, 0x4E, 0x91,
0x63, 0x75, 0xBA, 0x10, 0x30, 0x0C, 0x28, 0xC5,
0xE4, 0x7C, 0xFB, 0xF2, 0x5F, 0xA5, 0x8F, 0x52
};
static const unsigned char ecdsa_pub_key_y[] = {
0x71, 0xA0, 0xD4, 0xFC, 0xDE, 0x1A, 0xB8, 0x78,
0x5A, 0x3C, 0x78, 0x69, 0x35, 0xA7, 0xCF, 0xAB,
0xE9, 0x3F, 0x98, 0x72, 0x09, 0xDA, 0xED, 0x0B,
0x4F, 0xAB, 0xC3, 0x6F, 0xC7, 0x72, 0xF8, 0x29
};
#endif /* CONFIG_DTLS_ECC */
#ifdef __cplusplus
}
#endif
#endif /* TINYDTLS_KEYS_H */