Skip to content

Commit

Permalink
block: Handle separate responses that then are followed with Block2
Browse files Browse the repository at this point in the history
Set up lg_crcv if separate ACK response received for a coap_send() CON
request to be able to handle Block2 responses.

Handle Block1 request getting back a Block2 request that has an initial
separate response once the Block1 has completed by adjusting the stateless
token counter.

Separate response is typical for proxy support (OSCORE previously handled)..
  • Loading branch information
mrdeep1 committed Jun 14, 2024
1 parent ea3d1ac commit 0fbe59f
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 13 deletions.
4 changes: 4 additions & 0 deletions include/coap3/coap_block_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@
* @{
*/

#define STATE_TOKEN_BASE(t) ((t) & 0xffffffffffffULL)
#define STATE_TOKEN_RETRY(t) ((uint64_t)(t) >> 48)
#define STATE_TOKEN_FULL(t,r) (STATE_TOKEN_BASE(t) + ((uint64_t)(r) << 48))

#if COAP_Q_BLOCK_SUPPORT
#define COAP_BLOCK_SET_MASK (COAP_BLOCK_USE_LIBCOAP | \
COAP_BLOCK_SINGLE_BODY | \
Expand Down
9 changes: 2 additions & 7 deletions src/coap_block.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,6 @@
#define min(a,b) ((a) < (b) ? (a) : (b))
#endif

#define STATE_TOKEN_BASE(t) ((t) & 0xffffffffffffULL)
#define STATE_TOKEN_RETRY(t) ((uint64_t)(t) >> 48)
#define STATE_TOKEN_FULL(t,r) (STATE_TOKEN_BASE(t) + ((uint64_t)(r) << 48))

#if COAP_Q_BLOCK_SUPPORT
int
coap_q_block_is_supported(void) {
Expand Down Expand Up @@ -3317,9 +3313,7 @@ coap_handle_response_send_block(coap_session_t *session, coap_pdu_t *sent,
LL_FOREACH_SAFE(session->lg_xmit, p, q) {
if (!COAP_PDU_IS_REQUEST(&p->pdu) ||
(token_match != STATE_TOKEN_BASE(p->b.b1.state_token) &&
token_match !=
STATE_TOKEN_BASE(coap_decode_var_bytes8(p->b.b1.app_token->s,
p->b.b1.app_token->length)))) {
!coap_binary_equal(&rcvd->actual_token, p->b.b1.app_token))) {
/* try out the next one */
continue;
}
Expand Down Expand Up @@ -3578,6 +3572,7 @@ coap_handle_response_send_block(coap_session_t *session, coap_pdu_t *sent,
STATE_TOKEN_BASE(lg_crcv->state_token)) {
/* In case of observe */
lg_crcv->state_token = p->b.b1.state_token;
lg_crcv->retry_counter = p->b.b1.count;
break;
}
}
Expand Down
78 changes: 72 additions & 6 deletions src/coap_net.c
Original file line number Diff line number Diff line change
Expand Up @@ -1241,6 +1241,34 @@ coap_check_code_class(coap_session_t *session, coap_pdu_t *pdu) {
return 1;
}

#if COAP_CLIENT_SUPPORT
/*
* If type is CON and protocol is not reliable, there is no need to set up
* lg_crcv if it can be built up based on sent PDU if there is a
* (Q-)Block2 in the response. However, still need it for Observe, Oscore and
* (Q-)Block1.
*/
static int
coap_check_send_need_lg_crcv(coap_session_t *session, coap_pdu_t *pdu) {
coap_opt_iterator_t opt_iter;

if (
#if COAP_OSCORE_SUPPORT
session->oscore_encryption ||
#endif /* COAP_OSCORE_SUPPORT */
((pdu->type == COAP_MESSAGE_NON || COAP_PROTO_RELIABLE(session->proto)) &&
COAP_PDU_IS_REQUEST(pdu) && pdu->code != COAP_REQUEST_CODE_DELETE) ||
coap_check_option(pdu, COAP_OPTION_OBSERVE, &opt_iter) ||
#if COAP_Q_BLOCK_SUPPORT
coap_check_option(pdu, COAP_OPTION_Q_BLOCK1, &opt_iter) ||
#endif /* COAP_Q_BLOCK_SUPPORT */
coap_check_option(pdu, COAP_OPTION_BLOCK1, &opt_iter)) {
return 1;
}
return 0;
}
#endif /* COAP_CLIENT_SUPPORT */

COAP_API coap_mid_t
coap_send(coap_session_t *session, coap_pdu_t *pdu) {
coap_mid_t mid;
Expand Down Expand Up @@ -1510,12 +1538,7 @@ coap_send_lkd(coap_session_t *session, coap_pdu_t *pdu) {
* (Q-)Block2 in the response. However, still need it for Observe, Oscore and
* (Q-)Block1.
*/
if (observe_action != -1 || have_block1 ||
#if COAP_OSCORE_SUPPORT
session->oscore_encryption ||
#endif /* COAP_OSCORE_SUPPORT */
((pdu->type == COAP_MESSAGE_NON || COAP_PROTO_RELIABLE(session->proto)) &&
COAP_PDU_IS_REQUEST(pdu) && pdu->code != COAP_REQUEST_CODE_DELETE)) {
if (coap_check_send_need_lg_crcv(session, pdu)) {
coap_lg_xmit_t *lg_xmit = NULL;

if (!session->lg_xmit && have_block1) {
Expand Down Expand Up @@ -3968,6 +3991,49 @@ coap_dispatch(coap_context_t *context, coap_session_t *session,
}
}
#endif /* COAP_Q_BLOCK_SUPPORT */
#if COAP_CLIENT_SUPPORT
/*
* In coap_send(), lg_crcv was not set up if type is CON and protocol is not
* reliable to save overhead as this can be set up on detection of a (Q)-Block2
* response if the response was piggy-backed. Here, a separate response
* detected and so the lg_crcv needs to be set up before the sent PDU
* information is lost.
*
* lg_crcv was not set up if not a CoAP request or if DELETE.
*
* lg_crcv was always set up in coap_send() if Observe, Oscore and (Q)-Block1
* options.
*/
if (sent &&
!coap_check_send_need_lg_crcv(session, pdu)) {
/*
* lg_crcv was not set up in coap_send(). It coud have been set up
* the first separate response.
* See if there already is a lg_crcv set up.
*/
coap_lg_crcv_t *lg_crcv;
uint64_t token_match =
STATE_TOKEN_BASE(coap_decode_var_bytes8(sent->pdu->actual_token.s,
sent->pdu->actual_token.length));

LL_FOREACH(session->lg_crcv, lg_crcv) {
if (token_match == STATE_TOKEN_BASE(lg_crcv->state_token) ||
coap_binary_equal(&sent->pdu->actual_token, lg_crcv->app_token)) {
break;
}
}
if (!lg_crcv) {
/*
* Need to set up a lg_crcv as it was not set up in coap_send()
* to save time, but server has not sent back a piggy-back response.
*/
lg_crcv = coap_block_new_lg_crcv(session, sent->pdu, NULL);
if (lg_crcv) {
LL_PREPEND(session->lg_crcv, lg_crcv);
}
}
}
#endif /* COAP_CLIENT_SUPPORT */
/* an empty ACK needs no further handling */
goto cleanup;
} else if (COAP_PDU_IS_REQUEST(pdu)) {
Expand Down

0 comments on commit 0fbe59f

Please sign in to comment.