diff --git a/include/coap3/coap_block_internal.h b/include/coap3/coap_block_internal.h index 9abe8155..b7ad0a55 100644 --- a/include/coap3/coap_block_internal.h +++ b/include/coap3/coap_block_internal.h @@ -191,6 +191,9 @@ int coap_handle_response_get_block(coap_context_t *context, void coap_block_delete_lg_xmit(coap_session_t *session, coap_lg_xmit_t *lg_xmit); +coap_tick_t coap_block_check_lg_xmit_timeouts(coap_session_t *session, + coap_tick_t now); + /** * The function that does all the work for the coap_add_data_large*() * functions. diff --git a/src/block.c b/src/block.c index e4a2152a..46689039 100644 --- a/src/block.c +++ b/src/block.c @@ -730,6 +730,31 @@ error: return 0; } +coap_tick_t +coap_block_check_lg_xmit_timeouts(coap_session_t *session, coap_tick_t now) { + coap_lg_xmit_t *p; + coap_lg_xmit_t *q; + coap_tick_t partial_timeout = 8 * COAP_TICKS_PER_SECOND; + coap_tick_t tim_rem = -1; + + LL_FOREACH_SAFE(session->lg_xmit, p, q) { + if (p->last_used == 0) { + continue; + } + if (p->last_used + partial_timeout <= now) { + /* Expire this entry */ + LL_DELETE(session->lg_xmit, p); + coap_block_delete_lg_xmit(session, p); + } + else { + /* Delay until the lg_xmit needs to expire */ + if (tim_rem > p->last_used + partial_timeout - now) + tim_rem = p->last_used + partial_timeout - now; + } + } + return tim_rem; +} + coap_tick_t coap_block_check_lg_crcv_timeouts(coap_session_t *session, coap_tick_t now) { coap_lg_crcv_t *p; @@ -940,7 +965,7 @@ add_block_send(uint32_t num, uint32_t *out_blocks, * If additional responses needed, then these are expicitly sent out and * 'response' is updated to be the last response to be sent. * - * This is set up using coap_add_data_response_large() + * This is set up using coap_add_data_large_response() * * Server is sending a large data response to GET / observe (BLOCK2) * @@ -1068,8 +1093,7 @@ coap_handle_request_send_block(coap_session_t *session, out_pdu = coap_pdu_duplicate(&p->pdu, session, pdu->token_length, pdu->token, &drop_options); if (!out_pdu) { - response->code = COAP_RESPONSE_CODE(500); - goto fail; + goto internal_issue; } } else { @@ -1101,6 +1125,10 @@ coap_handle_request_send_block(coap_session_t *session, buf)) { goto internal_issue; } + if (!(p->offset + chunk < p->length)) { + /* Last block - keep in cache for 4 * ACK_TIMOUT */ + coap_ticks(&p->last_used); + } if (p->b.b2.maxage_expire) { coap_tick_t now; coap_time_t rem; @@ -1137,7 +1165,11 @@ coap_handle_request_send_block(coap_session_t *session, } goto skip_app_handler; -fail: +internal_issue: + response->code = COAP_RESPONSE_CODE(500); + error_phrase = coap_response_phrase(response->code); + coap_add_data(response, strlen(error_phrase), + (const uint8_t *)error_phrase); /* Keep in cache for 4 * ACK_TIMOUT */ coap_ticks(&p->last_used); goto skip_app_handler; @@ -1146,13 +1178,6 @@ fail: skip_app_handler: return 1; - -internal_issue: - response->code = COAP_RESPONSE_CODE(500); - error_phrase = coap_response_phrase(response->code); - coap_add_data(response, strlen(error_phrase), - (const uint8_t *)error_phrase); - goto fail; } static int @@ -1436,7 +1461,7 @@ skip_app_handler: * * Client receives large data acknowledgement from server (BLOCK1) * - * This is set up using coap_add_data_request_large() + * This is set up using coap_add_data_large_request() * * Client is sending a large data request using GET etc. * diff --git a/src/coap_io.c b/src/coap_io.c index 2e5a602a..a1b2258a 100644 --- a/src/coap_io.c +++ b/src/coap_io.c @@ -1113,6 +1113,12 @@ coap_io_prepare_io(coap_context_t *ctx, if (timeout == 0 || s_timeout < timeout) timeout = s_timeout; } + /* Check if any server large sending have timed out */ + if (s->lg_xmit) { + s_timeout = coap_block_check_lg_xmit_timeouts(s, now); + if (timeout == 0 || s_timeout < timeout) + timeout = s_timeout; + } #ifndef COAP_EPOLL_SUPPORT if (s->sock.flags & (COAP_SOCKET_WANT_READ | COAP_SOCKET_WANT_WRITE)) { if (*num_sockets < max_sockets)