diff --git a/src/net.c b/src/net.c index a54939587b..d59dd82f44 100644 --- a/src/net.c +++ b/src/net.c @@ -1535,12 +1535,67 @@ handle_request(coap_context_t *context, coap_queue_t *node) { assert(response == NULL); } +static inline int +is_separate(const coap_queue_t *node) { + return node->retransmit_cnt > COAP_DEFAULT_MAX_RETRANSMIT; +} + +static int +coap_remove_separate_from_queue(coap_context_t *context, const coap_address_t *dst, + const unsigned char *token, size_t token_length, coap_queue_t **sent) { + coap_queue_t *p, *q; + if (!context->sendqueue) + return 0; + + if (coap_address_equals(dst, &context->sendqueue->remote) && + token_match(token, token_length, + context->sendqueue->pdu->hdr->token, + context->sendqueue->pdu->hdr->token_length) && + is_separate(context->sendqueue)) { + *sent = context->sendqueue; + context->sendqueue = context->sendqueue->next; + return 1; + } + + p = context->sendqueue; + q = p->next; + + /* when q is not NULL, it does not match (dst, token), so we can skip it */ + while (q) { + if (coap_address_equals(dst, &q->remote) && + token_match(token, token_length, + q->pdu->hdr->token, + q->pdu->hdr->token_length) && + is_separate(q)) { + p->next = q->next; + q->next = NULL; + *sent = q; + return 1; + } else { + p = q; + q = q->next; + } + } + return 0; +} + static inline void handle_response(coap_context_t *context, coap_queue_t *sent, coap_queue_t *rcvd) { coap_send_ack(context, &rcvd->local_if, &rcvd->remote, rcvd->pdu); - + + /* In case of separate response, the request cannot be matched with + * transaction id which is based on message id and remote address. + * Besides, excludes type Acknowledgement since separate response + * cannot be be of that type. + */ + if (sent == NULL && rcvd->pdu->type != COAP_MESSAGE_ACK) { + coap_remove_separate_from_queue(context, &rcvd->remote, + rcvd->pdu->hdr->token, + rcvd->pdu->hdr->token_length, &sent); + } + /* In a lossy context, the ACK of a separate response may have * been lost, so we need to stop retransmitting requests with the * same token. @@ -1580,8 +1635,15 @@ coap_dispatch(coap_context_t *context, coap_queue_t *rcvd) { /* find transaction in sendqueue to stop retransmission */ coap_remove_from_queue(&context->sendqueue, rcvd->id, &sent); - if (rcvd->pdu->hdr->code == 0) + if (rcvd->pdu->hdr->code == 0) { + if (sent != NULL) { + sent->retransmit_cnt = COAP_DEFAULT_MAX_RETRANSMIT + 1; + sent->t = sent->timeout << COAP_DEFAULT_MAX_RETRANSMIT; + coap_insert_node(&context->sendqueue, sent); + sent = NULL; + } goto cleanup; + } /* if sent code was >= 64 the message might have been a * notification. Then, we must flag the observer to be alive