Reduce value of partial timeout if there are a lot of outstanding
large block receipts that are not active.
Add function coap_context_set_max_bodies_ram() to define an upper memory
limit usage across all active body receipts.
Examples are only built when the library mode they depend on is enabled,
otherwise their link step fails with undefined references. The tiny example
is gated on client mode only.
Signed-off-by: warter666 <271496918+warter666@users.noreply.github.com>
`coap_proxy_get_add_list_entry(incoming, ongoing, ...)` dereferences `ongoing->context` when `incoming == NULL`. Current in-tree callers always pass exactly one non-NULL session, but the function is a public-ish internal helper and a future caller passing both NULL would dereference NULL immediately. cppcheck flags exactly this (`nullPointer` on `ongoing`).
This adds an explicit early `return NULL` when both arguments are NULL - defensive only, no behavior change for existing callers.
Signed-off-by: warter666 <121139223+Warterkk@users.noreply.github.com>
Three format-string/argument type mismatches in `src/coap_debug.c`, all reported by `-Wall -Wextra` (fatal under -Werror):
1. `msg_code_string()`: `"%u.%02u"` receives `int` expressions (uint16_t promotes to int) - cast both to `unsigned`.
2. `print_content_format()`: `"%d"` receives `unsigned int format_type` - use `%u`.
3. block-size printing: `"%u"` receives the `int` expression `1 << (...)` - make the shift and cast unsigned.
No behavior change on any realistic input; only the int-vs-unsigned variance is fixed.
Signed-off-by: warter666 <121139223+Warterkk@users.noreply.github.com>
With `-DENABLE_CLIENT_MODE=OFF` (i.e. `COAP_CLIENT_SUPPORT=0`), `full_match()` in `src/coap_block.c` is defined but its only caller is compiled out, producing `-Wunused-function` (fatal in -Werror builds):
```
src/coap_block.c:479:1: error: unused function 'full_match' [-Werror=-Wunused-function]
```
Wrap the static-inline definition in the same `#if COAP_CLIENT_SUPPORT` guard as its caller.
Signed-off-by: warter666 <121139223+Warterkk@users.noreply.github.com>
In `coap_ws_rd_http_header_client()` the first header (the HTTP status line) is split by `coap_ws_split_rd_header()`, which returns NULL when the buffered line contains no space/tab separator. The second call site checks for NULL, but the first one does not:
```c
value = coap_ws_split_rd_header(session);
if (strcmp((char *)ws->http_hdr, "HTTP/1.1") != 0 ||
atoi(value) != 101) {
```
If the HTTP header buffer is exactly `"HTTP/1.1"` (no trailing space), `strcmp()` returns 0, the `||` short-circuit does not apply, and `atoi(NULL)` is called - a remote crash in the WS client handshake when a malicious or broken server sends a truncated status line.
Fix: return 0 when `value` is NULL, mirroring the second call site.
The library builds cleanly after the change (cmake -DENABLE_DTLS=OFF, gcc/clang, 0 warnings).
Signed-off-by: warter666 <121139223+Warterkk@users.noreply.github.com>
When a message spans multiple mbedTLS records, coap_tls_write() returns
only the final mbedtls_ssl_write() result despite sending the entire
message. Its caller treats the PDU as partially written and queues an
already transmitted suffix.
Update the successful return value to the accumulated byte count.
Preserve the existing nonblocking retry and fatal-error handling.
Validated with native mbedTLS 3.6.2 loopback transfers and a focused
ASan/UBSan harness covering record boundaries and WANT_READ/WANT_WRITE.
TCP BERT payloads can exceed the 1024-byte callback scratch buffer. Allocate a temporary buffer sized to the requested chunk, pass it to the large-data callback, and release it after the PDU has copied the data. Preserve the stack buffer for regular block transfers and report allocation failures explicitly.
Packets from the same peer can overwrite a session's local address with a
multicast destination. Save the address when an observation is created or
renewed and restore it before generating notifications, so deferred responses
snapshot the correct address instead of being dropped as invalid multicast.
Add regression coverage for CON and NON observations, including renewals and
the local address captured by a notification's async response.
Validation: 215 unit tests passed (1712 assertions).
A request handler that leaves the response code unset asks for no
response to be sent. That is honoured for a piggybacked ACK (the token
gets stripped, so an empty ACK goes out) and for a non-confirmable or
reliable response (dropped in no_response()), but not for a separate
response set up with coap_register_async().
There the response is turned into a CON, and a 0.00 CON was put on the
wire. An Empty message is a ping (RFC 7252 4.2), not a response, and the
PDU still carries the request's token, which RFC 7252 4.1 does not allow.
Being confirmable, it was then retransmitted up to MAX_RETRANSMIT times,
usually at a client port that had long gone away.
Drop it like the other two cases, delete it without logging it as a
dropped response since the application asked for this, and document in
coap_handler(3) that a separate response is not sent either.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Server sessions are keyed on (remote address, local port) only, and
session->addr_info.local is overwritten by the destination of every
received packet. When a unicast CON request is parked in a coap_async_t
for a separate response and a multicast packet from the same peer
arrives before the async fires, the re-invoked handle_request() sees a
multicast local address, drops the CON per RFC7252 8.1 ("Invalid
multicast packet received"), and coap_check_async() frees the async:
the response is silently never sent.
Snapshot the local address in coap_register_async() and restore it on
the session before the async fires, so the deferred request is handled
(and its response source selected) against the address it actually
arrived on.
Seen in the field with a CoAP remote control whose GET /endpoint was
answered via the async path while it also multicast periodic
announcements from the same source port: the device received the empty
ACK and then never got the response.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>