Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion include/coap3/coap_net.h
Original file line number Diff line number Diff line change
Expand Up @@ -341,7 +341,17 @@ void coap_context_rate_limit_ppm(coap_context_t *context,
* @param max_body_size The maximum supported body size. 0 indicates unlimited.
*/
void coap_context_set_max_body_size(coap_context_t *context,
uint32_t max_body_size);
size_t max_body_size);

/**
* Set the maximum supported total pending bodies that are being received.
*
* @param context The coap_context_t object.
* @param max_bodies_ram The maximum supported ram usage by server's pending
* receive queues. 0 (the default) indicates unlimited.
*/
void coap_context_set_max_bodies_ram(coap_context_t *context,
size_t max_bodies_ram);

/**
* Set the maximum token size (RFC8974).
Expand Down
6 changes: 5 additions & 1 deletion include/coap3/coap_net_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,10 @@ struct coap_context_t {
uint8_t shutdown_no_send_observe; /**< Do not send out unsolicited observe when
coap_free_context() is called. Otherwise
5.03 will get sent */
uint32_t lg_srcv_cnt; /**< Number of active lg_srcv */
size_t max_bodies_ram; /**< Max RAM usable for concurrent lg_srcv
0 = unlimited */
size_t cur_bodies_ram; /**< Current RAM in use for concurrent lg_srcv */
#endif /* COAP_SERVER_SUPPORT */
#if COAP_PROXY_SUPPORT
coap_proxy_entry_t *proxy_list; /**< Set of active proxy sessions */
Expand All @@ -235,7 +239,7 @@ struct coap_context_t {
coap_resource_dynamic_create_t dyn_create_handler; /**< Dynamic resource create handler */
uint32_t dynamic_cur; /**< Current number of dynamic resources */
uint32_t dynamic_max; /**< Max number of dynamic resources or 0 is unlimited */
uint32_t max_body_size; /**< Max supported body size or 0 is unlimited */
size_t max_body_size; /**< Max supported body size or 0 is unlimited */
#if COAP_THREAD_SAFE
pthread_t *thread_id; /**< Set of current additional threads */
uint32_t thread_id_count; /**< Number of additional threads */
Expand Down
1 change: 1 addition & 0 deletions libcoap-3.map
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ global:
coap_context_set_csm_timeout_ms;
coap_context_set_keepalive;
coap_context_set_max_block_size;
coap_context_set_max_bodies_ram;
coap_context_set_max_body_size;
coap_context_set_max_handshake_sessions;
coap_context_set_max_idle_sessions;
Expand Down
1 change: 1 addition & 0 deletions libcoap-3.sym
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ coap_context_set_csm_timeout
coap_context_set_csm_timeout_ms
coap_context_set_keepalive
coap_context_set_max_block_size
coap_context_set_max_bodies_ram
coap_context_set_max_body_size
coap_context_set_max_handshake_sessions
coap_context_set_max_idle_sessions
Expand Down
1 change: 1 addition & 0 deletions man/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ install-man: install-man3 install-man5 install-man7
@echo ".so man3/coap_address.3" > coap_is_mcast.3
@echo ".so man3/coap_address.3" > coap_is_af_unix.3
@echo ".so man3/coap_endpoint_server.3" > coap_endpoint_join_mcast_group_intf.3
@echo ".so man3/coap_block.3" > coap_block_build_body.3
@echo ".so man3/coap_block.3" > coap_q_block_is_supported.3
@echo ".so man3/coap_block.3" > coap_register_block_data_handler.3
@echo ".so man3/coap_cache.3" > coap_cache_get_pdu.3
Expand Down
39 changes: 33 additions & 6 deletions man/coap_block.txt.in
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ coap_block,
coap_context_set_block_mode,
coap_context_set_max_block_size,
coap_context_set_max_body_size,
coap_context_set_max_bodies_ram,
coap_add_data_large_request,
coap_add_data_large_request_app,
coap_add_data_large_response,
Expand All @@ -34,7 +35,10 @@ uint32_t _block_mode_);*
size_t _max_block_size_);*

*void coap_context_set_max_body_size(coap_context_t *_context_,
uint32_t _max_body_size_);*
size_t _max_body_size_);*

*void coap_context_set_max_bodies_ram(coap_context_t *_context_,
size_t _max_bodies_ram_);*

