mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2025-01-17 05:12:57 +01:00
nanocoap_sock: implement nanocoap_sock_send_separate()
This commit is contained in:
parent
330a6cfb91
commit
7e69c13630
@ -182,6 +182,48 @@ NANOCOAP_RESOURCE(sha256) {
|
||||
.path = "/sha256", .methods = COAP_POST, .handler = _sha256_handler
|
||||
};
|
||||
|
||||
/* separate response requires an event thread to execute it */
|
||||
#ifdef MODULE_EVENT_THREAD
|
||||
static nanocoap_server_response_ctx_t _separate_ctx;
|
||||
static bool _separate_in_progress;
|
||||
|
||||
static void _send_response(void *ctx)
|
||||
{
|
||||
const char response[] = "This is a delayed response.";
|
||||
|
||||
puts("_separate_handler(): send delayed response");
|
||||
nanocoap_sock_send_separate(ctx, COAP_CODE_CONTENT, COAP_TYPE_NON,
|
||||
response, sizeof(response));
|
||||
_separate_in_progress = false;
|
||||
}
|
||||
|
||||
static ssize_t _separate_handler(coap_pkt_t *pkt, uint8_t *buf, size_t len, coap_request_ctx_t *context)
|
||||
{
|
||||
static event_timeout_t event_timeout;
|
||||
static event_callback_t event_timed = EVENT_CALLBACK_INIT(_send_response, &_separate_ctx);
|
||||
|
||||
if (_separate_in_progress) {
|
||||
puts("_separate_handler(): response already scheduled");
|
||||
return coap_build_reply(pkt, COAP_CODE_SERVICE_UNAVAILABLE, buf, len, 0);
|
||||
}
|
||||
|
||||
puts("_separate_handler(): send ACK, schedule response");
|
||||
|
||||
nanocoap_sock_prepare_separate(&_separate_ctx, pkt, context);
|
||||
_separate_in_progress = true;
|
||||
|
||||
event_timeout_ztimer_init(&event_timeout, ZTIMER_MSEC, EVENT_PRIO_MEDIUM,
|
||||
&event_timed.super);
|
||||
event_timeout_set(&event_timeout, 1 * MS_PER_SEC);
|
||||
|
||||
return coap_build_empty_ack(pkt, buf, len);
|
||||
}
|
||||
|
||||
NANOCOAP_RESOURCE(separate) {
|
||||
.path = "/separate", .methods = COAP_GET, .handler = _separate_handler,
|
||||
};
|
||||
#endif /* MODULE_EVENT_THREAD */
|
||||
|
||||
/* we can also include the fileserver module */
|
||||
#ifdef MODULE_NANOCOAP_FILESERVER
|
||||
#include "net/nanocoap/fileserver.h"
|
||||
|
@ -544,6 +544,11 @@ ifneq (,$(filter nanocoap_server_auto_init,$(USEMODULE)))
|
||||
USEMODULE += nanocoap_server
|
||||
endif
|
||||
|
||||
ifneq (,$(filter nanocoap_server_separate,$(USEMODULE)))
|
||||
USEMODULE += nanocoap_server
|
||||
USEMODULE += sock_aux_local
|
||||
endif
|
||||
|
||||
ifneq (,$(filter nanocoap_server,$(USEMODULE)))
|
||||
USEMODULE += nanocoap_resources
|
||||
USEMODULE += nanocoap_sock
|
||||
|
@ -209,6 +209,55 @@ typedef struct {
|
||||
uint8_t blksize; /**< CoAP blocksize exponent */
|
||||
} coap_block_request_t;
|
||||
|
||||
/**
|
||||
* @brief Context from CoAP request for separate response
|
||||
*/
|
||||
typedef struct {
|
||||
sock_udp_ep_t remote; /**< remote to send response to */
|
||||
#if defined(MODULE_SOCK_AUX_LOCAL) || DOXYGEN
|
||||
sock_udp_ep_t local; /**< local from which to send response */
|
||||
#endif
|
||||
uint8_t token[COAP_TOKEN_LENGTH_MAX]; /**< request token */
|
||||
uint8_t tkl; /**< request token length */
|
||||
uint8_t no_response; /**< no-response bitmap */
|
||||
} nanocoap_server_response_ctx_t;
|
||||
|
||||
/**
|
||||
* @brief Prepare the context for a separate response
|
||||
*
|
||||
* This function serializes the CoAP request information so that
|
||||
* a separate response can be generated outside the CoAP handler.
|
||||
*
|
||||
* The CoAP handler should then respond with an empty ACK by calling
|
||||
* @ref coap_build_empty_ack
|
||||
*
|
||||
* @param[out] ctx Context information for separate response
|
||||
* @param[in] pkt CoAP packet to which the response will be generated
|
||||
* @param[in] req Context of the CoAP request
|
||||
*/
|
||||
void nanocoap_server_prepare_separate(nanocoap_server_response_ctx_t *ctx,
|
||||
coap_pkt_t *pkt, const coap_request_ctx_t *req);
|
||||
|
||||
/**
|
||||
* @brief Send a separate response to a CoAP request
|
||||
*
|
||||
* This sends a response to a CoAP request outside the CoAP handler
|
||||
*
|
||||
* @pre @ref nanocoap_server_prepare_separate has been called on @p ctx
|
||||
* inside the CoAP handler
|
||||
*
|
||||
* @param[in] ctx Context information for the CoAP response
|
||||
* @param[in] code CoAP response code
|
||||
* @param[in] type Response type, may be `COAP_TYPE_NON`
|
||||
* @param[in] payload Response payload
|
||||
* @param[in] len Payload length
|
||||
*
|
||||
* @returns 0 on success
|
||||
* negative error (see @ref sock_udp_sendv_aux)
|
||||
*/
|
||||
int nanocoap_server_send_separate(const nanocoap_server_response_ctx_t *ctx,
|
||||
unsigned code, unsigned type,
|
||||
const void *payload, size_t len);
|
||||
/**
|
||||
* @brief Get next consecutive message ID for use when building a new
|
||||
* CoAP request.
|
||||
|
@ -882,3 +882,66 @@ void auto_init_nanocoap_server(void)
|
||||
|
||||
nanocoap_server_start(&local);
|
||||
}
|
||||
|
||||
void nanocoap_server_prepare_separate(nanocoap_server_response_ctx_t *ctx,
|
||||
coap_pkt_t *pkt, const coap_request_ctx_t *req)
|
||||
{
|
||||
ctx->tkl = coap_get_token_len(pkt);
|
||||
memcpy(ctx->token, coap_get_token(pkt), ctx->tkl);
|
||||
memcpy(&ctx->remote, req->remote, sizeof(ctx->remote));
|
||||
#ifdef MODULE_SOCK_AUX_LOCAL
|
||||
assert(req->local);
|
||||
memcpy(&ctx->local, req->local, sizeof(ctx->local));
|
||||
#endif
|
||||
uint32_t no_response = 0;
|
||||
coap_opt_get_uint(pkt, COAP_OPT_NO_RESPONSE, &no_response);
|
||||
ctx->no_response = no_response;
|
||||
}
|
||||
|
||||
int nanocoap_server_send_separate(const nanocoap_server_response_ctx_t *ctx,
|
||||
unsigned code, unsigned type,
|
||||
const void *payload, size_t len)
|
||||
{
|
||||
uint8_t rbuf[sizeof(coap_hdr_t) + COAP_TOKEN_LENGTH_MAX + 1];
|
||||
assert(type != COAP_TYPE_ACK);
|
||||
assert(type != COAP_TYPE_CON); /* TODO: add support */
|
||||
|
||||
const uint8_t no_response_index = (code >> 5) - 1;
|
||||
/* If the handler code misbehaved here, we'd face UB otherwise */
|
||||
assert(no_response_index < 7);
|
||||
|
||||
const uint8_t mask = 1 << no_response_index;
|
||||
if (ctx->no_response & mask) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
iolist_t data = {
|
||||
.iol_base = (void *)payload,
|
||||
.iol_len = len,
|
||||
};
|
||||
|
||||
iolist_t head = {
|
||||
.iol_next = &data,
|
||||
.iol_base = rbuf,
|
||||
};
|
||||
head.iol_len = coap_build_hdr((coap_hdr_t *)rbuf, type,
|
||||
ctx->token, ctx->tkl,
|
||||
code, random_uint32());
|
||||
if (len) {
|
||||
rbuf[head.iol_len++] = 0xFF;
|
||||
}
|
||||
|
||||
sock_udp_aux_tx_t *aux_out_ptr = NULL;
|
||||
#ifdef MODULE_SOCK_AUX_LOCAL
|
||||
/* make sure we reply with the same address that the request was
|
||||
* destined for -- except in the multicast case */
|
||||
sock_udp_aux_tx_t aux_out = {
|
||||
.flags = SOCK_AUX_SET_LOCAL,
|
||||
.local = ctx->local,
|
||||
};
|
||||
if (!sock_udp_ep_is_multicast(&ctx->local)) {
|
||||
aux_out_ptr = &aux_out;
|
||||
}
|
||||
#endif
|
||||
return sock_udp_sendv_aux(NULL, &head, &ctx->remote, aux_out_ptr);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user