Skip to content

Commit

Permalink
Merge pull request #13894 from kb2ma/gcoap/ping
Browse files Browse the repository at this point in the history
net/gcoap: add CoAP ping request
  • Loading branch information
leandrolanzieri authored Apr 21, 2020
2 parents 5293e54 + c267633 commit 46507ff
Show file tree
Hide file tree
Showing 6 changed files with 131 additions and 37 deletions.
34 changes: 18 additions & 16 deletions examples/gcoap/gcoap_cli.c
Original file line number Diff line number Diff line change
Expand Up @@ -302,7 +302,7 @@ static size_t _send(uint8_t *buf, size_t len, char *addr_str, char *port_str)
int gcoap_cli_cmd(int argc, char **argv)
{
/* Ordered like the RFC method code numbers, but off by 1. GET is code 0. */
char *method_codes[] = {"get", "post", "put"};
char *method_codes[] = {"ping", "get", "post", "put"};
uint8_t buf[CONFIG_GCOAP_PDU_BUF_SIZE];
coap_pkt_t pdu;
size_t len;
Expand Down Expand Up @@ -351,7 +351,7 @@ int gcoap_cli_cmd(int argc, char **argv)
return 1;
}

/* if not 'info' and 'proxy', must be a method code */
/* if not 'info' and 'proxy', must be a method code or ping */
int code_pos = -1;
for (size_t i = 0; i < ARRAY_SIZE(method_codes); i++) {
if (strcmp(argv[1], method_codes[i]) == 0) {
Expand All @@ -363,32 +363,33 @@ int gcoap_cli_cmd(int argc, char **argv)
}

/* parse options */
int apos = 2; /* position of address argument */
unsigned msg_type = COAP_TYPE_NON;
int apos = 2; /* position of address argument */
/* ping must be confirmable */
unsigned msg_type = (!code_pos ? COAP_TYPE_CON : COAP_TYPE_NON);
if (argc > apos && strcmp(argv[apos], "-c") == 0) {
msg_type = COAP_TYPE_CON;
apos++;
}

/*
* "get" (code_pos 0) must have exactly apos + 3 arguments
* while "post" (code_pos 1) and "put" (code_pos 2) and must have exactly
* apos + 4 arguments
*/
if (((argc == apos + 3) && (code_pos == 0)) ||
((argc == apos + 4) && (code_pos != 0))) {
if (((argc == apos + 2) && (code_pos == 0)) || /* ping */
((argc == apos + 3) && (code_pos == 1)) || /* get */
((argc == apos + 4) && (code_pos > 1))) { /* post or put */

char *uri = argv[apos+2];
int uri_len = strlen(argv[apos+2]);
char *uri = NULL;
int uri_len = 0;
if (code_pos) {
uri = argv[apos+2];
uri_len = strlen(argv[apos+2]);
}

if (_proxied) {
uri_len = snprintf(proxy_uri, 64, "coap://[%s]:%s%s", argv[apos], argv[apos+1], uri);
uri = proxy_uri;

gcoap_req_init(&pdu, &buf[0], CONFIG_GCOAP_PDU_BUF_SIZE, code_pos+1, NULL);
gcoap_req_init(&pdu, &buf[0], CONFIG_GCOAP_PDU_BUF_SIZE, code_pos, NULL);
}
else{
gcoap_req_init(&pdu, &buf[0], CONFIG_GCOAP_PDU_BUF_SIZE, code_pos+1, uri);
gcoap_req_init(&pdu, &buf[0], CONFIG_GCOAP_PDU_BUF_SIZE, code_pos, uri);
}
coap_hdr_set_type(pdu.hdr, msg_type);

Expand Down Expand Up @@ -450,13 +451,14 @@ int gcoap_cli_cmd(int argc, char **argv)
else {
printf("usage: %s <get|post|put> [-c] <addr>[%%iface] <port> <path> [data]\n",
argv[0]);
printf(" %s ping <addr>[%%iface] <port>\n", argv[0]);
printf("Options\n");
printf(" -c Send confirmably (defaults to non-confirmable)\n");
return 1;
}

end:
printf("usage: %s <get|post|put|proxy|info>\n", argv[0]);
printf("usage: %s <get|post|put|ping|proxy|info>\n", argv[0]);
return 1;
}

Expand Down
6 changes: 5 additions & 1 deletion sys/include/net/gcoap.h
Original file line number Diff line number Diff line change
Expand Up @@ -734,10 +734,14 @@ void gcoap_register_listener(gcoap_listener_t *listener);
/**
* @brief Initializes a CoAP request PDU on a buffer.
*
* If @p code is COAP_CODE_EMPTY, prepares a complete "CoAP ping" 4 byte empty
* message request, ready to send.
*
* @param[out] pdu Request metadata
* @param[out] buf Buffer containing the PDU
* @param[in] len Length of the buffer
* @param[in] code Request code, one of COAP_METHOD_XXX
* @param[in] code Request code, one of COAP_METHOD_XXX or COAP_CODE_EMPTY
* to ping
* @param[in] path Resource path, may be NULL
*
* @pre @p path must start with `/` if not NULL
Expand Down
63 changes: 43 additions & 20 deletions sys/net/application_layer/gcoap/gcoap.c
Original file line number Diff line number Diff line change
Expand Up @@ -150,16 +150,29 @@ static void _on_sock_evt(sock_udp_t *sock, sock_async_flags_t type, void *arg)
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 */
/* incoming request or empty */
case COAP_CLASS_REQ:
if (coap_get_type(&pdu) == COAP_TYPE_NON
if (coap_get_code_raw(&pdu) == COAP_CODE_EMPTY) {
/* ping request */
if (coap_get_type(&pdu) == COAP_TYPE_CON) {
coap_hdr_set_type(pdu.hdr, COAP_TYPE_RST);

ssize_t bytes = sock_udp_send(sock, _listen_buf,
sizeof(coap_hdr_t), &remote);
if (bytes <= 0) {
DEBUG("gcoap: ping response failed: %d\n", (int)bytes);
}
} else if (coap_get_type(&pdu) == COAP_TYPE_NON) {
DEBUG("gcoap: empty NON msg\n");
}
else {
goto empty_as_response;
}
}
/* normal request */
else 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);
Expand All @@ -176,6 +189,10 @@ static void _on_sock_evt(sock_udp_t *sock, sock_async_flags_t type, void *arg)
}
break;

empty_as_response:
DEBUG("gcoap: empty ack/reset not handled yet\n");
return;

/* incoming response */
case COAP_CLASS_SUCCESS:
case COAP_CLASS_CLIENT_FAILURE:
Expand Down Expand Up @@ -640,22 +657,28 @@ int gcoap_req_init(coap_pkt_t *pdu, uint8_t *buf, size_t len,
pdu->hdr = (coap_hdr_t *)buf;

/* generate token */
#if CONFIG_GCOAP_TOKENLEN
uint8_t token[CONFIG_GCOAP_TOKENLEN];
for (size_t i = 0; i < CONFIG_GCOAP_TOKENLEN; i += 4) {
uint32_t rand = random_uint32();
memcpy(&token[i],
&rand,
(CONFIG_GCOAP_TOKENLEN - i >= 4) ? 4 : CONFIG_GCOAP_TOKENLEN - i);
}
uint16_t msgid = (uint16_t)atomic_fetch_add(&_coap_state.next_message_id, 1);
ssize_t res = coap_build_hdr(pdu->hdr, COAP_TYPE_NON, &token[0],
CONFIG_GCOAP_TOKENLEN, code, msgid);
ssize_t res;
if (code) {
#if CONFIG_GCOAP_TOKENLEN
uint8_t token[CONFIG_GCOAP_TOKENLEN];
for (size_t i = 0; i < CONFIG_GCOAP_TOKENLEN; i += 4) {
uint32_t rand = random_uint32();
memcpy(&token[i],
&rand,
(CONFIG_GCOAP_TOKENLEN - i >= 4) ? 4 : CONFIG_GCOAP_TOKENLEN - i);
}
res = coap_build_hdr(pdu->hdr, COAP_TYPE_NON, &token[0],
CONFIG_GCOAP_TOKENLEN, code, msgid);
#else
uint16_t msgid = (uint16_t)atomic_fetch_add(&_coap_state.next_message_id, 1);
ssize_t res = coap_build_hdr(pdu->hdr, COAP_TYPE_NON, NULL,
CONFIG_GCOAP_TOKENLEN, code, msgid);
res = coap_build_hdr(pdu->hdr, COAP_TYPE_NON, NULL,
CONFIG_GCOAP_TOKENLEN, code, msgid);
#endif
}
else {
/* ping request */
res = coap_build_hdr(pdu->hdr, COAP_TYPE_CON, NULL, 0, code, msgid);
}

coap_pkt_init(pdu, buf, len - CONFIG_GCOAP_REQ_OPTIONS_BUF, res);
if (path != NULL) {
Expand Down
9 changes: 9 additions & 0 deletions sys/net/application_layer/nanocoap/nanocoap.c
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,15 @@ int coap_parse(coap_pkt_t *pkt, uint8_t *buf, size_t len)
pkt->payload = NULL;
pkt->payload_len = 0;

if (len < sizeof(coap_hdr_t)) {
DEBUG("msg too short\n");
return -EBADMSG;
}
else if ((coap_get_code_raw(pkt) == 0) && (len > sizeof(coap_hdr_t))) {
DEBUG("empty msg too long\n");
return -EBADMSG;
}

/* token value (tkl bytes) */
if (coap_get_token_len(pkt)) {
pkt->token = pkt_pos;
Expand Down
23 changes: 23 additions & 0 deletions tests/unittests/tests-gcoap/tests-gcoap.c
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,28 @@ static void test_gcoap__client_get_path_defer(void)
TEST_ASSERT_EQUAL_STRING(&path[0], &uri[0]);
}

/*
* Validate client CoAP ping empty message request.
*/
static void test_gcoap__client_ping(void)
{
uint8_t buf[CONFIG_GCOAP_PDU_BUF_SIZE];
coap_pkt_t pdu;
int res;

res = gcoap_req_init(&pdu, buf, CONFIG_GCOAP_PDU_BUF_SIZE, COAP_CODE_EMPTY,
NULL);

TEST_ASSERT_EQUAL_INT(0, res);
TEST_ASSERT_EQUAL_INT(COAP_CODE_EMPTY, coap_get_code(&pdu));
TEST_ASSERT_EQUAL_INT(COAP_TYPE_CON, coap_get_type(&pdu));
TEST_ASSERT_EQUAL_INT(0, coap_get_token_len(&pdu));

/* confirm length */
res = coap_opt_finish(&pdu, COAP_OPT_FINISH_NONE);
TEST_ASSERT_EQUAL_INT(4, res);
}

/*
* Helper for server_get tests below.
* Request from libcoap example for gcoap_cli /cli/stats resource
Expand Down Expand Up @@ -371,6 +393,7 @@ Test *tests_gcoap_tests(void)
new_TestFixture(test_gcoap__client_put_req),
new_TestFixture(test_gcoap__client_put_req_overfill),
new_TestFixture(test_gcoap__client_get_path_defer),
new_TestFixture(test_gcoap__client_ping),
new_TestFixture(test_gcoap__server_get_req),
new_TestFixture(test_gcoap__server_get_resp),
new_TestFixture(test_gcoap__server_con_req),
Expand Down
33 changes: 33 additions & 0 deletions tests/unittests/tests-nanocoap/tests-nanocoap.c
Original file line number Diff line number Diff line change
Expand Up @@ -713,6 +713,38 @@ static void test_nanocoap__options_get_opaque(void)
TEST_ASSERT_EQUAL_INT(-ENOENT, optlen);
}

/*
* Validates empty message parsing.
*/
static void test_nanocoap__empty(void)
{
/* first four bytes are valid empty msg; include 5th byte for test */
static uint8_t pkt_data[] = {
0x40, 0x00, 0xAB, 0xCD, 0x00
};

uint16_t msgid = 0xABCD;

coap_pkt_t pkt;
int res = coap_parse(&pkt, pkt_data, 4);

TEST_ASSERT_EQUAL_INT(0, res);
TEST_ASSERT_EQUAL_INT(0, coap_get_code_raw(&pkt));
TEST_ASSERT_EQUAL_INT(msgid, coap_get_id(&pkt));
TEST_ASSERT_EQUAL_INT(0, coap_get_token_len(&pkt));
TEST_ASSERT_EQUAL_INT(0, pkt.payload_len);

/* too short */
memset(&pkt, 0, sizeof(coap_pkt_t));
res = coap_parse(&pkt, pkt_data, 3);
TEST_ASSERT_EQUAL_INT(-EBADMSG, res);

/* too long */
memset(&pkt, 0, sizeof(coap_pkt_t));
res = coap_parse(&pkt, pkt_data, 5);
TEST_ASSERT_EQUAL_INT(-EBADMSG, res);
}

Test *tests_nanocoap_tests(void)
{
EMB_UNIT_TESTFIXTURES(fixtures) {
Expand All @@ -736,6 +768,7 @@ Test *tests_nanocoap_tests(void)
new_TestFixture(test_nanocoap__server_reply_simple_con),
new_TestFixture(test_nanocoap__server_option_count_overflow_check),
new_TestFixture(test_nanocoap__server_option_count_overflow),
new_TestFixture(test_nanocoap__empty),
};

EMB_UNIT_TESTCALLER(nanocoap_tests, NULL, NULL, fixtures);
Expand Down

0 comments on commit 46507ff

Please sign in to comment.