Skip to content

Commit

Permalink
examples/gcoap: add /separate resource
Browse files Browse the repository at this point in the history
  • Loading branch information
fabian18 committed Aug 27, 2024
1 parent 6220a73 commit 280ee9a
Showing 1 changed file with 99 additions and 0 deletions.
99 changes: 99 additions & 0 deletions examples/gcoap/server.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,13 @@
#include <time.h>

#include "event/periodic_callback.h"
#include "event/timeout.h"
#include "event/thread.h"
#include "fmt.h"
#include "net/coap.h"
#include "net/gcoap.h"
#include "net/nanocoap.h"
#include "net/sock/util.h"
#include "net/utils.h"
#include "od.h"
#include "periph/rtc.h"
Expand Down Expand Up @@ -68,6 +72,7 @@ static ssize_t _riot_board_handler(coap_pkt_t* pdu, uint8_t *buf, size_t len, co
#if IS_USED(MODULE_PERIPH_RTC)
static ssize_t _rtc_handler(coap_pkt_t* pdu, uint8_t *buf, size_t len, coap_request_ctx_t *ctx);
#endif
static ssize_t _separate_handler(coap_pkt_t *pkt, uint8_t *buf, size_t len, coap_request_ctx_t *context);

Check warning on line 75 in examples/gcoap/server.c

View workflow job for this annotation

GitHub Actions / static-tests

line is longer than 100 characters

/* CoAP resources. Must be sorted by path (ASCII order). */
static const coap_resource_t _resources[] = {
Expand All @@ -76,6 +81,7 @@ static const coap_resource_t _resources[] = {
#if IS_USED(MODULE_PERIPH_RTC)
{ "/rtc", COAP_GET, _rtc_handler, NULL },
#endif
{ "/separate", COAP_GET, _separate_handler, NULL },
};

static const char *_link_params[] = {
Expand Down Expand Up @@ -227,6 +233,99 @@ static ssize_t _riot_board_handler(coap_pkt_t *pdu, uint8_t *buf, size_t len, co
}
}

/* separate response requires an event thread to execute it */
#ifndef CONFIG_EXAMPLE_GCOAP_SEPARATE_EVENT_QUEUE
#ifdef MODULE_EVENT_THREAD
#define CONFIG_EXAMPLE_GCOAP_SEPARATE_EVENT_QUEUE EVENT_PRIO_MEDIUM
#else
#define CONFIG_EXAMPLE_GCOAP_SEPARATE_EVENT_QUEUE gcoap_get_event_queue()
#endif
#endif
#ifndef CONFIG_EXAMPLE_GCOAP_SEPARATE_RESP_PDU_BUF_SIZE
#define CONFIG_EXAMPLE_GCOAP_SEPARATE_RESP_PDU_BUF_SIZE (32)
#endif
#ifndef CONFIG_EXAMPLE_GCOAP_SEPARATE_REQ_PDU_BUF_SIZE
#define CONFIG_EXAMPLE_GCOAP_SEPARATE_REQ_PDU_BUF_SIZE (32)
#endif

static void _send_separate_response_cb(event_t *ev)
{
gcoap_separate_response_ctx_t *ctx = container_of(ev, gcoap_separate_response_ctx_t, ev);
coap_pkt_t req = { 0 };
/* parse request again */
coap_parse(&req, ctx->req_buf, ctx->req_buf_size);
/* determine response type */
unsigned type = coap_get_type(&req) == COAP_TYPE_CON ? COAP_TYPE_CON : COAP_TYPE_NON;
/* determine response code */
unsigned code = ctx->result < 0 ? COAP_CODE_INTERNAL_SERVER_ERROR : COAP_CODE_CONTENT;
/* build simple response without further options or payload */
coap_pkt_t resp = req;
if (gcoap_separate_resp_init(&resp, ctx->resp_buf, ctx->resp_buf_size, type, code) < 0) {
puts("_send_separate_response(): failed to init separate response");
return;
}
/* maybe add options */
/* add payload */
ssize_t len;
if ((len = coap_opt_finish(&resp, COAP_OPT_FINISH_PAYLOAD)) < 0) {
printf("_send_separate_response(): failed to finish response %d\n", len);
return;
}
if (resp.payload_len) {
strncpy((char *)resp.payload, "This is a delayed response.", resp.payload_len - 1);
resp.payload_len = strlen((char *)resp.payload);
len += resp.payload_len;
}
/* send response */
if ((len = gcoap_resp_send_separate(ctx->resp_buf, len, &ctx->remote, &ctx->local, ctx->tl)) <= 0) {

Check warning on line 280 in examples/gcoap/server.c

View workflow job for this annotation

GitHub Actions / static-tests

line is longer than 100 characters
printf("_send_separate_response(): failed to send response %d\n", len);
return;
}
}

/* buffer size can be adjusted to fit the expectation of a resource */
static uint8_t _sep_req[CONFIG_EXAMPLE_GCOAP_SEPARATE_RESP_PDU_BUF_SIZE];
static uint8_t _sep_resp[CONFIG_EXAMPLE_GCOAP_SEPARATE_REQ_PDU_BUF_SIZE];
static gcoap_separate_response_ctx_t _separate_ctx = {
.ev = {
.handler = _send_separate_response_cb,
}
};

static ssize_t _separate_handler(coap_pkt_t *pkt, uint8_t *buf, size_t len, coap_request_ctx_t *context)

Check warning on line 295 in examples/gcoap/server.c

View workflow job for this annotation

GitHub Actions / static-tests

line is longer than 100 characters
{
static event_timeout_t _event_timeout;

if (event_timeout_is_pending(&_event_timeout)) {
if (!sock_udp_ep_equal(context->remote, &_separate_ctx.remote)) {
puts("_separate_handler(): response already scheduled");
return gcoap_response(pkt, buf, len, COAP_CODE_SERVICE_UNAVAILABLE);
}
else {
/* ignore, maybe ACK got lost */
goto empty_ack;
}
}
if (gcoap_resp_prepare_separate(&_separate_ctx,
_sep_req, sizeof(_sep_req),
_sep_resp, sizeof(_sep_resp),
pkt, context) < 0) {
puts("_separate_handler(): request too large");
return gcoap_response(pkt, buf, len, COAP_CODE_REQUEST_ENTITY_TOO_LARGE);
}

puts("_separate_handler(): schedule response");

event_timeout_ztimer_init(&_event_timeout, ZTIMER_MSEC,
CONFIG_EXAMPLE_GCOAP_SEPARATE_EVENT_QUEUE,
&_separate_ctx.ev);
event_timeout_set(&_event_timeout, 3 * MS_PER_SEC);

empty_ack:
/* gcoap handles transmission of empty ACK */
return 0;
}

void notify_observers(void)
{
size_t len;
Expand Down

0 comments on commit 280ee9a

Please sign in to comment.