mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
gcoap: multi-transport support for listeners
This commit is contained in:
parent
90eae8e0a4
commit
287bfdc10d
@ -75,6 +75,7 @@ static const char *_link_params[] = {
|
||||
static gcoap_listener_t _listener = {
|
||||
&_resources[0],
|
||||
ARRAY_SIZE(_resources),
|
||||
GCOAP_SOCKET_TYPE_UNDEF,
|
||||
_encode_link,
|
||||
NULL,
|
||||
NULL
|
||||
|
@ -704,6 +704,36 @@ typedef int (*gcoap_request_matcher_t)(gcoap_listener_t *listener,
|
||||
const coap_resource_t **resource,
|
||||
coap_pkt_t *pdu);
|
||||
|
||||
/**
|
||||
* @brief CoAP socket types
|
||||
*
|
||||
* May be used as flags for @ref gcoap_listener_t, but must be used numerically
|
||||
* with @ref gcoap_req_send_tl().
|
||||
*/
|
||||
typedef enum {
|
||||
GCOAP_SOCKET_TYPE_UNDEF = 0x0, /**< undefined */
|
||||
GCOAP_SOCKET_TYPE_UDP = 0x1, /**< Unencrypted UDP transport */
|
||||
GCOAP_SOCKET_TYPE_DTLS = 0x2, /**< DTLS-over-UDP transport */
|
||||
} gcoap_socket_type_t;
|
||||
|
||||
/**
|
||||
* @brief CoAP socket to handle multiple transport types
|
||||
*/
|
||||
typedef struct {
|
||||
gcoap_socket_type_t type; /**< Type of stored socket */
|
||||
union {
|
||||
sock_udp_t *udp;
|
||||
#if IS_USED(MODULE_GCOAP_DTLS) || defined(DOXYGEN)
|
||||
sock_dtls_t *dtls;
|
||||
#endif
|
||||
} socket; /**< Stored socket */
|
||||
#if IS_USED(MODULE_GCOAP_DTLS) || defined(DOXYGEN)
|
||||
sock_dtls_session_t ctx_dtls_session; /**< Session object for the stored socket.
|
||||
Used for exchanging a session between
|
||||
functions. */
|
||||
#endif
|
||||
} gcoap_socket_t;
|
||||
|
||||
/**
|
||||
* @brief A modular collection of resources for a server
|
||||
*/
|
||||
@ -711,6 +741,16 @@ struct gcoap_listener {
|
||||
const coap_resource_t *resources; /**< First element in the array of
|
||||
* resources; must order alphabetically */
|
||||
size_t resources_len; /**< Length of array */
|
||||
/**
|
||||
* @brief Transport type for the listener
|
||||
*
|
||||
* Any transport supported by the implementation can be set as a flag.
|
||||
* If @ref GCOAP_SOCKET_TYPE_UNDEF is set, the listener listens on all
|
||||
* supported transports. If non of the transports beyond UDP are compiled in
|
||||
* (i.e. no usage of modules `gcoap_dtls`, ...) this will be ignored and
|
||||
* @ref GCOAP_SOCKET_TYPE_UDP assumed.
|
||||
*/
|
||||
gcoap_socket_type_t tl_type;
|
||||
gcoap_link_encoder_t link_encoder; /**< Writes a link for a resource */
|
||||
struct gcoap_listener *next; /**< Next listener in list */
|
||||
|
||||
@ -750,33 +790,6 @@ typedef struct {
|
||||
size_t pdu_len; /**< Length of pdu_buf */
|
||||
} gcoap_resend_t;
|
||||
|
||||
/**
|
||||
* @brief Coap socket types
|
||||
*/
|
||||
typedef enum {
|
||||
GCOAP_SOCKET_TYPE_UNDEF = 0,
|
||||
GCOAP_SOCKET_TYPE_UDP,
|
||||
GCOAP_SOCKET_TYPE_DTLS
|
||||
} gcoap_socket_type_t;
|
||||
|
||||
/**
|
||||
* @brief Coap socket to handle multiple transport types
|
||||
*/
|
||||
typedef struct {
|
||||
gcoap_socket_type_t type; /**< Type of stored socket */
|
||||
union {
|
||||
sock_udp_t *udp;
|
||||
#if IS_USED(MODULE_GCOAP_DTLS) || defined(DOXYGEN)
|
||||
sock_dtls_t *dtls;
|
||||
#endif
|
||||
} socket; /**< Stored socket */
|
||||
#if IS_USED(MODULE_GCOAP_DTLS) || defined(DOXYGEN)
|
||||
sock_dtls_session_t ctx_dtls_session; /**< Session object for the stored socket.
|
||||
Used for exchanging a session between
|
||||
functions. */
|
||||
#endif
|
||||
} gcoap_socket_t;
|
||||
|
||||
/**
|
||||
* @brief Memo to handle a response for a request
|
||||
*/
|
||||
@ -918,8 +931,9 @@ static inline ssize_t gcoap_request(coap_pkt_t *pdu, uint8_t *buf, size_t len,
|
||||
* @param[in] resp_handler Callback when response received, may be NULL
|
||||
* @param[in] context User defined context passed to the response handler
|
||||
* @param[in] tl_type The transport type to use for send. When
|
||||
* GCOAP_SOCKET_TYPE_UNDEF is selected, the highest
|
||||
* available (by value) will be selected.
|
||||
* @ref GCOAP_SOCKET_TYPE_UNDEF is selected, the highest
|
||||
* available (by value) will be selected. Only single
|
||||
* types are allowed, not a combination of them.
|
||||
*
|
||||
* @return length of the packet
|
||||
* @return -ENOTCONN, if DTLS was used and session establishment failed
|
||||
@ -940,7 +954,7 @@ ssize_t gcoap_req_send_tl(const uint8_t *buf, size_t len,
|
||||
* @param[in] resp_handler Callback when response received, may be NULL
|
||||
* @param[in] context User defined context passed to the response handler
|
||||
*
|
||||
* @note The highest supported (by value) coap_socket_type_t will be selected
|
||||
* @note The highest supported (by value) gcoap_socket_type_t will be selected
|
||||
* as transport type.
|
||||
*
|
||||
* @return length of the packet
|
||||
@ -1037,6 +1051,35 @@ uint8_t gcoap_op_state(void);
|
||||
* @brief Get the resource list, currently only `CoRE Link Format`
|
||||
* (COAP_FORMAT_LINK) supported
|
||||
*
|
||||
* @deprecated Will be an alias for @ref gcoap_get_resource_list after the
|
||||
* 2022.01 release. Will be removed after the 2022.04 release.
|
||||
*
|
||||
* If @p buf := NULL, nothing will be written but the size of the resulting
|
||||
* resource list is computed and returned.
|
||||
*
|
||||
* @param[out] buf output buffer to write resource list into, my be NULL
|
||||
* @param[in] maxlen length of @p buf, ignored if @p buf is NULL
|
||||
* @param[in] cf content format to use for the resource list, currently
|
||||
* only COAP_FORMAT_LINK supported
|
||||
* @param[in] tl_type Transport type to get the list for.
|
||||
* @ref GCOAP_SOCKET_TYPE_UNDEF for all transport types.
|
||||
* If non of the transports beyond UDP are compiled in
|
||||
* (i.e. usage of modules no `gcoap_dtls`, ...) this will
|
||||
* be ignored and @ref GCOAP_SOCKET_TYPE_UDP assumed.
|
||||
*
|
||||
* @todo add support for `JSON CoRE Link Format`
|
||||
* @todo add support for 'CBOR CoRE Link Format`
|
||||
*
|
||||
* @return the number of bytes written to @p buf
|
||||
* @return -1 on error
|
||||
*/
|
||||
int gcoap_get_resource_list_tl(void *buf, size_t maxlen, uint8_t cf,
|
||||
gcoap_socket_type_t tl_type);
|
||||
|
||||
/**
|
||||
* @brief Get the resource list for all transports,
|
||||
* currently only `CoRE Link Format` (COAP_FORMAT_LINK) supported
|
||||
*
|
||||
* If @p buf := NULL, nothing will be written but the size of the resulting
|
||||
* resource list is computed and returned.
|
||||
*
|
||||
@ -1051,7 +1094,10 @@ uint8_t gcoap_op_state(void);
|
||||
* @return the number of bytes written to @p buf
|
||||
* @return -1 on error
|
||||
*/
|
||||
int gcoap_get_resource_list(void *buf, size_t maxlen, uint8_t cf);
|
||||
static inline int gcoap_get_resource_list(void *buf, size_t maxlen, uint8_t cf)
|
||||
{
|
||||
return gcoap_get_resource_list_tl(buf, maxlen, cf, GCOAP_SOCKET_TYPE_UNDEF);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Writes a resource in CoRE Link Format to a provided buffer.
|
||||
|
@ -208,6 +208,13 @@ typedef struct {
|
||||
BITFIELD(opt_crit, CONFIG_NANOCOAP_NOPTS_MAX); /**< unhandled critical option */
|
||||
#ifdef MODULE_GCOAP
|
||||
uint32_t observe_value; /**< observe value */
|
||||
/**
|
||||
* @brief transport the packet was received over
|
||||
* @see @ref gcoap_socket_type_t for values.
|
||||
* @note @ref gcoap_socket_type_t can not be used, as this would
|
||||
* cyclically include the @ref net_gcoap header.
|
||||
*/
|
||||
uint32_t tl_type;
|
||||
#endif
|
||||
} coap_pkt_t;
|
||||
|
||||
|
@ -66,7 +66,8 @@ static size_t _handle_req(gcoap_socket_t *sock, coap_pkt_t *pdu, uint8_t *buf,
|
||||
static void _expire_request(gcoap_request_memo_t *memo);
|
||||
static void _find_req_memo(gcoap_request_memo_t **memo_ptr, coap_pkt_t *pdu,
|
||||
const sock_udp_ep_t *remote, bool by_mid);
|
||||
static int _find_resource(coap_pkt_t *pdu,
|
||||
static int _find_resource(gcoap_socket_type_t tl_type,
|
||||
coap_pkt_t *pdu,
|
||||
const coap_resource_t **resource_ptr,
|
||||
gcoap_listener_t **listener_ptr);
|
||||
static int _find_observer(sock_udp_ep_t **observer, sock_udp_ep_t *remote);
|
||||
@ -92,6 +93,7 @@ const coap_resource_t _default_resources[] = {
|
||||
static gcoap_listener_t _default_listener = {
|
||||
&_default_resources[0],
|
||||
ARRAY_SIZE(_default_resources),
|
||||
GCOAP_SOCKET_TYPE_UNDEF,
|
||||
NULL,
|
||||
NULL,
|
||||
_request_matcher_default
|
||||
@ -130,7 +132,7 @@ static sock_udp_t _sock_udp;
|
||||
#if IS_USED(MODULE_GCOAP_DTLS)
|
||||
/* DTLS variables and definitions */
|
||||
#define SOCK_DTLS_CLIENT_TAG (2)
|
||||
|
||||
static sock_udp_t _sock_dtls_base;
|
||||
static sock_dtls_t _sock_dtls;
|
||||
static kernel_pid_t _auth_waiting_thread;
|
||||
|
||||
@ -147,11 +149,7 @@ static void *_event_loop(void *arg)
|
||||
memset(&local, 0, sizeof(sock_udp_ep_t));
|
||||
local.family = AF_INET6;
|
||||
local.netif = SOCK_ADDR_ANY_NETIF;
|
||||
if (IS_USED(MODULE_GCOAP_DTLS)) {
|
||||
local.port = CONFIG_GCOAPS_PORT;
|
||||
} else {
|
||||
local.port = CONFIG_GCOAP_PORT;
|
||||
}
|
||||
local.port = CONFIG_GCOAP_PORT;
|
||||
int res = sock_udp_create(&_sock_udp, &local, NULL, 0);
|
||||
if (res < 0) {
|
||||
DEBUG("gcoap: cannot create sock: %d\n", res);
|
||||
@ -159,20 +157,25 @@ static void *_event_loop(void *arg)
|
||||
}
|
||||
|
||||
event_queue_init(&_queue);
|
||||
sock_udp_event_init(&_sock_udp, &_queue, _on_sock_udp_evt, NULL);
|
||||
|
||||
if (IS_USED(MODULE_GCOAP_DTLS)) {
|
||||
#if IS_USED(MODULE_GCOAP_DTLS)
|
||||
if (sock_dtls_create(&_sock_dtls, &_sock_udp,
|
||||
local.port = CONFIG_GCOAPS_PORT;
|
||||
if (sock_udp_create(&_sock_dtls_base, &local, NULL, 0)) {
|
||||
DEBUG("gcoap: error creating DTLS transport sock\n");
|
||||
return 0;
|
||||
}
|
||||
if (sock_dtls_create(&_sock_dtls, &_sock_dtls_base,
|
||||
CREDMAN_TAG_EMPTY,
|
||||
SOCK_DTLS_1_2, SOCK_DTLS_SERVER) < 0) {
|
||||
DEBUG("gcoap: error creating DTLS sock");
|
||||
sock_udp_close(&_sock_udp);
|
||||
DEBUG("gcoap: error creating DTLS sock\n");
|
||||
sock_udp_close(&_sock_dtls_base);
|
||||
return 0;
|
||||
}
|
||||
sock_dtls_event_init(&_sock_dtls, &_queue, _on_sock_dtls_evt,
|
||||
NULL);
|
||||
#endif
|
||||
} else {
|
||||
sock_udp_event_init(&_sock_udp, &_queue, _on_sock_udp_evt, NULL);
|
||||
}
|
||||
|
||||
event_loop(&_queue);
|
||||
@ -537,7 +540,7 @@ static size_t _handle_req(gcoap_socket_t *sock, coap_pkt_t *pdu, uint8_t *buf,
|
||||
gcoap_observe_memo_t *memo = NULL;
|
||||
gcoap_observe_memo_t *resource_memo = NULL;
|
||||
|
||||
switch (_find_resource(pdu, &resource, &listener)) {
|
||||
switch (_find_resource(sock->type, pdu, &resource, &listener)) {
|
||||
case GCOAP_RESOURCE_WRONG_METHOD:
|
||||
return gcoap_response(pdu, buf, len, COAP_CODE_METHOD_NOT_ALLOWED);
|
||||
case GCOAP_RESOURCE_NO_PATH:
|
||||
@ -631,6 +634,7 @@ static size_t _handle_req(gcoap_socket_t *sock, coap_pkt_t *pdu, uint8_t *buf,
|
||||
return -1;
|
||||
}
|
||||
|
||||
pdu->tl_type = (uint32_t)sock->type;
|
||||
ssize_t pdu_len = resource->handler(pdu, buf, len, resource->context);
|
||||
if (pdu_len < 0) {
|
||||
pdu_len = gcoap_response(pdu, buf, len,
|
||||
@ -689,6 +693,7 @@ static int _request_matcher_default(gcoap_listener_t *listener,
|
||||
/*
|
||||
* Searches listener registrations for the resource matching the path in a PDU.
|
||||
*
|
||||
* param[in] tl_type -- transport the request for the resource came over.
|
||||
* param[in] pdu -- the PDU to check the resource for
|
||||
* param[out] resource_ptr -- found resource
|
||||
* param[out] listener_ptr -- listener for found resource
|
||||
@ -697,7 +702,8 @@ static int _request_matcher_default(gcoap_listener_t *listener,
|
||||
* code didn't match and `GCOAP_RESOURCE_NO_PATH` if no matching
|
||||
* resource was found.
|
||||
*/
|
||||
static int _find_resource(coap_pkt_t *pdu,
|
||||
static int _find_resource(gcoap_socket_type_t tl_type,
|
||||
coap_pkt_t *pdu,
|
||||
const coap_resource_t **resource_ptr,
|
||||
gcoap_listener_t **listener_ptr)
|
||||
{
|
||||
@ -708,8 +714,17 @@ static int _find_resource(coap_pkt_t *pdu,
|
||||
|
||||
while (listener) {
|
||||
const coap_resource_t *resource;
|
||||
int res = listener->request_matcher(listener, &resource, pdu);
|
||||
int res;
|
||||
|
||||
/* only makes sense to check if non-UDP transports are supported,
|
||||
* so check if module is used first. */
|
||||
if (IS_USED(MODULE_GCOAP_DTLS) &&
|
||||
(listener->tl_type != GCOAP_SOCKET_TYPE_UNDEF) &&
|
||||
!(listener->tl_type & tl_type)) {
|
||||
listener = listener->next;
|
||||
continue;
|
||||
}
|
||||
res = listener->request_matcher(listener, &resource, pdu);
|
||||
/* check next resource on mismatch */
|
||||
if (res == GCOAP_RESOURCE_NO_PATH) {
|
||||
listener = listener->next;
|
||||
@ -826,8 +841,9 @@ static ssize_t _well_known_core_handler(coap_pkt_t* pdu, uint8_t *buf, size_t le
|
||||
coap_opt_add_format(pdu, COAP_FORMAT_LINK);
|
||||
ssize_t plen = coap_opt_finish(pdu, COAP_OPT_FINISH_PAYLOAD);
|
||||
|
||||
plen += gcoap_get_resource_list(pdu->payload, (size_t)pdu->payload_len,
|
||||
COAP_FORMAT_LINK);
|
||||
plen += gcoap_get_resource_list_tl(pdu->payload, (size_t)pdu->payload_len,
|
||||
COAP_FORMAT_LINK,
|
||||
(gcoap_socket_type_t)pdu->tl_type);
|
||||
return plen;
|
||||
}
|
||||
|
||||
@ -1332,7 +1348,8 @@ uint8_t gcoap_op_state(void)
|
||||
return count;
|
||||
}
|
||||
|
||||
int gcoap_get_resource_list(void *buf, size_t maxlen, uint8_t cf)
|
||||
int gcoap_get_resource_list_tl(void *buf, size_t maxlen, uint8_t cf,
|
||||
gcoap_socket_type_t tl_type)
|
||||
{
|
||||
assert(cf == COAP_FORMAT_LINK);
|
||||
|
||||
@ -1351,6 +1368,15 @@ int gcoap_get_resource_list(void *buf, size_t maxlen, uint8_t cf)
|
||||
if (!listener->link_encoder) {
|
||||
continue;
|
||||
}
|
||||
/* only makes sense to check if non-UDP transports are supported,
|
||||
* so check if module is used first. */
|
||||
if (IS_USED(MODULE_GCOAP_DTLS) &&
|
||||
(tl_type != GCOAP_SOCKET_TYPE_UNDEF) &&
|
||||
(listener->tl_type != GCOAP_SOCKET_TYPE_UNDEF) &&
|
||||
((listener->tl_type & GCOAP_SOCKET_TYPE_UDP) != (tl_type & GCOAP_SOCKET_TYPE_UDP)) &&
|
||||
((listener->tl_type & GCOAP_SOCKET_TYPE_DTLS) != (tl_type & GCOAP_SOCKET_TYPE_DTLS))) {
|
||||
continue;
|
||||
}
|
||||
ctx.link_pos = 0;
|
||||
|
||||
for (; ctx.link_pos < listener->resources_len; ctx.link_pos++) {
|
||||
|
Loading…
Reference in New Issue
Block a user