Skip to content

Commit

Permalink
sys/net/nanocoap: Implement CoAP over WebSocket
Browse files Browse the repository at this point in the history
  • Loading branch information
maribu committed Jan 7, 2025
1 parent 9af5ae2 commit 08ae545
Show file tree
Hide file tree
Showing 9 changed files with 1,448 additions and 90 deletions.
2 changes: 2 additions & 0 deletions examples/nanocoap_server/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,8 @@ ifneq (,$(filter $(BOARD),$(HIGH_MEMORY_BOARDS)))
USEMODULE += vfs_auto_format
endif

USEMODULE += nanocoap_server_ws

# async TCP is not supported on GNRC yet
ifeq ($(NETWORK_STACK),lwip)
USEMODULE += nanocoap_server_tcp
Expand Down
11 changes: 11 additions & 0 deletions sys/Makefile.dep
Original file line number Diff line number Diff line change
Expand Up @@ -541,11 +541,22 @@ ifneq (,$(filter nanocoap_server_tcp,$(USEMODULE)))
USEMODULE += sock_async_event
endif

ifneq (,$(filter nanocoap_server_ws,$(USEMODULE)))
USEMODULE += nanocoap_server
USEMODULE += nanocoap_ws
USEMODULE += event
endif

ifneq (,$(filter nanocoap_server,$(USEMODULE)))
USEMODULE += nanocoap_resources
USEMODULE += nanocoap_sock
endif

ifneq (,$(filter nanocoap_ws_udp_yolo,$(USEMODULE)))
USEMODULE += sock_udp
USEMODULE += sock_async
endif

ifneq (,$(filter nanocoap_sock,$(USEMODULE)))
ifneq (,$(filter nanocoap_udp,$(USEMODULE)))
USEMODULE += sock_udp
Expand Down
109 changes: 95 additions & 14 deletions sys/include/net/nanocoap.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@
*
* nanocoap includes the core structs to store message information. It also
* provides helper functions for use before sending and after receiving a
* message, such as coap_parse_udp() / coap_parse_tcp() to read an incoming
* message.
* message, such as coap_parse_udp() / coap_parse_tcp() / coap_parse_ws() to
* read an incoming message.
*
* ## Application APIs
*
Expand Down Expand Up @@ -93,6 +93,7 @@
#include "macros/utils.h"
#include "modules.h"
#include "net/coap.h"
#include "net/nanocoap_ws.h"
#else
#include "coap.h"
#include <arpa/inet.h>
Expand Down Expand Up @@ -206,13 +207,18 @@ extern "C" {
# define MODULE_NANOCOAP_UDP 0
#endif

#ifndef MODULE_NANOCOAP_DTLS
# define MODULE_NANOCOAP_DTLS 0
#endif

#ifndef MODULE_NANOCOAP_TCP
# define MODULE_NANOCOAP_TCP 0
# define NANOCOAP_EXPOSE_DEPRECATED_API 0
#endif

#ifndef MODULE_NANOCOAP_DTLS
# define MODULE_NANOCOAP_DTLS 0
#ifndef MODULE_NANOCOAP_WS
# define MODULE_NANOCOAP_WS 0
# define NANOCOAP_EXPOSE_DEPRECATED_API 0
#endif

#ifndef NANOCOAP_EXPOSE_DEPRECATED_API
Expand All @@ -223,7 +229,7 @@ extern "C" {
* @brief Number of transports enabled at compile-time
*/
#define NANOCOAP_ENABLED_TRANSPORTS \
(MODULE_NANOCOAP_UDP + MODULE_NANOCOAP_TCP + MODULE_NANOCOAP_DTLS)
(MODULE_NANOCOAP_UDP + MODULE_NANOCOAP_DTLS + MODULE_NANOCOAP_TCP + MODULE_NANOCOAP_WS)

/**
*
Expand All @@ -242,6 +248,12 @@ extern "C" {
*/
#define COAP_TCP_TENTATIVE_HEADER_SIZE 4

/**
* @brief Size of the CoAP over WebSocket header (excluding the Token and
* extended TKL field)
*/
#define COAP_WS_HEADER_SIZE 2

/**
* @brief Raw CoAP over UDP PDU header structure
*/
Expand All @@ -268,6 +280,7 @@ typedef enum {
COAP_TRANSPORT_UDP, /**< CoAP over UDP (see RFC 7252) */
COAP_TRANSPORT_DTLS, /**< CoAP over DTLS (see RFC 7252) */
COAP_TRANSPORT_TCP, /**< CoAP over TCP (see RFC 8323) */
COAP_TRANSPORT_WS, /**< CoAP over WebSocket (see RFC 8323) */
} coap_transport_t;

/**
Expand Down Expand Up @@ -559,6 +572,9 @@ struct _coap_request_ctx {
#endif
#if MODULE_NANOCOAP_TCP
sock_tcp_t *sock_tcp; /**< TCP socket the request was received on */
#endif
#if MODULE_NANOCOAP_WS
coap_ws_conn_t *conn_ws; /**< WebSocket connection the request was received over */
#endif
};
#if defined(MODULE_GCOAP) || DOXYGEN
Expand Down Expand Up @@ -592,6 +608,8 @@ static inline coap_transport_t coap_get_transport(const coap_pkt_t *pkt)
return COAP_TRANSPORT_DTLS;
#elif MODULE_NANOCOAP_TCP
return COAP_TRANSPORT_TCP;
#elif MODULE_NANOCOAP_WS
return COAP_TRANSPORT_WS;
#else
# error "No nanocoap transport enabled"
#endif
Expand Down Expand Up @@ -832,7 +850,8 @@ static inline unsigned coap_get_id(const coap_pkt_t *pkt)
case COAP_TRANSPORT_DTLS:
return ntohs(coap_get_udp_hdr_const(pkt)->id);
case COAP_TRANSPORT_TCP:
/* there are no message IDs in CoAP over TCP, as TCP is inherently
case COAP_TRANSPORT_WS:
/* there are no message IDs in CoAP over TCP/WS, they are inherently
* reliable */
return 0;
}
Expand All @@ -853,7 +872,8 @@ static inline void coap_set_id(coap_pkt_t *pkt, uint16_t id)
coap_get_udp_hdr(pkt)->id = ntohs(id);
break;
case COAP_TRANSPORT_TCP:
/* there are no message IDs in CoAP over TCP, as TCP is inherently
case COAP_TRANSPORT_WS:
/* there are no message IDs in CoAP over TCP/WS, they are inherently
* reliable */
return;
}
Expand Down Expand Up @@ -1022,8 +1042,13 @@ static inline unsigned coap_get_response_hdr_len(const coap_pkt_t *pkt)
default:
case COAP_TRANSPORT_UDP:
case COAP_TRANSPORT_DTLS:
case COAP_TRANSPORT_WS:
/* header length depends only on token length, which matches between
* request and response */
return coap_get_total_hdr_len(pkt);
case COAP_TRANSPORT_TCP:
/* header length also depends on payload length, which may differ
* between request and response */
break;
}

