Skip to content

Commit

Permalink
nanocoap_sock: implement nanocoap_sock_send_separate()
Browse files Browse the repository at this point in the history
  • Loading branch information
benpicco committed Jan 16, 2024
1 parent 8e5212c commit ec51e63
Show file tree
Hide file tree
Showing 2 changed files with 112 additions and 0 deletions.
49 changes: 49 additions & 0 deletions sys/include/net/nanocoap_sock.h
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,55 @@ typedef struct {
uint8_t blksize; /**< CoAP blocksize exponent */
} coap_block_request_t;

/**
* @brief Request context 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_sock_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_sock_prepare_separate(nanocoap_sock_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_sock_prepare_separate has been called on @p ctx
* inside the CoAP handler
*
* @param[in] ctx Context information about the CoAP request
* @param[in] code CoAP response code
* @param[in] type Response type, may be `COAP_TYPE_NON` or `COAP_TYPE_RST`
* @param[in] payload Response payload
* @param[in] len Payload length
*
* @returns 0 on success
* negative error (see @ref sock_udp_sendv_aux)
*/
int nanocoap_sock_send_separate(const nanocoap_sock_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.
Expand Down
63 changes: 63 additions & 0 deletions sys/net/application_layer/nanocoap/sock.c
Original file line number Diff line number Diff line change
Expand Up @@ -882,3 +882,66 @@ void auto_init_nanocoap_server(void)

nanocoap_server_start(&local);
}

void nanocoap_sock_prepare_separate(nanocoap_sock_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_sock_send_separate(const nanocoap_sock_response_ctx_t *ctx,
unsigned code, unsigned type,
const void *payload, size_t len)
{
uint8_t rbuf[32];
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 (code & 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);
}

0 comments on commit ec51e63

Please sign in to comment.