Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

net/gcoap: Create confirm request infrastructure and adapt existing messaging #7336

Merged
merged 5 commits into from
Dec 1, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
115 changes: 67 additions & 48 deletions examples/gcoap/gcoap_cli.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2015-2016 Ken Bannister. All rights reserved.
* Copyright (c) 2015-2017 Ken Bannister. All rights reserved.
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
Expand Down Expand Up @@ -180,60 +180,79 @@ int gcoap_cli_cmd(int argc, char **argv)
goto end;
}

if (strcmp(argv[1], "info") == 0) {
uint8_t open_reqs = gcoap_op_state();

printf("CoAP server is listening on port %u\n", GCOAP_PORT);
printf(" CLI requests sent: %u\n", req_count);
printf("CoAP open requests: %u\n", open_reqs);
return 0;
}

/* if not 'info', must be a method code */
int code_pos = -1;
for (size_t i = 0; i < sizeof(method_codes) / sizeof(char*); i++) {
if (strcmp(argv[1], method_codes[i]) == 0) {
if (argc == 5 || argc == 6) {
if (argc == 6) {
gcoap_req_init(&pdu, &buf[0], GCOAP_PDU_BUF_SIZE, i+1, argv[4]);
memcpy(pdu.payload, argv[5], strlen(argv[5]));
len = gcoap_finish(&pdu, strlen(argv[5]), COAP_FORMAT_TEXT);
}
else {
len = gcoap_request(&pdu, &buf[0], GCOAP_PDU_BUF_SIZE, i+1,
argv[4]);
}
printf("gcoap_cli: sending msg ID %u, %u bytes\n", coap_get_id(&pdu),
(unsigned) len);
if (!_send(&buf[0], len, argv[2], argv[3])) {
puts("gcoap_cli: msg send failed");
}
else {
/* send Observe notification for /cli/stats */
switch (gcoap_obs_init(&pdu, &buf[0], GCOAP_PDU_BUF_SIZE,
&_resources[0])) {
case GCOAP_OBS_INIT_OK:
DEBUG("gcoap_cli: creating /cli/stats notification\n");
size_t payload_len = fmt_u16_dec((char *)pdu.payload, req_count);
len = gcoap_finish(&pdu, payload_len, COAP_FORMAT_TEXT);
gcoap_obs_send(&buf[0], len, &_resources[0]);
break;
case GCOAP_OBS_INIT_UNUSED:
DEBUG("gcoap_cli: no observer for /cli/stats\n");
break;
case GCOAP_OBS_INIT_ERR:
DEBUG("gcoap_cli: error initializing /cli/stats notification\n");
break;
}
}
return 0;
}
else {
printf("usage: %s <get|post|put> <addr> <port> <path> [data]\n",
argv[0]);
return 1;
}
code_pos = i;
}
}
if (code_pos == -1) {
goto end;
}

