mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
Merge pull request #16688 from miri64/gcoap/enh/multitransport
gcoap: multi-transport support
This commit is contained in:
commit
c411edef55
@ -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 */
|
||||
|
||||
@ -768,6 +808,7 @@ struct gcoap_request_memo {
|
||||
void *context; /**< ptr to user defined context data */
|
||||
event_timeout_t resp_evt_tmout; /**< Limits wait for response */
|
||||
event_callback_t resp_tmout_cb; /**< Callback for response timeout */
|
||||
gcoap_socket_t socket; /**< Transport type to remote endpoint */
|
||||
};
|
||||
|
||||
/**
|
||||
@ -778,35 +819,9 @@ typedef struct {
|
||||
const coap_resource_t *resource; /**< Entity being observed */
|
||||
uint8_t token[GCOAP_TOKENLEN_MAX]; /**< Client token for notifications */
|
||||
unsigned token_len; /**< Actual length of token attribute */
|
||||
gcoap_socket_t socket; /**< Transport type to observer */
|
||||
} gcoap_observe_memo_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 Initializes the gcoap thread and device
|
||||
*
|
||||
@ -904,6 +919,32 @@ static inline ssize_t gcoap_request(coap_pkt_t *pdu, uint8_t *buf, size_t len,
|
||||
: -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sends a buffer containing a CoAP request to the provided endpoint
|
||||
*
|
||||
* @deprecated Will be an alias for @ref gcoap_req_send after the 2022.01
|
||||
* release. Will be removed after the 2022.04 release.
|
||||
*
|
||||
* @param[in] buf Buffer containing the PDU
|
||||
* @param[in] len Length of the buffer
|
||||
* @param[in] remote Destination for the packet
|
||||
* @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
|
||||
* @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
|
||||
* @return -EINVAL, if @p tl_type is is not supported
|
||||
* @return 0 if cannot send
|
||||
*/
|
||||
ssize_t gcoap_req_send_tl(const uint8_t *buf, size_t len,
|
||||
const sock_udp_ep_t *remote,
|
||||
gcoap_resp_handler_t resp_handler, void *context,
|
||||
gcoap_socket_type_t tl_type);
|
||||
|
||||
/**
|
||||
* @brief Sends a buffer containing a CoAP request to the provided endpoint
|
||||
*
|
||||
@ -913,13 +954,21 @@ 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
|
||||
*
|
||||
* @note The highest supported (by value) gcoap_socket_type_t will be selected
|
||||
* as transport type.
|
||||
*
|
||||
* @return length of the packet
|
||||
* @return -ENOTCONN, if DTLS was used and session establishment failed
|
||||
* @return 0 if cannot send
|
||||
*/
|
||||
ssize_t gcoap_req_send(const uint8_t *buf, size_t len,
|
||||
const sock_udp_ep_t *remote,
|
||||
gcoap_resp_handler_t resp_handler, void *context);
|
||||
static inline ssize_t gcoap_req_send(const uint8_t *buf, size_t len,
|
||||
const sock_udp_ep_t *remote,
|
||||
gcoap_resp_handler_t resp_handler,
|
||||
void *context)
|
||||
{
|
||||
return gcoap_req_send_tl(buf, len, remote, resp_handler, context,
|
||||
GCOAP_SOCKET_TYPE_UNDEF);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Initializes a CoAP response packet on a buffer
|
||||
@ -1002,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.
|
||||
*
|
||||
@ -1016,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;
|
||||
|
||||
|
@ -54,19 +54,20 @@ static void *_event_loop(void *arg);
|
||||
static void _on_sock_udp_evt(sock_udp_t *sock, sock_async_flags_t type, void *arg);
|
||||
static void _process_coap_pdu(gcoap_socket_t *sock, sock_udp_ep_t *remote,
|
||||
uint8_t *buf, size_t len, bool truncated);
|
||||
static void _tl_init_coap_socket(gcoap_socket_t *sock);
|
||||
static int _tl_init_coap_socket(gcoap_socket_t *sock, gcoap_socket_type_t type);
|
||||
static ssize_t _tl_send(gcoap_socket_t *sock, const void *data, size_t len,
|
||||
const sock_udp_ep_t *remote);
|
||||
static ssize_t _tl_authenticate(gcoap_socket_t *sock, const sock_udp_ep_t *remote,
|
||||
uint32_t timeout);
|
||||
static ssize_t _well_known_core_handler(coap_pkt_t* pdu, uint8_t *buf, size_t len, void *ctx);
|
||||
static void _cease_retransmission(gcoap_request_memo_t *memo);
|
||||
static size_t _handle_req(coap_pkt_t *pdu, uint8_t *buf, size_t len,
|
||||
sock_udp_ep_t *remote);
|
||||
static size_t _handle_req(gcoap_socket_t *sock, coap_pkt_t *pdu, uint8_t *buf,
|
||||
size_t len, sock_udp_ep_t *remote);
|
||||
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);
|
||||
@ -383,7 +386,8 @@ static void _process_coap_pdu(gcoap_socket_t *sock, sock_udp_ep_t *remote,
|
||||
pdu_len = gcoap_response(&pdu, _listen_buf, sizeof(_listen_buf),
|
||||
COAP_CODE_REQUEST_ENTITY_TOO_LARGE);
|
||||
} else {
|
||||
pdu_len = _handle_req(&pdu, _listen_buf, sizeof(_listen_buf), remote);
|
||||
pdu_len = _handle_req(sock, &pdu, _listen_buf,
|
||||
sizeof(_listen_buf), remote);
|
||||
}
|
||||
|
||||
if (pdu_len > 0) {
|
||||
@ -485,9 +489,7 @@ static void _on_resp_timeout(void *arg) {
|
||||
return;
|
||||
}
|
||||
|
||||
gcoap_socket_t socket;
|
||||
_tl_init_coap_socket(&socket);
|
||||
ssize_t bytes = _tl_send(&socket, memo->msg.data.pdu_buf,
|
||||
ssize_t bytes = _tl_send(&memo->socket, memo->msg.data.pdu_buf,
|
||||
memo->msg.data.pdu_len, &memo->remote_ep);
|
||||
if (bytes <= 0) {
|
||||
DEBUG("gcoap: sock resend failed: %d\n", (int)bytes);
|
||||
@ -529,8 +531,8 @@ static void _cease_retransmission(gcoap_request_memo_t *memo) {
|
||||
*
|
||||
* return length of response pdu, or < 0 if can't handle
|
||||
*/
|
||||
static size_t _handle_req(coap_pkt_t *pdu, uint8_t *buf, size_t len,
|
||||
sock_udp_ep_t *remote)
|
||||
static size_t _handle_req(gcoap_socket_t *sock, coap_pkt_t *pdu, uint8_t *buf,
|
||||
size_t len, sock_udp_ep_t *remote)
|
||||
{
|
||||
const coap_resource_t *resource = NULL;
|
||||
gcoap_listener_t *listener = NULL;
|
||||
@ -538,7 +540,7 @@ static size_t _handle_req(coap_pkt_t *pdu, uint8_t *buf, size_t len,
|
||||
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:
|
||||
@ -567,7 +569,8 @@ static size_t _handle_req(coap_pkt_t *pdu, uint8_t *buf, size_t len,
|
||||
}
|
||||
/* otherwise OK to re-register resource with the same token */
|
||||
}
|
||||
else if (sock_udp_ep_equal(remote, resource_memo->observer)) {
|
||||
else if ((sock->type == resource_memo->socket.type) &&
|
||||
sock_udp_ep_equal(remote, resource_memo->observer)) {
|
||||
/* accept new token for resource */
|
||||
memo = resource_memo;
|
||||
}
|
||||
@ -601,6 +604,7 @@ static size_t _handle_req(coap_pkt_t *pdu, uint8_t *buf, size_t len,
|
||||
/* resource may be assigned here if it is not already registered */
|
||||
memo->resource = resource;
|
||||
memo->token_len = coap_get_token_len(pdu);
|
||||
memo->socket = *sock;
|
||||
if (memo->token_len) {
|
||||
memcpy(&memo->token[0], pdu->token, memo->token_len);
|
||||
}
|
||||
@ -630,6 +634,7 @@ static size_t _handle_req(coap_pkt_t *pdu, uint8_t *buf, size_t len,
|
||||
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,
|
||||
@ -688,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
|
||||
@ -696,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)
|
||||
{
|
||||
@ -707,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;
|
||||
@ -825,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;
|
||||
}
|
||||
|
||||
@ -924,54 +941,72 @@ static void _find_obs_memo_resource(gcoap_observe_memo_t **memo,
|
||||
* Transport layer functions
|
||||
*/
|
||||
|
||||
static void _tl_init_coap_socket(gcoap_socket_t *sock)
|
||||
static int _tl_init_coap_socket(gcoap_socket_t *sock, gcoap_socket_type_t type)
|
||||
{
|
||||
#if IS_USED(MODULE_GCOAP_DTLS)
|
||||
sock->type = GCOAP_SOCKET_TYPE_DTLS;
|
||||
sock->socket.dtls = &_sock_dtls;
|
||||
#else
|
||||
sock->type = GCOAP_SOCKET_TYPE_UDP;
|
||||
sock->socket.udp = &_sock_udp;
|
||||
switch (type) {
|
||||
#if !IS_USED(MODULE_GCOAP_DTLS)
|
||||
case GCOAP_SOCKET_TYPE_UNDEF:
|
||||
#endif
|
||||
case GCOAP_SOCKET_TYPE_UDP:
|
||||
sock->type = GCOAP_SOCKET_TYPE_UDP;
|
||||
sock->socket.udp = &_sock_udp;
|
||||
break;
|
||||
#if IS_USED(MODULE_GCOAP_DTLS)
|
||||
case GCOAP_SOCKET_TYPE_UNDEF:
|
||||
case GCOAP_SOCKET_TYPE_DTLS:
|
||||
sock->type = GCOAP_SOCKET_TYPE_DTLS;
|
||||
sock->socket.dtls = &_sock_dtls;
|
||||
break;
|
||||
#else
|
||||
default:
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t _tl_send(gcoap_socket_t *sock, const void *data, size_t len,
|
||||
const sock_udp_ep_t *remote)
|
||||
const sock_udp_ep_t *remote)
|
||||
{
|
||||
ssize_t res = -1;
|
||||
if (sock->type == GCOAP_SOCKET_TYPE_DTLS) {
|
||||
switch (sock->type) {
|
||||
case GCOAP_SOCKET_TYPE_UDP:
|
||||
res = sock_udp_send(sock->socket.udp, data, len, remote);
|
||||
break;
|
||||
#if IS_USED(MODULE_GCOAP_DTLS)
|
||||
/* prepare session */
|
||||
sock_dtls_session_set_udp_ep(&sock->ctx_dtls_session, remote);
|
||||
dsm_state_t session_state = dsm_store(sock->socket.dtls, &sock->ctx_dtls_session,
|
||||
SESSION_STATE_HANDSHAKE, true);
|
||||
if (session_state == NO_SPACE) {
|
||||
return -1;
|
||||
}
|
||||
case GCOAP_SOCKET_TYPE_DTLS:
|
||||
/* prepare session */
|
||||
sock_dtls_session_set_udp_ep(&sock->ctx_dtls_session, remote);
|
||||
dsm_state_t session_state = dsm_store(sock->socket.dtls,
|
||||
&sock->ctx_dtls_session,
|
||||
SESSION_STATE_HANDSHAKE,
|
||||
true);
|
||||
if (session_state == NO_SPACE) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* send application data */
|
||||
res = sock_dtls_send(sock->socket.dtls, &sock->ctx_dtls_session, data, len,
|
||||
SOCK_NO_TIMEOUT);
|
||||
switch (res) {
|
||||
case -EHOSTUNREACH:
|
||||
case -ENOTCONN:
|
||||
case 0:
|
||||
DEBUG("gcoap: DTLS sock not connected or remote unreachable. "
|
||||
"Destroying session.\n");
|
||||
dsm_remove(sock->socket.dtls, &sock->ctx_dtls_session);
|
||||
sock_dtls_session_destroy(sock->socket.dtls, &sock->ctx_dtls_session);
|
||||
/* send application data */
|
||||
res = sock_dtls_send(sock->socket.dtls, &sock->ctx_dtls_session, data, len,
|
||||
SOCK_NO_TIMEOUT);
|
||||
switch (res) {
|
||||
case -EHOSTUNREACH:
|
||||
case -ENOTCONN:
|
||||
case 0:
|
||||
DEBUG("gcoap: DTLS sock not connected or remote unreachable. "
|
||||
"Destroying session.\n");
|
||||
dsm_remove(sock->socket.dtls, &sock->ctx_dtls_session);
|
||||
sock_dtls_session_destroy(sock->socket.dtls, &sock->ctx_dtls_session);
|
||||
break;
|
||||
default:
|
||||
/* Temporary error. Keeping the DTLS session */
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
/* Temporary error. Keeping the DTLS session */
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
} else if (sock->type == GCOAP_SOCKET_TYPE_UDP) {
|
||||
res = sock_udp_send(sock->socket.udp, data, len, remote);
|
||||
} else {
|
||||
DEBUG("gcoap: undefined socket type\n");
|
||||
default:
|
||||
DEBUG("gcoap: undefined socket type\n");
|
||||
break;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
@ -986,6 +1021,9 @@ static ssize_t _tl_authenticate(gcoap_socket_t *sock, const sock_udp_ep_t *remot
|
||||
#else
|
||||
int res;
|
||||
|
||||
if (sock->type != GCOAP_SOCKET_TYPE_DTLS) {
|
||||
return 0;
|
||||
}
|
||||
/* prepare session */
|
||||
sock_dtls_session_set_udp_ep(&sock->ctx_dtls_session, remote);
|
||||
dsm_state_t session_state = dsm_store(sock->socket.dtls, &sock->ctx_dtls_session,
|
||||
@ -1111,16 +1149,23 @@ int gcoap_req_init_path_buffer(coap_pkt_t *pdu, uint8_t *buf, size_t len,
|
||||
return (res > 0) ? 0 : res;
|
||||
}
|
||||
|
||||
ssize_t gcoap_req_send(const uint8_t *buf, size_t len,
|
||||
const sock_udp_ep_t *remote,
|
||||
gcoap_resp_handler_t resp_handler, void *context)
|
||||
ssize_t gcoap_req_send_tl(const uint8_t *buf, size_t len,
|
||||
const sock_udp_ep_t *remote,
|
||||
gcoap_resp_handler_t resp_handler, void *context,
|
||||
gcoap_socket_type_t tl_type)
|
||||
{
|
||||
gcoap_socket_t socket = { 0 };
|
||||
gcoap_request_memo_t *memo = NULL;
|
||||
unsigned msg_type = (*buf & 0x30) >> 4;
|
||||
uint32_t timeout = 0;
|
||||
ssize_t res = 0;
|
||||
|
||||
assert(remote != NULL);
|
||||
|
||||
res = _tl_init_coap_socket(&socket, tl_type);
|
||||
if (res < 0) {
|
||||
return -EINVAL;
|
||||
}
|
||||
/* Only allocate memory if necessary (i.e. if user is interested in the
|
||||
* response or request is confirmable) */
|
||||
if ((resp_handler != NULL) || (msg_type == COAP_TYPE_CON)) {
|
||||
@ -1142,6 +1187,7 @@ ssize_t gcoap_req_send(const uint8_t *buf, size_t len,
|
||||
memo->resp_handler = resp_handler;
|
||||
memo->context = context;
|
||||
memcpy(&memo->remote_ep, remote, sizeof(sock_udp_ep_t));
|
||||
memo->socket = socket;
|
||||
|
||||
switch (msg_type) {
|
||||
case COAP_TYPE_CON:
|
||||
@ -1186,10 +1232,7 @@ ssize_t gcoap_req_send(const uint8_t *buf, size_t len,
|
||||
}
|
||||
}
|
||||
|
||||
ssize_t res = 0;
|
||||
gcoap_socket_t socket = { 0 };
|
||||
|
||||
_tl_init_coap_socket(&socket);
|
||||
_tl_init_coap_socket(&socket, tl_type);
|
||||
if (IS_USED(MODULE_GCOAP_DTLS) && socket.type == GCOAP_SOCKET_TYPE_DTLS) {
|
||||
res = _tl_authenticate(&socket, remote, CONFIG_GCOAP_DTLS_HANDSHAKE_TIMEOUT_MSEC);
|
||||
}
|
||||
@ -1283,12 +1326,10 @@ size_t gcoap_obs_send(const uint8_t *buf, size_t len,
|
||||
const coap_resource_t *resource)
|
||||
{
|
||||
gcoap_observe_memo_t *memo = NULL;
|
||||
gcoap_socket_t socket;
|
||||
_tl_init_coap_socket(&socket);
|
||||
_find_obs_memo_resource(&memo, resource);
|
||||
|
||||
if (memo) {
|
||||
ssize_t bytes = _tl_send(&socket, buf, len, memo->observer);
|
||||
ssize_t bytes = _tl_send(&memo->socket, buf, len, memo->observer);
|
||||
return (size_t)((bytes > 0) ? bytes : 0);
|
||||
}
|
||||
else {
|
||||
@ -1307,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);
|
||||
|
||||
@ -1326,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