mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
net/dtls/dsm: add DTLS session management module
This commit is contained in:
parent
ccfd3ee980
commit
5567f13258
@ -38,6 +38,9 @@ endif
|
||||
ifneq (,$(filter dhcpv6,$(USEMODULE)))
|
||||
DIRS += net/application_layer/dhcpv6
|
||||
endif
|
||||
ifneq (,$(filter dsm,$(USEMODULE)))
|
||||
DIRS += net/dsm
|
||||
endif
|
||||
ifneq (,$(filter dummy_thread,$(USEMODULE)))
|
||||
DIRS += test_utils/dummy_thread
|
||||
endif
|
||||
|
@ -174,6 +174,11 @@ void auto_init(void)
|
||||
extern void auto_init_loramac(void);
|
||||
auto_init_loramac();
|
||||
}
|
||||
if (IS_USED(MODULE_DSM)) {
|
||||
LOG_DEBUG("Auto init dsm.\n");
|
||||
extern void dsm_init(void);
|
||||
dsm_init();
|
||||
}
|
||||
|
||||
/* initialize USB devices */
|
||||
if (IS_USED(MODULE_AUTO_INIT_USBUS)) {
|
||||
|
123
sys/include/net/dsm.h
Normal file
123
sys/include/net/dsm.h
Normal file
@ -0,0 +1,123 @@
|
||||
/*
|
||||
* Copyright (C) 2021 ML!PA Consulting GmbH
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup net_dsm DTLS Session Management (DSM)
|
||||
* @ingroup net net_dtls
|
||||
* @brief This module provides functionality to store and retrieve session
|
||||
* information of DTLS connections.
|
||||
*
|
||||
* dsm allows to store necessary session information so that not every application
|
||||
* has to provide the potentially maximum number of possible session objects.
|
||||
* Session storage can be offloaded to this generic module.
|
||||
*
|
||||
* @{\
|
||||
*
|
||||
* @file
|
||||
* @brief DTLS session management module definition
|
||||
*
|
||||
* @note This module does not accept or close DTLS sessions, it merely
|
||||
* provides a place to store session objects.
|
||||
*
|
||||
* @author János Brodbeck <janos.brodbeck@ml-pa.com>
|
||||
*/
|
||||
|
||||
#ifndef NET_DSM_H
|
||||
#define NET_DSM_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include "net/sock/dtls.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Maximum number of maintained DTLS sessions (tinyDTLS)
|
||||
*/
|
||||
#ifndef DTLS_PEER_MAX
|
||||
#define DTLS_PEER_MAX (1)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Session management states
|
||||
*/
|
||||
typedef enum {
|
||||
NO_SPACE = -1,
|
||||
SESSION_STATE_NONE = 0,
|
||||
SESSION_STATE_HANDSHAKE,
|
||||
SESSION_STATE_ESTABLISHED
|
||||
} dsm_state_t;
|
||||
|
||||
/**
|
||||
* @brief Initialize the DTLS session management
|
||||
*
|
||||
* Must call once before first use.
|
||||
*/
|
||||
void dsm_init(void);
|
||||
|
||||
/**
|
||||
* @brief Stores a session
|
||||
*
|
||||
* Stores a given session in the internal storage of the session management.
|
||||
* If the session is already stored only the state will be updated when the session
|
||||
* gets established.
|
||||
*
|
||||
* @param[in] sock @ref sock_dtls_t, which the session is created on
|
||||
* @param[in] session Session to store
|
||||
* @param[in] new_state New state of the session
|
||||
* @param[in] restore Indicates, whether the session object should be restored
|
||||
* when an already established session is found
|
||||
*
|
||||
* @return Previous state of the session. If no session existed before it returns
|
||||
* SESSION_STATE_NONE. If no space is available it returns NO_SPACE.
|
||||
*/
|
||||
dsm_state_t dsm_store(sock_dtls_t *sock, sock_dtls_session_t *session,
|
||||
dsm_state_t new_state, bool restore);
|
||||
|
||||
/**
|
||||
* @brief Removes a session
|
||||
*
|
||||
* Removes a given session in the internal storage of the session management.
|
||||
*
|
||||
* @param[in] sock @ref sock_dtls_t, which the session is created on
|
||||
* @param[in] session Session to store
|
||||
*/
|
||||
void dsm_remove(sock_dtls_t *sock, sock_dtls_session_t *session);
|
||||
|
||||
/**
|
||||
* @brief Returns the maximum number of sessions slots
|
||||
*
|
||||
* @return Number of session slots.
|
||||
*/
|
||||
uint8_t dsm_get_num_maximum_slots(void);
|
||||
|
||||
/**
|
||||
* @brief Returns the number of available session slots
|
||||
*
|
||||
* @return Number of available session slots in the session management.
|
||||
*/
|
||||
uint8_t dsm_get_num_available_slots(void);
|
||||
|
||||
/**
|
||||
* @brief Returns the least recently used session
|
||||
*
|
||||
* @param[in] sock @ref sock_dtls_t, which the session is created on
|
||||
* @param[out] session Oldest used session
|
||||
*
|
||||
* @return 1, on success
|
||||
* @return -1, when no session is stored
|
||||
*/
|
||||
ssize_t dsm_get_least_recently_used_session(sock_dtls_t *sock, sock_dtls_session_t *session);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* NET_DSM_H */
|
||||
/** @} */
|
2
sys/net/dsm/Makefile
Normal file
2
sys/net/dsm/Makefile
Normal file
@ -0,0 +1,2 @@
|
||||
MODULE = dsm
|
||||
include $(RIOTBASE)/Makefile.base
|
1
sys/net/dsm/Makefile.dep
Normal file
1
sys/net/dsm/Makefile.dep
Normal file
@ -0,0 +1 @@
|
||||
FEATURES_REQUIRED += sock_dtls
|
186
sys/net/dsm/dsm.c
Normal file
186
sys/net/dsm/dsm.c
Normal file
@ -0,0 +1,186 @@
|
||||
/*
|
||||
* Copyright (C) 2021 ML!PA Consulting GmbH
|
||||
*
|
||||
* 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 net_dsm
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief DTLS Session Management module implementation
|
||||
*
|
||||
* @author János Brodbeck <janos.brodbeck@ml-pa.com>
|
||||
*
|
||||
* @}
|
||||
*/
|
||||
|
||||
#include "net/dsm.h"
|
||||
#include "mutex.h"
|
||||
#include "net/sock/util.h"
|
||||
#include "xtimer.h"
|
||||
|
||||
#define ENABLE_DEBUG 0
|
||||
#include "debug.h"
|
||||
|
||||
typedef struct {
|
||||
sock_dtls_t *sock;
|
||||
sock_dtls_session_t session;
|
||||
dsm_state_t state;
|
||||
uint32_t last_used_sec;
|
||||
} dsm_session_t;
|
||||
|
||||
static int _find_session(sock_dtls_t *sock, sock_dtls_session_t *to_find,
|
||||
dsm_session_t **session);
|
||||
|
||||
static mutex_t _lock;
|
||||
static dsm_session_t _sessions[DTLS_PEER_MAX];
|
||||
static uint8_t _available_slots;
|
||||
|
||||
void dsm_init(void)
|
||||
{
|
||||
mutex_init(&_lock);
|
||||
_available_slots = DTLS_PEER_MAX;
|
||||
}
|
||||
|
||||
dsm_state_t dsm_store(sock_dtls_t *sock, sock_dtls_session_t *session,
|
||||
dsm_state_t new_state, bool restore)
|
||||
{
|
||||
sock_udp_ep_t ep;
|
||||
dsm_session_t *session_slot = NULL;
|
||||
dsm_state_t prev_state = NO_SPACE;
|
||||
mutex_lock(&_lock);
|
||||
|
||||
ssize_t res = _find_session(sock, session, &session_slot);
|
||||
if (res < 0) {
|
||||
DEBUG("dsm: no space for session to store\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
prev_state = session_slot->state;
|
||||
if (session_slot->state != SESSION_STATE_ESTABLISHED) {
|
||||
session_slot->state = new_state;
|
||||
}
|
||||
|
||||
/* no existing session found */
|
||||
if (res == 0) {
|
||||
DEBUG("dsm: no existing session found, storing as new session\n")
|
||||
sock_dtls_session_get_udp_ep(session, &ep);
|
||||
sock_dtls_session_set_udp_ep(&session_slot->session, &ep);
|
||||
session_slot->sock = sock;
|
||||
_available_slots--;
|
||||
}
|
||||
|
||||
/* existing session found and session should be restored */
|
||||
if (res == 1 && restore) {
|
||||
DEBUG("dsm: existing session found, restoring\n")
|
||||
memcpy(session, &session_slot->session, sizeof(sock_dtls_session_t));
|
||||
}
|
||||
session_slot->last_used_sec = (uint32_t)(xtimer_now_usec64() / US_PER_SEC);
|
||||
|
||||
out:
|
||||
mutex_unlock(&_lock);
|
||||
return prev_state;
|
||||
}
|
||||
|
||||
void dsm_remove(sock_dtls_t *sock, sock_dtls_session_t *session)
|
||||
{
|
||||
dsm_session_t *session_slot = NULL;
|
||||
mutex_lock(&_lock);
|
||||
if (_find_session(sock, session, &session_slot) == 1) {
|
||||
if (session_slot->state == SESSION_STATE_NONE) {
|
||||
/* session has already been removed. Can happen when we remove the session
|
||||
before we get the close ACK of the remote peer (e.g. force reset of peer)
|
||||
and then get an ACK (= SOCK_ASYNC_CONN_FIN event) of the remote and
|
||||
call this function again. */
|
||||
goto out;
|
||||
}
|
||||
|
||||
session_slot->state = SESSION_STATE_NONE;
|
||||
_available_slots++;
|
||||
DEBUG("dsm: removed session\n");
|
||||
} else {
|
||||
DEBUG("dsm: could not find session to remove, it was probably already removed\n");
|
||||
}
|
||||
out:
|
||||
mutex_unlock(&_lock);
|
||||
}
|
||||
|
||||
uint8_t dsm_get_num_available_slots(void)
|
||||
{
|
||||
return _available_slots;
|
||||
}
|
||||
|
||||
uint8_t dsm_get_num_maximum_slots(void)
|
||||
{
|
||||
return DTLS_PEER_MAX;
|
||||
}
|
||||
|
||||
ssize_t dsm_get_least_recently_used_session(sock_dtls_t *sock, sock_dtls_session_t *session)
|
||||
{
|
||||
int res = -1;
|
||||
dsm_session_t *session_slot = NULL;
|
||||
|
||||
if (dsm_get_num_available_slots() == DTLS_PEER_MAX) {
|
||||
return res;
|
||||
}
|
||||
|
||||
mutex_lock(&_lock);
|
||||
for (uint8_t i=0; i < DTLS_PEER_MAX; i++) {
|
||||
if (_sessions[i].state != SESSION_STATE_ESTABLISHED) {
|
||||
continue;
|
||||
}
|
||||
if (_sessions[i].sock != sock) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (session_slot == NULL ||
|
||||
session_slot->last_used_sec > _sessions[i].last_used_sec) {
|
||||
session_slot = &_sessions[i];
|
||||
}
|
||||
}
|
||||
|
||||
if (session_slot) {
|
||||
memcpy(session, &session_slot->session, sizeof(sock_dtls_session_t));
|
||||
res = 1;
|
||||
}
|
||||
mutex_unlock(&_lock);
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Search for existing session or empty slot for new one
|
||||
* Returns 1, if existing session found
|
||||
* Returns 0, if empty slot found
|
||||
* Returns -1, if no existing or empty session found */
|
||||
static int _find_session(sock_dtls_t *sock, sock_dtls_session_t *to_find,
|
||||
dsm_session_t **session)
|
||||
{
|
||||
|
||||
/* FIXME: optimize search / data structure */
|
||||
sock_udp_ep_t to_find_ep, curr_ep;
|
||||
dsm_session_t *empty_session = NULL;
|
||||
|
||||
sock_dtls_session_get_udp_ep(to_find, &to_find_ep);
|
||||
for (uint8_t i=0; i < DTLS_PEER_MAX; i++) {
|
||||
if (_sessions[i].state == SESSION_STATE_NONE) {
|
||||
empty_session = &_sessions[i];
|
||||
continue;
|
||||
}
|
||||
|
||||
sock_dtls_session_get_udp_ep(&_sessions[i].session, &curr_ep);
|
||||
if (sock_udp_ep_equal(&curr_ep, &to_find_ep) && _sessions[i].sock == sock) {
|
||||
/* found existing session */
|
||||
*session = &_sessions[i];
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (empty_session) {
|
||||
*session = empty_session;
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
Loading…
Reference in New Issue
Block a user