if (strcmp(argv[1], "info") == 0) {
if (argc == 2) {
uint8_t open_reqs = gcoap_op_state();
/* parse options */
int apos = 2; /* position of address argument */
unsigned msg_type = COAP_TYPE_NON;
if (argc > apos && strcmp(argv[apos], "-c") == 0) {
msg_type = COAP_TYPE_CON;
apos++;
}

printf("CoAP server is listening on port %u\n", GCOAP_PORT);
printf(" CLI requests sent: %u\n", req_count);
printf("CoAP open requests: %u\n", open_reqs);
return 0;
if (argc == apos + 3 || argc == apos + 4) {
gcoap_req_init(&pdu, &buf[0], GCOAP_PDU_BUF_SIZE, code_pos+1, argv[apos+2]);
if (argc == apos + 4) {
memcpy(pdu.payload, argv[apos+3], strlen(argv[apos+3]));
}
coap_hdr_set_type(pdu.hdr, msg_type);

if (argc == apos + 4) {
len = gcoap_finish(&pdu, strlen(argv[apos+3]), COAP_FORMAT_TEXT);
}
else {
len = gcoap_finish(&pdu, 0, COAP_FORMAT_NONE);
}

printf("gcoap_cli: sending msg ID %u, %u bytes\n", coap_get_id(&pdu),
(unsigned) len);
if (!_send(&buf[0], len, argv[apos], argv[apos+1])) {
puts("gcoap_cli: msg send failed");
}
else {
/* send Observe notification for /cli/stats */
switch (gcoap_obs_init(&pdu, &buf[0], GCOAP_PDU_BUF_SIZE,
&_resources[0])) {
case GCOAP_OBS_INIT_OK:
DEBUG("gcoap_cli: creating /cli/stats notification\n");
size_t payload_len = fmt_u16_dec((char *)pdu.payload, req_count);
len = gcoap_finish(&pdu, payload_len, COAP_FORMAT_TEXT);
gcoap_obs_send(&buf[0], len, &_resources[0]);
break;
case GCOAP_OBS_INIT_UNUSED:
DEBUG("gcoap_cli: no observer for /cli/stats\n");
break;
case GCOAP_OBS_INIT_ERR:
DEBUG("gcoap_cli: error initializing /cli/stats notification\n");
break;
}
}
return 0;
}
else {
printf("usage: %s <get|post|put> [-c] <addr> <port> <path> [data]\n",
argv[0]);
printf("Options\n");
printf(" -c Send confirmably (defaults to non-confirmable)\n");
return 1;
}

end:
Expand Down
26 changes: 23 additions & 3 deletions sys/include/net/gcoap.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2015-2016 Ken Bannister. All rights reserved.
* Copyright (c) 2015-2017 Ken Bannister. All rights reserved.
* 2017 Freie Universität Berlin
*
* This file is subject to the terms and conditions of the GNU Lesser
Expand Down Expand Up @@ -302,6 +302,11 @@ extern "C" {
#define GCOAP_MEMO_ERR (4) /**< Error processing response packet */
/** @} */

/**
* @brief Value for send_limit in request memo when non-confirmable type
*/
#define GCOAP_SEND_LIMIT_NON (-1)

/**
* @brief Time in usec that the event loop waits for an incoming CoAP message
*/
Expand Down Expand Up @@ -424,13 +429,28 @@ typedef struct gcoap_listener {
typedef void (*gcoap_resp_handler_t)(unsigned req_state, coap_pkt_t* pdu,
sock_udp_ep_t *remote);

/**
* @brief Extends request memo for resending a confirmable request.
*/
typedef struct {
sock_udp_ep_t remote_ep; /**< Remote endpoint */
uint8_t *pdu_buf; /**< Buffer containing the PDU */
size_t pdu_len; /**< Length of pdu_buf */
} gcoap_resend_t;

/**
* @brief Memo to handle a response for a request
*/
typedef struct {
unsigned state; /**< State of this memo, a GCOAP_MEMO... */
uint8_t hdr_buf[GCOAP_HEADER_MAXLEN];
/**< Stores a copy of the request header */
int send_limit; /**< Remaining resends, 0 if none;
GCOAP_SEND_LIMIT_NON if non-confirmable */
union {
uint8_t hdr_buf[GCOAP_HEADER_MAXLEN];
/**< Copy of PDU header, if no resends */
gcoap_resend_t data; /**< Endpoint and PDU buffer, for resend */
} msg; /**< Request message data; if confirmable,
supports resending message */
gcoap_resp_handler_t resp_handler; /**< Callback for the response */
xtimer_t response_timer; /**< Limits wait for response */
msg_t timeout_msg; /**< For response timer */
Expand Down
55 changes: 25 additions & 30 deletions sys/net/application_layer/gcoap/gcoap.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2015-2016 Ken Bannister. All rights reserved.
* Copyright (c) 2015-2017 Ken Bannister. All rights reserved.
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
Expand Down Expand Up @@ -35,8 +35,7 @@ static size_t _handle_req(coap_pkt_t *pdu, uint8_t *buf, size_t len,
sock_udp_ep_t *remote);
static ssize_t _finish_pdu(coap_pkt_t *pdu, uint8_t *buf, size_t len);
static void _expire_request(gcoap_request_memo_t *memo);
static void _find_req_memo(gcoap_request_memo_t **memo_ptr, coap_pkt_t *pdu,
uint8_t *buf, size_t len);
static void _find_req_memo(gcoap_request_memo_t **memo_ptr, coap_pkt_t *pdu);
static void _find_resource(coap_pkt_t *pdu, coap_resource_t **resource_ptr,
gcoap_listener_t **listener_ptr);
static int _find_observer(sock_udp_ep_t **observer, sock_udp_ep_t *remote);
Expand Down Expand Up @@ -156,7 +155,7 @@ static void _listen(sock_udp_t *sock)

/* incoming response */
else {
_find_req_memo(&memo, &pdu, buf, sizeof(buf));
_find_req_memo(&memo, &pdu);
if (memo) {
xtimer_remove(&memo->response_timer);
memo->state = GCOAP_MEMO_RESP;
Expand Down Expand Up @@ -331,39 +330,34 @@ static ssize_t _finish_pdu(coap_pkt_t *pdu, uint8_t *buf, size_t len)
* Finds the memo for an outstanding request within the _coap_state.open_reqs
* array. Matches on token.
*
* src_pdu Source for the match token
* memo_ptr[out] -- Registered request memo, or NULL if not found
* src_pdu[in] -- PDU for token to match
*/
static void _find_req_memo(gcoap_request_memo_t **memo_ptr, coap_pkt_t *src_pdu,
uint8_t *buf, size_t len)
static void _find_req_memo(gcoap_request_memo_t **memo_ptr, coap_pkt_t *src_pdu)
{
gcoap_request_memo_t *memo;
coap_pkt_t memo_pdu = { .token = NULL };
(void) buf;
(void) len;
*memo_ptr = NULL;
/* no need to initialize struct; we only care about buffer contents below */
coap_pkt_t memo_pdu_data;
coap_pkt_t *memo_pdu = &memo_pdu_data;
unsigned cmplen = coap_get_token_len(src_pdu);

for (int i = 0; i < GCOAP_REQ_WAITING_MAX; i++) {
if (_coap_state.open_reqs[i].state == GCOAP_MEMO_UNUSED)
continue;

/* setup memo PDU from memo header */
memo = &_coap_state.open_reqs[i];
coap_hdr_t *memo_hdr = (coap_hdr_t *) &memo->hdr_buf[0];
memo_pdu.hdr = memo_hdr;
if (coap_get_token_len(&memo_pdu)) {
memo_pdu.token = &memo_hdr->data[0];
gcoap_request_memo_t *memo = &_coap_state.open_reqs[i];
if (memo->send_limit == GCOAP_SEND_LIMIT_NON) {
memo_pdu->hdr = (coap_hdr_t *) &memo->msg.hdr_buf[0];
}
/* match on token */
if (coap_get_token_len(src_pdu) == coap_get_token_len(&memo_pdu)) {
uint8_t *src_byte = src_pdu->token;
uint8_t *memo_byte = memo_pdu.token;
size_t j;
for (j = 0; j < coap_get_token_len(src_pdu); j++) {
if (*src_byte++ != *memo_byte++) {
break; /* token mismatch */
}
}
if (j == coap_get_token_len(src_pdu)) {
else {
memo_pdu->hdr = (coap_hdr_t *) memo->msg.data.pdu_buf;
}

if (coap_get_token_len(memo_pdu) == cmplen) {
memo_pdu->token = &memo_pdu->hdr->data[0];
if (memcmp(src_pdu->token, memo_pdu->token, cmplen) == 0) {
*memo_ptr = memo;
break;
}
}
}
Expand All @@ -379,7 +373,7 @@ static void _expire_request(gcoap_request_memo_t *memo)
memo->state = GCOAP_MEMO_TIMEOUT;
/* Pass response to handler */
if (memo->resp_handler) {
req.hdr = (coap_hdr_t *)&memo->hdr_buf[0]; /* for reference */
req.hdr = (coap_hdr_t *)&memo->msg.hdr_buf[0]; /* for reference */
memo->resp_handler(memo->state, &req, NULL);
}
memo->state = GCOAP_MEMO_UNUSED;
Expand Down Expand Up @@ -692,7 +686,8 @@ size_t gcoap_req_send2(const uint8_t *buf, size_t len,
mutex_unlock(&_coap_state.lock);

if (memo) {
memcpy(&memo->hdr_buf[0], buf, GCOAP_HEADER_MAXLEN);
memo->send_limit = GCOAP_SEND_LIMIT_NON;
memcpy(&memo->msg.hdr_buf[0], buf, GCOAP_HEADER_MAXLEN);
memo->resp_handler = resp_handler;

size_t res = sock_udp_send(&_sock, buf, len, remote);
Expand Down