1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00

net/gcoap: add sock_async event handling

Rework from earlier custom event/msg handling.
This commit is contained in:
Ken Bannister 2020-02-16 08:20:10 -05:00
parent 20e912fcfa
commit ea62734baf
2 changed files with 76 additions and 176 deletions

View File

@ -362,13 +362,6 @@ extern "C" {
* @ingroup config
* @{
*/
/**
* @brief Size for module message queue
*/
#ifndef CONFIG_GCOAP_MSG_QUEUE_SIZE
#define CONFIG_GCOAP_MSG_QUEUE_SIZE (4)
#endif
/**
* @brief Server port; use RFC 7252 default if not defined
*/
@ -481,14 +474,6 @@ extern "C" {
*/
#define GCOAP_SEND_LIMIT_NON (-1)
/**
* @ingroup net_gcoap_conf
* @brief Time in usec that the event loop waits for an incoming CoAP message
*/
#ifndef CONFIG_GCOAP_RECV_TIMEOUT
#define CONFIG_GCOAP_RECV_TIMEOUT (1 * US_PER_SEC)
#endif
#ifdef DOXYGEN
/**
* @ingroup net_gcoap_conf

View File

@ -27,6 +27,7 @@
#include "assert.h"
#include "net/gcoap.h"
#include "net/sock/async/event.h"
#include "net/sock/util.h"
#include "mutex.h"
#include "random.h"
@ -45,11 +46,10 @@
/* Internal functions */
static void *_event_loop(void *arg);
static void _listen(sock_udp_t *sock);
static void _on_sock_evt(sock_udp_t *sock, sock_async_flags_t type);
static ssize_t _well_known_core_handler(coap_pkt_t* pdu, uint8_t *buf, size_t len, void *ctx);
static size_t _handle_req(coap_pkt_t *pdu, uint8_t *buf, size_t len,
sock_udp_ep_t *remote);
static void _expire_request(gcoap_request_memo_t *memo);
static void _find_req_memo(gcoap_request_memo_t **memo_ptr, coap_pkt_t *pdu,
const sock_udp_ep_t *remote);
static int _find_resource(coap_pkt_t *pdu, const coap_resource_t **resource_ptr,
@ -98,19 +98,16 @@ static gcoap_state_t _coap_state = {
static kernel_pid_t _pid = KERNEL_PID_UNDEF;
static char _msg_stack[GCOAP_STACK_SIZE];
static msg_t _msg_queue[CONFIG_GCOAP_MSG_QUEUE_SIZE];
static event_queue_t _queue;
static uint8_t _listen_buf[CONFIG_GCOAP_PDU_BUF_SIZE];
static sock_udp_t _sock;
/* Event/Message loop for gcoap _pid thread. */
/* Event loop for gcoap _pid thread. */
static void *_event_loop(void *arg)
{
msg_t msg_rcvd;
(void)arg;
msg_init_queue(_msg_queue, CONFIG_GCOAP_MSG_QUEUE_SIZE);
sock_udp_ep_t local;
memset(&local, 0, sizeof(sock_udp_ep_t));
local.family = AF_INET6;
@ -123,150 +120,96 @@ static void *_event_loop(void *arg)
return 0;
}
while(1) {
res = msg_try_receive(&msg_rcvd);
if (res > 0) {
switch (msg_rcvd.type) {
case GCOAP_MSG_TYPE_TIMEOUT: {
gcoap_request_memo_t *memo = (gcoap_request_memo_t *)msg_rcvd.content.ptr;
/* no retries remaining */
if ((memo->send_limit == GCOAP_SEND_LIMIT_NON)
|| (memo->send_limit == 0)) {
_expire_request(memo);
}
/* reduce retries remaining, double timeout and resend */
else {
memo->send_limit--;
#ifdef CONFIG_GCOAP_NO_RETRANS_BACKOFF
unsigned i = 0;
#else
unsigned i = COAP_MAX_RETRANSMIT - memo->send_limit;
#endif
uint32_t timeout = ((uint32_t)COAP_ACK_TIMEOUT << i) * US_PER_SEC;
#if COAP_RANDOM_FACTOR_1000 > 1000
uint32_t end = ((uint32_t)TIMEOUT_RANGE_END << i) * US_PER_SEC;
timeout = random_uint32_range(timeout, end);
#endif
ssize_t bytes = sock_udp_send(&_sock, memo->msg.data.pdu_buf,
memo->msg.data.pdu_len,
&memo->remote_ep);
if (bytes > 0) {
xtimer_set_msg(&memo->response_timer, timeout,
&memo->timeout_msg, _pid);
}
else {
DEBUG("gcoap: sock resend failed: %d\n", (int)bytes);
_expire_request(memo);
}
}
break;
}
default:
break;
}
}
_listen(&_sock);
}
event_queue_init(&_queue);
sock_udp_event_init(&_sock, &_queue, _on_sock_evt);
event_loop(&_queue);
return 0;
}
/* Listen for an incoming CoAP message. */
static void _listen(sock_udp_t *sock)
/* Handles sock events from the event queue. */
static void _on_sock_evt(sock_udp_t *sock, sock_async_flags_t type)
{
coap_pkt_t pdu;
sock_udp_ep_t remote;
gcoap_request_memo_t *memo = NULL;
uint8_t open_reqs = gcoap_op_state();
/* We expect a -EINTR response here when unlimited waiting (SOCK_NO_TIMEOUT)
* is interrupted when sending a message in gcoap_req_send(). While a
* request is outstanding, sock_udp_recv() is called here with limited
* waiting so the request's timeout can be handled in a timely manner in
* _event_loop(). */
ssize_t res = sock_udp_recv(sock, _listen_buf, sizeof(_listen_buf),
open_reqs > 0 ? CONFIG_GCOAP_RECV_TIMEOUT : SOCK_NO_TIMEOUT,
&remote);
if (res <= 0) {
#if ENABLE_DEBUG
if (res < 0 && res != -ETIMEDOUT) {
if (type & SOCK_ASYNC_MSG_RECV) {
ssize_t res = sock_udp_recv(sock, _listen_buf, sizeof(_listen_buf),
0, &remote);
if (res <= 0) {
DEBUG("gcoap: udp recv failure: %d\n", res);
return;
}
#endif
return;
}
res = coap_parse(&pdu, _listen_buf, res);
if (res < 0) {
DEBUG("gcoap: parse failure: %d\n", (int)res);
/* If a response, can't clear memo, but it will timeout later. */
return;
}
res = coap_parse(&pdu, _listen_buf, res);
if (res < 0) {
DEBUG("gcoap: parse failure: %d\n", (int)res);
/* If a response, can't clear memo, but it will timeout later. */
return;
}
if (pdu.hdr->code == COAP_CODE_EMPTY) {
DEBUG("gcoap: empty messages not handled yet\n");
return;
}
if (pdu.hdr->code == COAP_CODE_EMPTY) {
DEBUG("gcoap: empty messages not handled yet\n");
return;
}
/* validate class and type for incoming */
switch (coap_get_code_class(&pdu)) {
/* incoming request */
case COAP_CLASS_REQ:
if (coap_get_type(&pdu) == COAP_TYPE_NON
|| coap_get_type(&pdu) == COAP_TYPE_CON) {
size_t pdu_len = _handle_req(&pdu, _listen_buf, sizeof(_listen_buf),
&remote);
if (pdu_len > 0) {
ssize_t bytes = sock_udp_send(sock, _listen_buf, pdu_len,
&remote);
if (bytes <= 0) {
DEBUG("gcoap: send response failed: %d\n", (int)bytes);
/* validate class and type for incoming */
switch (coap_get_code_class(&pdu)) {
/* incoming request */
case COAP_CLASS_REQ:
if (coap_get_type(&pdu) == COAP_TYPE_NON
|| coap_get_type(&pdu) == COAP_TYPE_CON) {
size_t pdu_len = _handle_req(&pdu, _listen_buf, sizeof(_listen_buf),
&remote);
if (pdu_len > 0) {
ssize_t bytes = sock_udp_send(sock, _listen_buf, pdu_len,
&remote);
if (bytes <= 0) {
DEBUG("gcoap: send response failed: %d\n", (int)bytes);
}
}
}
}
else {
DEBUG("gcoap: illegal request type: %u\n", coap_get_type(&pdu));
}
break;
/* incoming response */
case COAP_CLASS_SUCCESS:
case COAP_CLASS_CLIENT_FAILURE:
case COAP_CLASS_SERVER_FAILURE:
_find_req_memo(&memo, &pdu, &remote);
if (memo) {
switch (coap_get_type(&pdu)) {
case COAP_TYPE_NON:
case COAP_TYPE_ACK:
xtimer_remove(&memo->response_timer);
memo->state = GCOAP_MEMO_RESP;
if (memo->resp_handler) {
memo->resp_handler(memo, &pdu, &remote);
}
if (memo->send_limit >= 0) { /* if confirmable */
*memo->msg.data.pdu_buf = 0; /* clear resend PDU buffer */
}
memo->state = GCOAP_MEMO_UNUSED;
break;
case COAP_TYPE_CON:
DEBUG("gcoap: separate CON response not handled yet\n");
break;
default:
DEBUG("gcoap: illegal response type: %u\n", coap_get_type(&pdu));
break;
else {
DEBUG("gcoap: illegal request type: %u\n", coap_get_type(&pdu));
}
break;
/* incoming response */
case COAP_CLASS_SUCCESS:
case COAP_CLASS_CLIENT_FAILURE:
case COAP_CLASS_SERVER_FAILURE:
_find_req_memo(&memo, &pdu, &remote);
if (memo) {
switch (coap_get_type(&pdu)) {
case COAP_TYPE_NON:
case COAP_TYPE_ACK:
xtimer_remove(&memo->response_timer);
memo->state = GCOAP_MEMO_RESP;
if (memo->resp_handler) {
memo->resp_handler(memo, &pdu, &remote);
}
if (memo->send_limit >= 0) { /* if confirmable */
*memo->msg.data.pdu_buf = 0; /* clear resend PDU buffer */
}
memo->state = GCOAP_MEMO_UNUSED;
break;
case COAP_TYPE_CON:
DEBUG("gcoap: separate CON response not handled yet\n");
break;
default:
DEBUG("gcoap: illegal response type: %u\n", coap_get_type(&pdu));
break;
}
}
else {
DEBUG("gcoap: msg not found for ID: %u\n", coap_get_id(&pdu));
}
break;
default:
DEBUG("gcoap: illegal code class: %u\n", coap_get_code_class(&pdu));
}
else {
DEBUG("gcoap: msg not found for ID: %u\n", coap_get_id(&pdu));
}
break;
default:
DEBUG("gcoap: illegal code class: %u\n", coap_get_code_class(&pdu));
}
}
@ -478,34 +421,6 @@ static void _find_req_memo(gcoap_request_memo_t **memo_ptr, coap_pkt_t *src_pdu,
}
}
/* Calls handler callback on receipt of a timeout message. */
static void _expire_request(gcoap_request_memo_t *memo)
{
DEBUG("coap: received timeout message\n");
if (memo->state == GCOAP_MEMO_WAIT) {
memo->state = GCOAP_MEMO_TIMEOUT;
/* Pass response to handler */
if (memo->resp_handler) {
coap_pkt_t req;
if (memo->send_limit == GCOAP_SEND_LIMIT_NON) {
req.hdr = (coap_hdr_t *)&memo->msg.hdr_buf[0]; /* for reference */
}
else {
req.hdr = (coap_hdr_t *)memo->msg.data.pdu_buf;
}
memo->resp_handler(memo, &req, NULL);
}
if (memo->send_limit != GCOAP_SEND_LIMIT_NON) {
*memo->msg.data.pdu_buf = 0; /* clear resend buffer */
}
memo->state = GCOAP_MEMO_UNUSED;
}
else {
/* Response already handled; timeout must have fired while response */
/* was in queue. */
}
}
/*
* Handler for /.well-known/core. Lists registered handlers, except for
* /.well-known/core itself.