Skip to content

Commit

Permalink
fixup! gcoap: add nanocoap_cache support for clients
Browse files Browse the repository at this point in the history
  • Loading branch information
miri64 committed Apr 1, 2022
1 parent 11631a6 commit a1f7acb
Showing 1 changed file with 97 additions and 58 deletions.
155 changes: 97 additions & 58 deletions sys/net/application_layer/gcoap/gcoap.c
Original file line number Diff line number Diff line change
Expand Up @@ -449,6 +449,7 @@ static void _process_coap_pdu(gcoap_socket_t *sock, sock_udp_ep_t *remote,
memo->state = GCOAP_MEMO_ERR;
}
}
/* TODO: resend request if VALID but no cache entry? */
else if ((pdu.hdr->code != COAP_CODE_VALID)) {
_cache_process(memo, &pdu);
}
Expand Down Expand Up @@ -1228,17 +1229,20 @@ static void _receive_from_cache_cb(void *ctx)
static void _update_memo_cache_key(gcoap_request_memo_t *memo, uint8_t *cache_key)
{
#if IS_USED(MODULE_NANOCOAP_CACHE)
/* memo->cache_key is guarded by MODULE_NANOCOAP_CACHE, so preprocessor magic is needed */
memcpy(memo->cache_key, cache_key, CONFIG_NANOCOAP_CACHE_KEY_LENGTH);
if (memo) {
/* memo->cache_key is guarded by MODULE_NANOCOAP_CACHE, so preprocessor
* magic is needed */
memcpy(memo->cache_key, cache_key, CONFIG_NANOCOAP_CACHE_KEY_LENGTH);
}
#else
(void)memo;
(void)cache_key;
#endif
}

