diff --git a/makefiles/pseudomodules.inc.mk b/makefiles/pseudomodules.inc.mk index 6b66fcca95..77d7ca1e90 100644 --- a/makefiles/pseudomodules.inc.mk +++ b/makefiles/pseudomodules.inc.mk @@ -70,6 +70,7 @@ PSEUDOMODULES += evtimer_mbox PSEUDOMODULES += fatfs_vfs_format PSEUDOMODULES += fmt_% PSEUDOMODULES += gcoap_forward_proxy +PSEUDOMODULES += gcoap_forward_proxy_thread PSEUDOMODULES += gcoap_fileserver PSEUDOMODULES += gcoap_dtls ## @addtogroup net_gcoap_dns diff --git a/sys/Makefile.dep b/sys/Makefile.dep index 326472e357..76f437d926 100644 --- a/sys/Makefile.dep +++ b/sys/Makefile.dep @@ -471,6 +471,10 @@ ifneq (,$(filter gcoap_forward_proxy,$(USEMODULE))) USEMODULE += uri_parser endif +ifneq (,$(filter gcoap_forward_proxy_thread,$(USEMODULE))) + USEMODULE += gcoap_forward_proxy +endif + ifneq (,$(filter gcoap_dtls,$(USEMODULE))) USEMODULE += gcoap USEMODULE += dsm diff --git a/sys/net/application_layer/gcoap/Makefile.include b/sys/net/application_layer/gcoap/Makefile.include index 5cde727e7f..7540d2812b 100644 --- a/sys/net/application_layer/gcoap/Makefile.include +++ b/sys/net/application_layer/gcoap/Makefile.include @@ -6,3 +6,7 @@ endif CONFIG_GCOAP_PDU_BUF_SIZE := $(or $(CONFIG_GCOAP_PDU_BUF_SIZE),128) # the initial DTLS handshake may exceed the block size DTLS_MAX_BUF ?= $(shell echo $$(((${CONFIG_GCOAP_PDU_BUF_SIZE} + 36) > 200 ? (${CONFIG_GCOAP_PDU_BUF_SIZE} + 36) : 200 ))) + +ifneq (,$(filter gcoap_forward_proxy,$(USEMODULE))) + INCLUDES += -I$(RIOTBASE)/sys/net/application_layer/gcoap/include +endif diff --git a/sys/net/application_layer/gcoap/forward_proxy.c b/sys/net/application_layer/gcoap/forward_proxy.c index a426b80be3..4e863f8beb 100644 --- a/sys/net/application_layer/gcoap/forward_proxy.c +++ b/sys/net/application_layer/gcoap/forward_proxy.c @@ -25,6 +25,8 @@ #include "net/nanocoap/cache.h" #include "ztimer.h" +#include "forward_proxy_internal.h" + #define ENABLE_DEBUG 0 #include "debug.h" @@ -34,16 +36,7 @@ #define CLIENT_EP_FLAGS_ETAG_LEN_MASK 0x0f #define CLIENT_EP_FLAGS_ETAG_LEN_POS 0U -typedef struct { - sock_udp_ep_t ep; - uint16_t mid; - uint8_t flags; -#if IS_USED(MODULE_NANOCOAP_CACHE) - uint8_t req_etag[COAP_ETAG_LENGTH_MAX]; -#endif - ztimer_t empty_ack_timer; - event_t event; -} client_ep_t; +extern kernel_pid_t forward_proxy_pid; extern uint16_t gcoap_next_msg_id(void); extern void gcoap_forward_proxy_post_event(void *arg); @@ -87,6 +80,9 @@ gcoap_listener_t forward_proxy_listener = { void gcoap_forward_proxy_init(void) { gcoap_register_listener(&forward_proxy_listener); + if (IS_ACTIVE(MODULE_GCOAP_FORWARD_PROXY_THREAD)) { + gcoap_forward_proxy_thread_init(); + } } static client_ep_t *_allocate_client_ep(const sock_udp_ep_t *ep) @@ -99,6 +95,7 @@ static client_ep_t *_allocate_client_ep(const sock_udp_ep_t *ep) _cep_set_in_use(cep); _cep_set_req_etag(cep, NULL, 0); memcpy(&cep->ep, ep, sizeof(*ep)); + DEBUG("Client_ep is allocated %p\n", (void *)cep); return cep; } } @@ -108,7 +105,9 @@ static client_ep_t *_allocate_client_ep(const sock_udp_ep_t *ep) static void _free_client_ep(client_ep_t *cep) { ztimer_remove(ZTIMER_MSEC, &cep->empty_ack_timer); - memset(cep, 0, sizeof(*cep)); + /* timer removed but event could be queued */ + cep->flags = 0; + DEBUG("Client_ep is freed %p\n", (void *)cep); } static int _request_matcher_forward_proxy(gcoap_listener_t *listener, @@ -390,24 +389,34 @@ static int _gcoap_forward_proxy_copy_options(coap_pkt_t *pkt, return len; } +int gcoap_forward_proxy_req_send(client_ep_t *cep) +{ + int len; + if ((len = gcoap_req_send((uint8_t *)cep->pdu.hdr, coap_get_total_len(&cep->pdu), + &cep->server_ep, _forward_resp_handler, cep, + GCOAP_SOCKET_TYPE_UNDEF)) <= 0) { + DEBUG("gcoap_forward_proxy_req_send(): gcoap_req_send failed %d\n", len); + _free_client_ep(cep); + } + return len; +} + static int _gcoap_forward_proxy_via_coap(coap_pkt_t *client_pkt, client_ep_t *client_ep, uri_parser_result_t *urip) { - coap_pkt_t pkt; - sock_udp_ep_t origin_server_ep; - ssize_t len; gcoap_request_memo_t *memo = NULL; - if (!_parse_endpoint(&origin_server_ep, urip)) { + if (!_parse_endpoint(&client_ep->server_ep, urip)) { + _free_client_ep(client_ep); return -EINVAL; } /* do not forward requests if they already exist, e.g., due to CON and retransmissions. In the future, the proxy should set an empty ACK message to stop the retransmissions of a client */ - gcoap_forward_proxy_find_req_memo(&memo, client_pkt, &origin_server_ep); + gcoap_forward_proxy_find_req_memo(&memo, client_pkt, &client_ep->server_ep); if (memo) { DEBUG("gcoap_forward_proxy: request already exists, ignore!\n"); _free_client_ep(client_ep); @@ -424,28 +433,37 @@ static int _gcoap_forward_proxy_via_coap(coap_pkt_t *client_pkt, unsigned token_len = coap_get_token_len(client_pkt); - coap_pkt_init(&pkt, proxy_req_buf, CONFIG_GCOAP_PDU_BUF_SIZE, + coap_pkt_init(&client_ep->pdu, proxy_req_buf, CONFIG_GCOAP_PDU_BUF_SIZE, sizeof(coap_hdr_t) + token_len); - pkt.hdr->ver_t_tkl = client_pkt->hdr->ver_t_tkl; - pkt.hdr->code = client_pkt->hdr->code; - pkt.hdr->id = client_pkt->hdr->id; + client_ep->pdu.hdr->ver_t_tkl = client_pkt->hdr->ver_t_tkl; + client_ep->pdu.hdr->code = client_pkt->hdr->code; + client_ep->pdu.hdr->id = client_pkt->hdr->id; if (token_len) { - memcpy(coap_get_token(&pkt), coap_get_token(client_pkt), token_len); + memcpy(coap_get_token(&client_ep->pdu), coap_get_token(client_pkt), token_len); } /* copy all options from client_pkt to pkt */ - len = _gcoap_forward_proxy_copy_options(&pkt, client_pkt, client_ep, urip); + len = _gcoap_forward_proxy_copy_options(&client_ep->pdu, client_pkt, client_ep, urip); if (len == -EINVAL) { + _free_client_ep(client_ep); return -EINVAL; } + if (IS_USED(MODULE_GCOAP_FORWARD_PROXY_THREAD)) { + /* WORKAROUND: DTLS communication is blocking the gcoap thread, + * therefore the communication should be handled in the proxy thread */ + + msg_t msg = { .type = GCOAP_FORWARD_PROXY_MSG_SEND, + .content.ptr = client_ep + }; + msg_send(&msg, forward_proxy_pid); + } + else { + len = gcoap_forward_proxy_req_send(client_ep); + } - len = gcoap_req_send((uint8_t *)pkt.hdr, len, - &origin_server_ep, - _forward_resp_handler, (void *)client_ep, - GCOAP_SOCKET_TYPE_UNDEF); return len; } @@ -484,10 +502,11 @@ int gcoap_forward_proxy_request_process(coap_pkt_t *pkt, } /* target is using CoAP */ - if (!strncmp("coap", urip.scheme, urip.scheme_len)) { + if (!strncmp("coap", urip.scheme, urip.scheme_len) || + !strncmp("coaps", urip.scheme, urip.scheme_len)) { + /* client context ownership is passed to gcoap_forward_proxy_req_send() */ int res = _gcoap_forward_proxy_via_coap(pkt, cep, &urip); if (res < 0) { - _free_client_ep(cep); return -EINVAL; } } diff --git a/sys/net/application_layer/gcoap/forward_proxy_thread.c b/sys/net/application_layer/gcoap/forward_proxy_thread.c new file mode 100644 index 0000000000..b3e725c8fc --- /dev/null +++ b/sys/net/application_layer/gcoap/forward_proxy_thread.c @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2024 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. + */ + +/** + * @{ + * + * @file + * @brief Forward Proxy Thread + * + * @author Mariem Charrada + * @} + */ + +#include "msg.h" +#include "net/gcoap.h" +#include "net/gcoap/forward_proxy.h" +#include "thread.h" + +#include "forward_proxy_internal.h" + +#define ENABLE_DEBUG 0 +#include "debug.h" + +static char _forward_proxy_thread[GCOAP_PROXY_STACK_SIZE]; +kernel_pid_t forward_proxy_pid = KERNEL_PID_UNDEF; + +static void *_forward_proxy_thread_start(void *arg) +{ + (void)arg; + + msg_t _forward_proxy_msg_queue[CONFIG_GCOAP_REQ_WAITING_MAX]; + msg_init_queue(_forward_proxy_msg_queue, ARRAY_SIZE(_forward_proxy_msg_queue)); + + msg_t msg; + + while (1) { + msg_receive(&msg); + client_ep_t *cep = (client_ep_t *)msg.content.ptr; + switch (msg.type) { + case GCOAP_FORWARD_PROXY_MSG_SEND: { + gcoap_forward_proxy_req_send(cep); + break; + } + default: + DEBUG_PUTS("_forward_proxy_thread_start: unknown message type\n"); + break; + } + } + return NULL; +} + +void gcoap_forward_proxy_thread_init(void) +{ + forward_proxy_pid = thread_create(_forward_proxy_thread, sizeof(_forward_proxy_thread), + THREAD_PRIORITY_MAIN - 1, THREAD_CREATE_STACKTEST, + _forward_proxy_thread_start, NULL, "gcoap proxy"); + if (forward_proxy_pid <= KERNEL_PID_UNDEF) { + DEBUG_PUTS("gcoap_forward_proxy_thread_init(): thread_create failed\n"); + } +} diff --git a/sys/net/application_layer/gcoap/include/forward_proxy_internal.h b/sys/net/application_layer/gcoap/include/forward_proxy_internal.h new file mode 100644 index 0000000000..dbeb93fbf5 --- /dev/null +++ b/sys/net/application_layer/gcoap/include/forward_proxy_internal.h @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2024 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_gcoap_forward_proxy_thread GCoAP Forward Proxy Thread + * @ingroup net_gcoap + * @brief Forward proxy thread implementation for GCoAP + * + * @{ + * + * @file + * @brief Definitions for the GCoAP forward proxy internal communication + * + * @author Mariem Charrada + */ + +#ifndef FORWARD_PROXY_INTERNAL_H +#define FORWARD_PROXY_INTERNAL_H + +#include +#include "net/coap.h" +#include "net/gcoap.h" +#include "net/sock/udp.h" +#include "ztimer.h" +#include "event.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief client ep structure + */ +typedef struct { + coap_pkt_t pdu; /**< forward CoAP PDU */ + sock_udp_ep_t server_ep; /**< forward Server endpoint */ + sock_udp_ep_t ep; /**< client endpoint */ + uint16_t mid; /**< message ID */ + uint8_t flags; /**< client flags */ +#if IS_USED(MODULE_NANOCOAP_CACHE) + uint8_t req_etag[COAP_ETAG_LENGTH_MAX]; /**< request ETag */ +#endif + ztimer_t empty_ack_timer; /**< empty ACK timer */ + event_t event; /**< client event */ +} client_ep_t; + +/** + * @brief Stack size for the forward proxy thread + * + */ +#ifndef GCOAP_PROXY_STACK_SIZE +#define GCOAP_PROXY_STACK_SIZE (THREAD_STACKSIZE_DEFAULT + DEBUG_EXTRA_STACKSIZE \ + + sizeof(coap_pkt_t) + GCOAP_DTLS_EXTRA_STACKSIZE) +#endif + +/** + * @brief Definition of forward proxy thread msgs. + */ +enum { + GCOAP_FORWARD_PROXY_MSG_SEND, +}; + +/** + * @brief Initialize the forward proxy thread + */ +void gcoap_forward_proxy_thread_init(void); + +/** + * @brief Forward the CoAP request to the server + * The client endpoint is passed as an argument + * and freed if the send failed. + * + * @param[in] cep client endpoint + * @return @ref gcoap_req_send + */ +int gcoap_forward_proxy_req_send(client_ep_t *cep); + +#ifdef __cplusplus +} +#endif + +#endif /* FORWARD_PROXY_INTERNAL_H */ +/** + * @} + */