diff --git a/examples/nanocoap_reverse_proxy/Makefile b/examples/nanocoap_reverse_proxy/Makefile new file mode 100644 index 000000000000..60b100a116af --- /dev/null +++ b/examples/nanocoap_reverse_proxy/Makefile @@ -0,0 +1,61 @@ +# name of your application +APPLICATION = nanocoap_reverse_proxy + +# If no BOARD is found in the environment, use this default: +BOARD ?= native + +# This has to be the absolute path to the RIOT base directory: +RIOTBASE ?= $(CURDIR)/../.. + +NETWORK_STACK ?= gnrc + +# Include packages that pull up and auto-init the link layer. +# NOTE: 6LoWPAN will be included if IEEE802.15.4 devices are present +USEMODULE += netdev_default +USEMODULE += sock_udp +USEMODULE += ipv6_addr + +ifeq ($(NETWORK_STACK),gnrc) + USEMODULE += auto_init_gnrc_netif + # Specify the mandatory networking modules for IPv6 + USEMODULE += gnrc_ipv6_default + # Additional networking modules that can be dropped if not needed + USEMODULE += gnrc_icmpv6_echo +endif +ifeq ($(NETWORK_STACK),lwip) + USEMODULE += auto_init_lwip_netif + USEMODULE += lwip_ipv6 lwip_ipv6_autoconfig +endif + +# Comment this out to enable code in RIOT that does safety checking +# which is not needed in a production environment but helps in the +# development process: +#DEVELHELP = 1 + +# Enable fileserver and TCP for boards with plenty of memory +HIGH_MEMORY_BOARDS := native native64 same54-xpro mcb2388 + +USEMODULE += event_thread +USEMODULE += nanocoap_proxy +USEMODULE += nanocoap_server_ws +USEMODULE += nanocoap_ws_udp_yolo +USEMODULE += ztimer_usec + +# async TCP is not supported on GNRC yet +ifeq ($(NETWORK_STACK),lwip) + USEMODULE += nanocoap_server_tcp +endif + +# if nanocaop_server_tcp is used: This app makes use of event_thread +# to run the TCP server +ifneq (,$(filter nanocoap_server_tcp,$(USEMODULE))) + USEMODULE += event_thread +endif + +# Change this to 0 show compiler invocation lines by default: +QUIET ?= 1 + +include $(RIOTBASE)/Makefile.include + +# Set a custom channel if needed +include $(RIOTMAKE)/default-radio-settings.inc.mk diff --git a/examples/nanocoap_reverse_proxy/Makefile.ci b/examples/nanocoap_reverse_proxy/Makefile.ci new file mode 100644 index 000000000000..d8e75b093a38 --- /dev/null +++ b/examples/nanocoap_reverse_proxy/Makefile.ci @@ -0,0 +1,35 @@ +BOARD_INSUFFICIENT_MEMORY := \ + arduino-duemilanove \ + arduino-leonardo \ + arduino-mega2560 \ + arduino-nano \ + arduino-uno \ + atmega328p \ + atmega328p-xplained-mini \ + atmega8 \ + bluepill-stm32f030c8 \ + i-nucleo-lrwan1 \ + msb-430 \ + msb-430h \ + nucleo-c031c6 \ + nucleo-f030r8 \ + nucleo-f031k6 \ + nucleo-f042k6 \ + nucleo-f303k8 \ + nucleo-f334r8 \ + nucleo-l011k4 \ + nucleo-l031k6 \ + nucleo-l053r8 \ + olimex-msp430-h1611 \ + olimex-msp430-h2618 \ + samd10-xmini \ + slstk3400a \ + stk3200 \ + stm32f030f4-demo \ + stm32f0discovery \ + stm32g0316-disco \ + stm32l0538-disco \ + telosb \ + weact-g030f6 \ + z1 \ + # diff --git a/examples/nanocoap_reverse_proxy/main.c b/examples/nanocoap_reverse_proxy/main.c new file mode 100644 index 000000000000..8752503bd2f4 --- /dev/null +++ b/examples/nanocoap_reverse_proxy/main.c @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2016 Kaspar Schleiser + * + * 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 examples + * @{ + * + * @file + * @brief CoAP example server application (using nanocoap) + * + * @author Kaspar Schleiser + * @} + */ + +#include + +#include "net/nanocoap_sock.h" +#include "time_units.h" +#include "ztimer.h" + +#if MODULE_NANOCOAP_SERVER_TCP +# include "event/thread.h" +#endif + +#define COAP_INBUF_SIZE (256U) + +#define MAIN_QUEUE_SIZE (8) +static msg_t _main_msg_queue[MAIN_QUEUE_SIZE]; + +#if MODULE_NANOCOAP_SERVER_TCP +static nanocoap_tcp_server_ctx_t tcp_ctx; +#endif + +#if MODULE_NANOCOAP_SERVER_WS && MODULE_NANOCOAP_WS_UDP_YOLO +static coap_ws_over_udp_yolo_init_arg_t _ws_ctx; +#endif + +int main(void) +{ + puts("RIOT nanocoap example application"); + + /* nanocoap_server uses gnrc sock which uses gnrc which needs a msg queue */ + msg_init_queue(_main_msg_queue, MAIN_QUEUE_SIZE); + + puts("Waiting for address autoconfiguration..."); + ztimer_sleep(ZTIMER_USEC, 3 * US_PER_SEC); + + /* print network addresses */ + printf("{\"IPv6 addresses\": [\""); + netifs_print_ipv6("\", \""); + puts("\"]}"); + +#if MODULE_NANOCOAP_SERVER_TCP + nanocoap_server_tcp(&tcp_ctx, EVENT_PRIO_MEDIUM, NULL); + printf("CoAP+TCP on PORT %u\n", (unsigned)tcp_ctx.local.port); +#endif + +#if MODULE_NANOCOAP_SERVER_WS && MODULE_NANOCOAP_WS_UDP_YOLO + sock_udp_ep_t local_ws = { .port = 1337, .family = AF_INET6 }; + nanocoap_server_ws(&coap_ws_over_udp_yolo, &_ws_ctx, &local_ws, sizeof(local_ws)); + printf("CoAP+YOLO on PORT %u\n", (unsigned)local_ws.port); +#endif + +#if MODULE_NANOCOAP_UDP + /* initialize nanocoap server instance */ + uint8_t buf[COAP_INBUF_SIZE]; + sock_udp_ep_t local = { .port=COAP_PORT, .family=AF_INET6 }; + printf("CoAP (UDP) on PORT %u\n", (unsigned)local.port); + nanocoap_server_udp(&local, buf, sizeof(buf)); +#endif + + /* should be never reached */ + return 0; +} diff --git a/examples/nanocoap_reverse_proxy/reverse_proxy.c b/examples/nanocoap_reverse_proxy/reverse_proxy.c new file mode 100644 index 000000000000..69b2f5cce9a1 --- /dev/null +++ b/examples/nanocoap_reverse_proxy/reverse_proxy.c @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2025 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. + */ + +#include "event/thread.h" +#include "net/nanocoap.h" +#include "net/nanocoap_proxy.h" + +/* set up reverse proxies per supported transport */ +#if MODULE_NANOCOAP_WS_UDP_YOLO +static nanocoap_rproxy_ctx_t _yolo_proxy = { + .evq = EVENT_PRIO_MEDIUM, + .scheme = "coap+yolo://" +}; + +NANOCOAP_RESOURCE(yolo_proxy) { + .path = "/yolo", + .methods = COAP_GET | COAP_PUT | COAP_POST | COAP_DELETE | COAP_MATCH_SUBTREE, + .handler= nanocoap_rproxy_handler, + .context = &_yolo_proxy, +}; +#endif + +#if MODULE_NANOCOAP_UDP +static nanocoap_rproxy_ctx_t _udp_proxy = { + .evq = EVENT_PRIO_MEDIUM, + .scheme = "coap://" +}; + +NANOCOAP_RESOURCE(udp_proxy) { + .path = "/udp", + .methods = COAP_GET | COAP_PUT | COAP_POST | COAP_DELETE | COAP_MATCH_SUBTREE, + .handler= nanocoap_rproxy_handler, + .context = &_udp_proxy, +}; +#endif + +#if MODULE_NANOCOAP_TCP +static nanocoap_rproxy_ctx_t _tcp_proxy = { + .evq = EVENT_PRIO_MEDIUM, + .scheme = "coap://" +}; + +NANOCOAP_RESOURCE(tcp_proxy) { + .path = "/tcp", + .methods = COAP_GET | COAP_PUT | COAP_POST | COAP_DELETE | COAP_MATCH_SUBTREE, + .handler= _proxy_resource_handler, + .context = &_tcp_proxy, +}; +#endif diff --git a/sys/net/application_layer/nanocoap/proxy.c b/sys/net/application_layer/nanocoap/proxy.c index 530e6348f0eb..b6b334a34c30 100644 --- a/sys/net/application_layer/nanocoap/proxy.c +++ b/sys/net/application_layer/nanocoap/proxy.c @@ -76,11 +76,11 @@ static void _forward_request_handler(event_t *ev) _disconnect(conn); } -static bool _is_duplicate(nanocoap_rproxy_ctx_t *ctx, coap_pkt_t *pkt, const coap_request_ctx_t *req) +static bool _is_duplicate(nanocoap_rproxy_ctx_t *ctx, const coap_request_ctx_t *req) { for (unsigned i = 0; i < CONFIG_NANOCOAP_RPROXY_PARALLEL_FORWARDS; i++) { if (bf_isset(ctx->forwards_used, i)) { - if (nanocoap_is_duplicate_in_separate_ctx(&ctx->forwards[i].response_ctx, pkt, req)) { + if (nanocoap_server_is_remote_in_response_ctx(&ctx->forwards[i].response_ctx, req)) { return true; } } @@ -145,7 +145,7 @@ ssize_t nanocoap_rproxy_handler(coap_pkt_t *pkt, uint8_t *buf, size_t len, { nanocoap_rproxy_ctx_t *proxy = coap_request_ctx_get_context(ctx); - if (_is_duplicate(proxy, pkt, ctx)) { + if (_is_duplicate(proxy, ctx)) { DEBUG_PUTS("[reverse proxy] Got duplicate --> empty ACK (if needed)"); return coap_reply_empty_ack(pkt, buf, len); }