static bool _cache_lookup_and_post(gcoap_request_memo_t *memo,
coap_pkt_t *pdu,
nanocoap_cache_entry_t **ce)
static bool _cache_lookup(gcoap_request_memo_t *memo,
coap_pkt_t *pdu,
nanocoap_cache_entry_t **ce)
{
if (IS_USED(MODULE_NANOCOAP_CACHE)) {
uint8_t cache_key[SHA256_DIGEST_LENGTH];
Expand All @@ -1252,16 +1256,74 @@ static bool _cache_lookup_and_post(gcoap_request_memo_t *memo,
if (*ce &&
((*ce)->request_method == coap_get_code(pdu)) &&
((*ce)->max_age > now)) {
/* use response from cache */
event_callback_init(&_receive_from_cache, _receive_from_cache_cb, memo);
event_post(&_queue, &_receive_from_cache.super);
return true;
}
}

return false;
}

static ssize_t _cache_check(const uint8_t *buf, size_t len,
gcoap_request_memo_t *memo,
ssize_t *bytes_from_cache)
{
if (!IS_USED(MODULE_NANOCOAP_CACHE)) {
return len;
}
coap_pkt_t pdu;
nanocoap_cache_entry_t *ce = NULL;
bool cache_hit;
/* XXX cast to const might cause problems here :-/ */
ssize_t res = coap_parse(&pdu, (uint8_t *)buf, len);

if (res < 0) {
DEBUG("gcoap: parse failure for cache lookup: %d\n", (int)res);
return -EINVAL;
}

cache_hit = _cache_lookup(memo, &pdu, &ce);

if (cache_hit) {
/* Valid cache entry found and response event was issued. Don't send request. */
*bytes_from_cache = len;
}
else if (ce != NULL) {
/* Cache entry was found, but it is stale. Try to validate */
uint8_t *etag;
/* Searching for more ETags might become necessary in the future */
ssize_t etag_len = coap_opt_get_opaque(&ce->response_pkt, COAP_OPT_ETAG, &etag);

/* ETag found, but don't act on illegal ETag size */
if ((etag_len > 0) && (etag_len <= COAP_ETAG_LENGTH_MAX)) {
uint8_t *ptr;

coap_opt_get_opaque(&pdu, COAP_OPT_ETAG, &ptr);
memcpy(ptr, etag, etag_len);
if (etag_len < COAP_ETAG_LENGTH_MAX) {
/* now we need the start of the option (not its value) so dig once more */
uint8_t *start = coap_find_option(&pdu, COAP_OPT_ETAG);
/* option length must always be <= COAP_ETAG_LENGTH_MAX = 8 < 12, so the length
* is encoded in the first byte, see also RFC 7252, section 3.1 */
*start &= 0x0f;
/* first if around here should make sure we are <= 8 < 0xf, so we don't need to
* bitmask etag_len */
*start |= (uint8_t)etag_len;
/* remove padding */
size_t rem_len = (len - (ptr + COAP_ETAG_LENGTH_MAX - buf));
memmove(ptr + etag_len, ptr + COAP_ETAG_LENGTH_MAX, rem_len);
len -= (COAP_ETAG_LENGTH_MAX - etag_len);
}
}
else {
len = coap_opt_remove(&pdu, COAP_OPT_ETAG);
}
}
else {
len = coap_opt_remove(&pdu, COAP_OPT_ETAG);
}
return len;
}

/*
* gcoap interface functions
*/
Expand Down Expand Up @@ -1362,6 +1424,7 @@ ssize_t gcoap_req_send_tl(const uint8_t *buf, size_t len,
{
gcoap_socket_t socket = { 0 };
gcoap_request_memo_t *memo = NULL;
ssize_t bytes_from_cache = 0;
unsigned msg_type = (*buf & 0x30) >> 4;
uint32_t timeout = 0;
ssize_t res = 0;
Expand Down Expand Up @@ -1395,6 +1458,15 @@ ssize_t gcoap_req_send_tl(const uint8_t *buf, size_t len,
memcpy(&memo->remote_ep, remote, sizeof(sock_udp_ep_t));
memo->socket = socket;

if (IS_USED(MODULE_NANOCOAP_CACHE)) {
ssize_t res = _cache_check(buf, len, memo, &bytes_from_cache);

if (res < 0) {
return res;
}
len = res;
}

switch (msg_type) {
case COAP_TYPE_CON:
/* copy buf to resend_bufs record */
Expand Down Expand Up @@ -1437,61 +1509,28 @@ ssize_t gcoap_req_send_tl(const uint8_t *buf, size_t len,
return 0;
}
}

if (IS_USED(MODULE_NANOCOAP_CACHE)) {
coap_pkt_t pdu;
nanocoap_cache_entry_t *ce = NULL;
bool cache_hit;
/* XXX cast to const might cause problems here :-/ */
ssize_t res = coap_parse(&pdu, (uint8_t *)buf, len);
/* check cache without memo */
else if (IS_USED(MODULE_NANOCOAP_CACHE)) {
ssize_t res = _cache_check(buf, len, NULL, &bytes_from_cache);

if (res < 0) {
DEBUG("gcoap: parse failure for cache lookup: %d\n", (int)res);
return -EINVAL;
}

/* This cast might be dangerous! */
cache_hit = _cache_lookup_and_post(memo, &pdu, &ce);

if (cache_hit) {
/* Valid cache entry found and response event was issued. Don't send request. */
return len;
}
else if (ce != NULL) {
/* Cache entry was found, but it is stale. Try to validate */
uint8_t *etag;
/* Searching for more ETags might become necessary in the future */
ssize_t etag_len = coap_opt_get_opaque(&ce->response_pkt, COAP_OPT_ETAG, &etag);

/* ETag found, but don't act on illegal ETag size */
if ((etag_len > 0) && (etag_len <= COAP_ETAG_LENGTH_MAX)) {
uint8_t *ptr;

coap_opt_get_opaque(&pdu, COAP_OPT_ETAG, &ptr);
memcpy(ptr, etag, etag_len);
if (etag_len < COAP_ETAG_LENGTH_MAX) {
/* now we need the start of the option (not its value) so dig once more */
uint8_t *start = coap_find_option(&pdu, COAP_OPT_ETAG);
/* option length must always be <= COAP_ETAG_LENGTH_MAX = 8 < 12, so the length
* is encoded in the first byte, see also RFC 7252, section 3.1 */
*start &= 0x0f;
/* first if around here should make sure we are <= 8 < 0xf, so we don't need to
* bitmask etag_len */
*start |= (uint8_t)etag_len;
/* remove padding */
size_t rem_len = (len - (ptr + COAP_ETAG_LENGTH_MAX - buf));
memmove(ptr + etag_len, ptr + COAP_ETAG_LENGTH_MAX, rem_len);
len -= (COAP_ETAG_LENGTH_MAX - etag_len);
}
}
else {
len = coap_opt_remove(&pdu, COAP_OPT_ETAG);
}
return res;
}
else {
len = coap_opt_remove(&pdu, COAP_OPT_ETAG);
len = res;
}

if (bytes_from_cache > 0) {
/* post to receive cache entry */
if (memo != NULL) {
/* use response from cache */
event_callback_init(&_receive_from_cache,
_receive_from_cache_cb,
memo);
event_post(&_queue, &_receive_from_cache.super);
}
return bytes_from_cache;
}

_tl_init_coap_socket(&socket, tl_type);
if (IS_USED(MODULE_GCOAP_DTLS) && socket.type == GCOAP_SOCKET_TYPE_DTLS) {
res = _tl_authenticate(&socket, remote, CONFIG_GCOAP_DTLS_HANDSHAKE_TIMEOUT_MSEC);
Expand Down

0 comments on commit a1f7acb

Please sign in to comment.