1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2025-01-17 05:52:44 +01:00

Merge pull request #20454 from mariemC/mariem/coap-coaps-forward-proxy

gcoap:  add coaps forward proxy
This commit is contained in:
Martine Lenders 2024-05-06 08:54:08 +00:00 committed by GitHub
commit a5996e22b8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 211 additions and 28 deletions

View File

@ -70,6 +70,7 @@ PSEUDOMODULES += evtimer_mbox
PSEUDOMODULES += fatfs_vfs_format PSEUDOMODULES += fatfs_vfs_format
PSEUDOMODULES += fmt_% PSEUDOMODULES += fmt_%
PSEUDOMODULES += gcoap_forward_proxy PSEUDOMODULES += gcoap_forward_proxy
PSEUDOMODULES += gcoap_forward_proxy_thread
PSEUDOMODULES += gcoap_fileserver PSEUDOMODULES += gcoap_fileserver
PSEUDOMODULES += gcoap_dtls PSEUDOMODULES += gcoap_dtls
## @addtogroup net_gcoap_dns ## @addtogroup net_gcoap_dns

View File

@ -471,6 +471,10 @@ ifneq (,$(filter gcoap_forward_proxy,$(USEMODULE)))
USEMODULE += uri_parser USEMODULE += uri_parser
endif endif
ifneq (,$(filter gcoap_forward_proxy_thread,$(USEMODULE)))
USEMODULE += gcoap_forward_proxy
endif
ifneq (,$(filter gcoap_dtls,$(USEMODULE))) ifneq (,$(filter gcoap_dtls,$(USEMODULE)))
USEMODULE += gcoap USEMODULE += gcoap
USEMODULE += dsm USEMODULE += dsm

View File

@ -6,3 +6,7 @@ endif
CONFIG_GCOAP_PDU_BUF_SIZE := $(or $(CONFIG_GCOAP_PDU_BUF_SIZE),128) CONFIG_GCOAP_PDU_BUF_SIZE := $(or $(CONFIG_GCOAP_PDU_BUF_SIZE),128)
# the initial DTLS handshake may exceed the block size # 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 ))) 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

View File

@ -25,6 +25,8 @@
#include "net/nanocoap/cache.h" #include "net/nanocoap/cache.h"
#include "ztimer.h" #include "ztimer.h"
#include "forward_proxy_internal.h"
#define ENABLE_DEBUG 0 #define ENABLE_DEBUG 0
#include "debug.h" #include "debug.h"
@ -34,16 +36,7 @@
#define CLIENT_EP_FLAGS_ETAG_LEN_MASK 0x0f #define CLIENT_EP_FLAGS_ETAG_LEN_MASK 0x0f
#define CLIENT_EP_FLAGS_ETAG_LEN_POS 0U #define CLIENT_EP_FLAGS_ETAG_LEN_POS 0U
typedef struct { extern kernel_pid_t forward_proxy_pid;
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 uint16_t gcoap_next_msg_id(void); extern uint16_t gcoap_next_msg_id(void);
extern void gcoap_forward_proxy_post_event(void *arg); 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) void gcoap_forward_proxy_init(void)
{ {
gcoap_register_listener(&forward_proxy_listener); 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) 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_in_use(cep);
_cep_set_req_etag(cep, NULL, 0); _cep_set_req_etag(cep, NULL, 0);
memcpy(&cep->ep, ep, sizeof(*ep)); memcpy(&cep->ep, ep, sizeof(*ep));
DEBUG("Client_ep is allocated %p\n", (void *)cep);
return 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) static void _free_client_ep(client_ep_t *cep)
{ {
ztimer_remove(ZTIMER_MSEC, &cep->empty_ack_timer); 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, 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; 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, static int _gcoap_forward_proxy_via_coap(coap_pkt_t *client_pkt,
client_ep_t *client_ep, client_ep_t *client_ep,
uri_parser_result_t *urip) uri_parser_result_t *urip)
{ {
coap_pkt_t pkt;
sock_udp_ep_t origin_server_ep;
ssize_t len; ssize_t len;
gcoap_request_memo_t *memo = NULL; 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; return -EINVAL;
} }
/* do not forward requests if they already exist, e.g., due to CON /* do not forward requests if they already exist, e.g., due to CON
and retransmissions. In the future, the proxy should set an and retransmissions. In the future, the proxy should set an
empty ACK message to stop the retransmissions of a client */ 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) { if (memo) {
DEBUG("gcoap_forward_proxy: request already exists, ignore!\n"); DEBUG("gcoap_forward_proxy: request already exists, ignore!\n");
_free_client_ep(client_ep); _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); 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); sizeof(coap_hdr_t) + token_len);
pkt.hdr->ver_t_tkl = client_pkt->hdr->ver_t_tkl; client_ep->pdu.hdr->ver_t_tkl = client_pkt->hdr->ver_t_tkl;
pkt.hdr->code = client_pkt->hdr->code; client_ep->pdu.hdr->code = client_pkt->hdr->code;
pkt.hdr->id = client_pkt->hdr->id; client_ep->pdu.hdr->id = client_pkt->hdr->id;
if (token_len) { 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 */ /* 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) { if (len == -EINVAL) {
_free_client_ep(client_ep);
return -EINVAL; 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; return len;
} }
@ -484,10 +502,11 @@ int gcoap_forward_proxy_request_process(coap_pkt_t *pkt,
} }
/* target is using CoAP */ /* 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); int res = _gcoap_forward_proxy_via_coap(pkt, cep, &urip);
if (res < 0) { if (res < 0) {
_free_client_ep(cep);
return -EINVAL; return -EINVAL;
} }
} }

View File

@ -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 <mariem.charrada@ml-pa.com>
* @}
*/
#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");
}
}

View File

@ -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 <mariem.charrada@ml-pa.com>
*/
#ifndef FORWARD_PROXY_INTERNAL_H
#define FORWARD_PROXY_INTERNAL_H
#include <stdint.h>
#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 */
/**
* @}
*/