Expand Down Expand Up @@ -1053,15 +1078,19 @@ static inline void coap_hdr_set_code(coap_udp_hdr_t *hdr, uint8_t code)
*/
static inline void coap_pkt_set_code(coap_pkt_t *pkt, uint8_t code)
{
coap_udp_hdr_t *hdr = coap_get_udp_hdr(pkt);

if (hdr) {
coap_hdr_set_code(hdr, code);
}
else {
switch (coap_get_transport(pkt)) {
case COAP_TRANSPORT_UDP:
case COAP_TRANSPORT_DTLS:
coap_hdr_set_code(coap_get_udp_hdr(pkt), code);
break;
case COAP_TRANSPORT_TCP:
/* the position of the message code is not fixed
* when using CoAP over TCP / WebSockets */
* when using CoAP over TCP */
pkt->buf[2 + coap_tcp_get_ext_len(pkt)] = code;
break;
case COAP_TRANSPORT_WS:
pkt->buf[2] = code;
break;
}
}

Expand Down Expand Up @@ -2500,6 +2529,41 @@ static inline ssize_t coap_build_tcp_hdr(void *buf, size_t buf_len,
return coap_build_tcp(NULL, buf, buf_len, token, token_len, code);
}

/**
* @brief Build a CoAP over WebSocket packet
*
* @param[out] pkt Destination packet to write to
* @param[out] buf Destination buffer to write to
* @param[in] buf_len Length of @p buf in bytes
* @param[in] token token
* @param[in] token_len length of @p token
* @param[in] code CoAP code (e.g., COAP_CODE_204, ...)
*
* @return Length of the header written into the packet
*/
ssize_t coap_build_ws(coap_pkt_t *pkt, void *buf, size_t buf_len, const void *token,
size_t token_len, uint8_t code);

/**
* @brief Build a CoAP over WebSocket packet
*
* @param[out] buf Destination buffer to write to
* @param[in] buf_len Length of @p buf in bytes
* @param[in] token token
* @param[in] token_len length of @p token
* @param[in] code CoAP code (e.g., COAP_CODE_204, ...)
*
* @return length of resulting header
*
* @note You probably want to call @ref coap_build_ws instead.
*/
static inline ssize_t coap_build_ws_hdr(void *buf, size_t buf_len,
const void *token, size_t token_len,
uint8_t code)
{
return coap_build_ws(NULL, buf, buf_len, token, token_len, code);
}

/**
* @brief Finalize a CoAP over TCP packet
*
Expand Down Expand Up @@ -2749,6 +2813,22 @@ static inline ssize_t coap_parse(coap_pkt_t *pkt, uint8_t *buf, size_t len)
*/
ssize_t coap_parse_tcp(coap_pkt_t *pkt, uint8_t *buf, size_t len);

/**
* @brief Parse a CoAP PDU in WebSocket format
*
* This function parses a raw CoAP PDU from @p buf with size @p len and fills
* the structure pointed to by @p pkt.
* @p pkt must point to a preallocated coap_pkt_t structure.
*
* @param[out] pkt structure to parse into
* @param[in] buf pointer to raw packet data
* @param[in] len length of packet at @p buf
*
* @return Number of bytes parsed (will match @p len here)
* @retval <0 error
*/
ssize_t coap_parse_ws(coap_pkt_t *pkt, uint8_t *buf, size_t len);

/**
* @brief Initialize a packet struct, to build a message buffer
*
Expand Down Expand Up @@ -2900,6 +2980,7 @@ static inline ssize_t coap_reply_empty_ack(coap_pkt_t *pkt,
{
switch (coap_get_transport(pkt)) {
case COAP_TRANSPORT_TCP:
case COAP_TRANSPORT_WS:
return 0;
case COAP_TRANSPORT_UDP:
if (len < sizeof(coap_udp_hdr_t)) {
Expand Down
Loading

0 comments on commit 08ae545

Please sign in to comment.