*int coap_add_data_large_request(coap_session_t *_session_,
coap_pdu_t *_pdu_, size_t _length_, const uint8_t *_data_,
Expand Down Expand Up @@ -284,11 +288,34 @@ Block2 options are used. This must be set before a server session is created.
*Function: coap_context_set_max_body_size()*

The *coap_context_set_max_body_size*() function is used to set the
_max_body_size_ in the _context_ that a server or client supports when the Block1 or
Block2 options are used. This must be set before a server session is created.
_max_body_size_ specifies the maximum size that the peer can handle after
re-assembling all the individual blocks. If set to 0 (the default),
_max_body_size_ is treated as unlimited.
_max_body_size_ in the _context_ that a server or client supports when the (Q-)Block1
or (Q-)Block2 options are used and COAP_BLOCK_SINGLE_BODY is set. This should be called
before a server session is created. _max_body_size_ specifies the maximum size that
the peer can handle after re-assembling all the individual blocks within a
transferred body. If set to 0 (the default), _max_body_size_ is treated as unlimited.

*NOTE:* If COAP_BLOCK_SINGLE_BODY is not set, then it is up to the application to respond
with a 4.13 code (server) or RST (client) should a limit be hit as libcoap is not
tracking the size.

*Function: coap_context_set_max_bodies_ram()*

The *coap_context_set_max_bodies_ram*() function is used to set the
_max_bodies_ram_ in the _context_ that a server supports across all the pending
body transfers when the (Q-)Block1 option is used and COAP_BLOCK_SINGLE_BODY is set.
This should be called before a server session is created. _max_bodies_ram_ specifies
the maximum size that the server can handle after re-assembling all the individual
blocks across all the sessions. If set to 0 (the default), _max_bodies_ram_ is
treated as unlimited.

*NOTE:* *coap_context_set_max_body_size*() sets the individual body maximum,
*coap_context_set_max_bodies_ram*() sets the sum of the bodies maximum.
Both can be used. If *coap_context_set_max_body_size*() is not used, then
_max_body_size_ is assumed to have the value of _max_bodies_ram_.

*NOTE:* If COAP_BLOCK_SINGLE_BODY is not set, then it is up to the application to
respond with a 5.03 code should a limit be hit as libcoap is not tracking the
pending bodies summation.

*Function: coap_add_data_large_request()*

Expand Down
78 changes: 56 additions & 22 deletions src/coap_block.c
Original file line number Diff line number Diff line change
Expand Up @@ -2095,6 +2095,17 @@ coap_block_check_lg_srcv_timeouts(coap_session_t *session, coap_tick_t now,
#endif /* COAP_Q_BLOCK_SUPPORT */
partial_timeout = COAP_MAX_TRANSMIT_WAIT_TICKS(session);

if (session->context->lg_srcv_cnt > 5) {
/* In case someone is DOSing us.
* DEFAULT_NON_PARTIAL_TIMEOUT is 247 seconds.
* MAX_TRANSIT_WAIT is 93 seconds.
*/
partial_timeout /= (session->context->lg_srcv_cnt - 5);
if (partial_timeout < 10 * COAP_TICKS_PER_SECOND) {
/* Do not shrink it too much */
partial_timeout = 10 * COAP_TICKS_PER_SECOND;
}
}
LL_FOREACH_SAFE(session->lg_srcv, lg_srcv, q) {
if (lg_srcv->dont_timeout) {
/* Not safe to timeout at present */
Expand Down Expand Up @@ -2832,7 +2843,7 @@ coap_block_delete_lg_crcv(coap_session_t *session,
return;
}

coap_free_type(COAP_STRING, lg_crcv->body_data);
coap_delete_binary(lg_crcv->body_data);
if (lg_crcv->obs_data) {
coap_block_release_lg_xmit_data(session, lg_crcv->obs_data);
lg_crcv->obs_data = NULL;
Expand All @@ -2854,9 +2865,6 @@ coap_block_delete_lg_crcv(coap_session_t *session,
void
coap_block_delete_lg_srcv(coap_session_t *session,
coap_lg_srcv_t *lg_srcv) {
#if (COAP_MAX_LOGGING_LEVEL < _COAP_LOG_DEBUG)
(void)session;
#endif
if (lg_srcv == NULL)
return;

Expand All @@ -2867,10 +2875,13 @@ coap_block_delete_lg_srcv(coap_session_t *session,

coap_delete_cache_key(lg_srcv->cache_key);
coap_delete_bin_const(lg_srcv->last_token);
coap_free_type(COAP_STRING, lg_srcv->body_data);
if (lg_srcv->body_data)
session->context->cur_bodies_ram -= lg_srcv->body_data->length;
coap_delete_binary(lg_srcv->body_data);
coap_log_debug("** %s: lg_srcv %p released\n",
coap_session_str(session), (void *)lg_srcv);
coap_free_type(COAP_LG_SRCV, lg_srcv);
session->context->lg_srcv_cnt--;
}
#endif /* COAP_SERVER_SUPPORT */

Expand Down Expand Up @@ -3467,15 +3478,15 @@ coap_handle_request_put_block(coap_context_t *context,
(block_option == COAP_OPTION_BLOCK1 && block.num == 0 && block.m == 0)) {
/* Not blocked, or a single block */
if (context->max_body_size && total > context->max_body_size) {
uint8_t buf[4];
uint8_t buf[8];

coap_update_option(response,
COAP_OPTION_SIZE1,
coap_encode_var_safe((uint8_t *)buf, sizeof(buf),
context->max_body_size),
coap_encode_var_safe8((uint8_t *)buf, sizeof(buf),
context->max_body_size),
(uint8_t *)buf);
response->code = COAP_RESPONSE_CODE(413);
coap_log_warn("Unable to handle data size %" PRIuS " (max %" PRIu32 ")\n", total,
coap_log_warn("Unable to handle data size %" PRIuS " (max %" PRIuS ")\n", total,
context->max_body_size);
goto skip_app_handler;
}
Expand Down Expand Up @@ -3540,20 +3551,20 @@ coap_handle_request_put_block(coap_context_t *context,
(total > max_body)) {
/* Suggested body size larger than allowed */
char buf[32];
uint32_t max_body_size = context->max_body_size;
size_t max_body_size = context->max_body_size;

if (max_body_size == 0 || max_body < max_body_size) {
max_body_size = max_body;
}
coap_update_option(response,
COAP_OPTION_SIZE1,
coap_encode_var_safe((uint8_t *)buf, sizeof(buf),
max_body_size),
coap_encode_var_safe8((uint8_t *)buf, sizeof(buf),
max_body_size),
(uint8_t *)buf);
snprintf(buf, sizeof(buf), "Max body size %" PRIu32, max_body_size);
snprintf(buf, sizeof(buf), "Max body size %" PRIuS, max_body_size);
coap_add_data(response, strlen(buf), (uint8_t *)buf);
response->code = COAP_RESPONSE_CODE(413);
coap_log_warn("Unable to handle body size %" PRIuS " (max %" PRIu32 ")\n", total, max_body_size);
coap_log_warn("Unable to handle body size %" PRIuS " (max %" PRIuS ")\n", total, max_body_size);
goto skip_app_handler;
}
}
Expand Down Expand Up @@ -3634,10 +3645,12 @@ coap_handle_request_put_block(coap_context_t *context,
}
coap_log_debug("** %s: lg_srcv %p initialized\n",
coap_session_str(session), (void *)lg_srcv);
session->context->lg_srcv_cnt++;
memset(lg_srcv, 0, sizeof(coap_lg_srcv_t));
#if COAP_OSCORE_SUPPORT && COAP_SERVER_SUPPORT
lg_srcv->recipient_ctx = session->recipient_ctx;
#endif /* COAP_OSCORE_SUPPORT && COAP_SERVER_SUPPORT */
coap_ticks(&lg_srcv->last_used);
lg_srcv->resource = resource;
lg_srcv->cache_key = cache_key_l;
cache_key_l = NULL;
Expand All @@ -3661,7 +3674,6 @@ coap_handle_request_put_block(coap_context_t *context,
memcpy(lg_srcv->rtag, coap_opt_value(rtag_opt), lg_srcv->rtag_length);
lg_srcv->rtag_set = 1;
}
lg_srcv->body_data = NULL;
#if COAP_Q_BLOCK_SUPPORT
lg_srcv->r_m_payload_set = -1;
#endif /* COAP_Q_BLOCK_SUPPORT */
Expand Down Expand Up @@ -3703,6 +3715,24 @@ coap_handle_request_put_block(coap_context_t *context,

lg_srcv->last_type = pdu->type;

if (context->max_bodies_ram) {
ssize_t increase = total - (lg_srcv->body_data ? lg_srcv->body_data->length : 0);

if (increase > 0 && context->cur_bodies_ram + increase > context->max_bodies_ram) {
uint8_t buf[4];

coap_update_option(response, COAP_OPTION_MAXAGE,
coap_encode_var_safe(buf,
sizeof(buf),
5),
buf);
coap_add_data(response, sizeof("Memory limit hit")-1,
(const uint8_t *)"Memory limit hit");
response->code = COAP_RESPONSE_CODE(503);
goto skip_app_handler;
}
}

update_data = 0;
saved_num = block.num;
saved_offset = offset;
Expand Down Expand Up @@ -3763,6 +3793,8 @@ coap_handle_request_put_block(coap_context_t *context,
((session->block_mode & COAP_SINGLE_BLOCK_OR_Q) || block.bert) && \
(resource->flags & COAP_RESOURCE_USE_BLOCK_DATA_HANDLER))

if (lg_srcv->body_data)
session->context->cur_bodies_ram -= lg_srcv->body_data->length;
if (USE_BLOCK_DATA_HANDLER) {
coap_response_t resp;

Expand All @@ -3785,6 +3817,8 @@ coap_handle_request_put_block(coap_context_t *context,
goto skip_app_handler;
}
}
if (lg_srcv->body_data)
context->cur_bodies_ram += lg_srcv->body_data->length;
} else {
#if COAP_Q_BLOCK_SUPPORT
if (block_option == COAP_OPTION_Q_BLOCK1) {
Expand Down Expand Up @@ -4499,7 +4533,7 @@ coap_block_build_body_lkd(coap_binary_t *body_data, size_t length,
return NULL;

/* Check no overflow (including a 8 byte small headroom) */
if (SIZE_MAX - length < 8 || offset > SIZE_MAX - length - 8) {
if (SIZE_MAX - 8 < length || offset > SIZE_MAX - length - 8) {
coap_delete_binary(body_data);
return NULL;
}
Expand Down Expand Up @@ -4656,7 +4690,7 @@ coap_handle_response_get_block(coap_context_t *context,
#endif /* COAP_Q_BLOCK_SUPPORT */
lg_crcv->initial = 0;
if (lg_crcv->body_data) {
coap_free_type(COAP_STRING, lg_crcv->body_data);
coap_delete_binary(lg_crcv->body_data);
lg_crcv->body_data = NULL;
}
if (etag_opt) {
Expand Down Expand Up @@ -4693,12 +4727,12 @@ coap_handle_response_get_block(coap_context_t *context,
max_body = MAX_BLK_LEN;
if ((context->max_body_size && size2 > context->max_body_size) ||
(size2 > max_body)) {
uint32_t max_body_size = context->max_body_size;
size_t max_body_size = context->max_body_size;

if (max_body_size == 0 || max_body < max_body_size) {
max_body_size = max_body;
}
coap_log_warn("Unable to handle body size %" PRIuS " (max %" PRIu32 ")\n", size2, max_body_size);
coap_log_warn("Unable to handle body size %" PRIuS " (max %" PRIuS ")\n", size2, max_body_size);
/* Try to hint to the server there is an issue */
coap_send_rst_lkd(session, rcvd);
coap_handle_event_lkd(session->context, COAP_EVENT_BLOCK_ISSUE, session);
Expand Down Expand Up @@ -4726,7 +4760,7 @@ coap_handle_response_get_block(coap_context_t *context,
coap_handle_event_lkd(context, COAP_EVENT_PARTIAL_BLOCK, session);

lg_crcv->initial = 1;
coap_free_type(COAP_STRING, lg_crcv->body_data);
coap_delete_binary(lg_crcv->body_data);
lg_crcv->body_data = NULL;

coap_session_new_token(session, &len, buf);
Expand Down Expand Up @@ -5017,7 +5051,7 @@ coap_handle_response_get_block(coap_context_t *context,
COAP_OPTION_OBSERVE,
&opt_iter);
if (context->max_body_size && length > context->max_body_size) {
coap_log_warn("Unable to handle body size %" PRIuS " (max %" PRIu32 ")\n", length,
coap_log_warn("Unable to handle body size %" PRIuS " (max %" PRIuS ")\n", length,
context->max_body_size);
/* Try to hint to the server there is an issue */
coap_send_rst_lkd(session, rcvd);
Expand Down Expand Up @@ -5175,7 +5209,7 @@ coap_handle_response_get_block(coap_context_t *context,
}
coap_get_data(rcvd, &length, &data);
if (context->max_body_size && length > context->max_body_size) {
coap_log_warn("Unable to handle body size %" PRIuS " (max %" PRIu32 ")\n", length,
coap_log_warn("Unable to handle body size %" PRIuS " (max %" PRIuS ")\n", length,
context->max_body_size);
/* Try to hint to the server there is an issue */
coap_send_rst_lkd(session, rcvd);
Expand Down
Loading
Loading