When a subscription is canceled, coap_cancel() iterates through the
resources and deletes the observer. In addition, all outstanding
messages for this observer are removed from the send queue.
With commit 5b1a8f67, the session object associated with the deleted
observer may be automatically released by coap_delete_observer().
Therefore, coap_cancel_all_messages() must be invoked on the session
before deletion.
Fixes CID 1484386 found by Coverity scan.
When an idle server (D)TLS session times out, no event is reported to a
defined event handler. COAP_EVENT_DTLS_CLOSED is reported whenever there is
a read / write issue, and this fix also reports the event COAP_EVENT_DTLS_CLOSED
when the (D)TLS session is closed.
Some extra code had to be added in to prevent event COAP_EVENT_DTLS_CLOSED
being reported twice.
src/coap_gnutls.c:
src/coap_openssl.c:
src/coap_tinydtls.c:
Report event COAP_EVENT_DTLS_CLOSED when coap_dtls_free_session() and
coap_tls_free_session() are called.
src/coap_session.c:
Do not log spurious (D)TLS Alert packets received after session is closed.
Make endpoint->sessions and context->sessions a hashed chain of sessions
based on a key comprising of local and remote addresses and ports instead of
a linked list that has to be linearly searched.
include/coap2/coap_io.h:
include/coap2/coap_session.h:
Create a new struct coap_addr_tuple_t for the local and remote addresses/ports
to be used as the hash key. Update coap_packet_t and coap_session_t
appropriately.
Create SESSIONS_* macros to Add, Delete, Find and Iterate through the hashed
chain.
examples/coap-rd.c:
src/coap_io.c:
src/coap_io_lwip.c:
src/coap_openssl.c:
src/coap_session.c:
src/coap_tinydtls.c:
src/net.c:
src/resource.c:
Update with the new struct element names and replace the LL_* functions with
SESSIONS_* as appropriate.
Update coap_endpoint_get_session() to use SESSIONS_FIND() for fast lookup.
Future work is to review all the SESSIONS_ITER* and see if they can be sped up
as well.
As COAP_NACK_RST is used for
1. ICMP Port Unreachable message is received
2. CoAP reply RST message.
there needs to be a way to differentiate between these conditions.
If there is detected to be an ICMP response issue to sending a UDP
packet, report this as COAP_NACK_ICMP_ISSUE instead of COAP_NACK_RST.
If the reported issue to coap_session_disconnected() is COAP_NACK_ICMP_ISSUE,
then make sure that the packet (plain or DTLS) gets re-transmitted.
As hinted in #131 discussion, retry of the packet should be attempted,
(as per https://tools.ietf.org/html/rfc7252#section-4.2 ICMP Unreachable)
this fix will cause the plain packet to get retransmitted up to the maximum
retry count if type CON.
Likewise, DTLS will get restarted up to the maximum retry count if type CON.
examples/client.c:
Include COAP_NACK_ICMP_ISSUE in the nack_handler.
include/coap2/coap_io.h:
Add in COAP_NACK_ICMP_ISSUE to coap_nack_reason_t.
src/coap_session.c:
Update coap_session_disconnected() so that plain/DTLS can restart.
src/net.c:
Fix coap_wait_ack() to exponentially back off the re-transmit times.
Update coap_read_session() to report COAP_NACK_ICMP_ISSUE instead of
COAP_NACK_RST.
man/coap_handler.txt.in:
Update documentation
Add in support for both reliable and unreliable sessions when calling
coap_context_set_keepalive().
include/coap2/coap_session.h:
Track the last ping mid in coap_session_t.
src/coap_io.c:
src/coap_session.c:
Support both reliable and unreliable sending of pings in coap_write().
src/net.c:
Determine whether RST packet response is associated with a CoAP Empty Ping
that was sent and handle accordingly.
configure.ac:
examples/client.c:
include/coap2/net.h:
man/Makefile.am:
man/coap-client.txt.in:
man/coap.txt.in:
man/coap_handler.txt.in:
man/coap_keepalive.txt.in: (New)
man/coap_observe.txt.in:
Add in a new man page (coap_keepalive).
Update documentation to remove references to TCP and reliable only.
This is done by calling prng_init() with a non-zero value in coap_startup().
Change 7fb4ace2b7 modified the parameter to
prng_init() from a computed value to 0 when the code was re-organized.
This change uses the current time in microseconds as the seed to prng_init().
include/coap2/coap_time.h:
Add in coap_ticks_to_rt_us() support for lwIP and Contiki
src/net.c:
Update call to prng_init() in coap_startup() to use time in microsecs as the
seed parameter
See #373 where the issue was raised.
With
define Q(frac,fval) ((coap_tick_t)(((1 << (frac)) * (fval))))
and
tmp = SHR_FP(tv.tv_nsec * Q(FRAC, (COAP_TICKS_PER_SECOND/1000000000.0)), FRAC);
The Q function always returns 0 in error - e.g.
(gdb) p ((coap_tick_t)(((1 << (FRAC))*((COAP_TICKS_PER_SECOND/1000000000.0)))))
$6 = 0
(gdb) p ((((1 << (FRAC))*((COAP_TICKS_PER_SECOND/1000000000.0)))))
$7 = 0.001024
whereas we need the value 0.001024 to multiple with tv_nsec.
This change fixes this by moving the coap_tick_t from Q to SHR_FP.
Found when debugging #374
If a CoAP client using GnuTLS does not have PSK or PKI security defined
but communicatioes with coaps:// with a CoAP server that has PKI defined,
then there is a memory leak when the session is closed down.
src/coap_gnutls.c:
Free off PKI credentials if a client and PSK or PKI was not explicitly
defined in coap_dtls_free_gnutls_env().
Issue introduced by OpenSSL 1.1.1c causes valgrind errors to be reported. See
https://www.mail-archive.com/openssl-commits@openssl.org/msg21701.html and
https://github.com/openssl/openssl/pull/8606 which did not make 1.1.1c
scripts/build.sh:
tests/valgrind_suppression:
Temporarily suppress valgrind errors when SSL_CTS_new() is called when running
the tests.
Note: This suppression will also need to be applied when running valgrind
against other CoAP executables using OpenSSL 1.1.1c to prevent the valgrind
errors getting reported.
src/coap_openssl.c:
memset cookie_secret to 0 to stop valgrind warning.
GnuTLS currently does not retry to send the Client Hello packets if there was
no (Server Hello) response. This was never correctly implemented.
src/coap_gnutls.c:
Fix receive_timout() so that it differentiates between DTLS and TLS.
If DTLS, if data has already been read in, indicate this.
if this is a coap_dtls_handle_timeout() call, only check readfds
(writefds will always be true, causing confusion).
Set DTLS timeouts where appropriate.
Update coap_dtls_*_timeout() functions to return the correct values.
include/coap2/coap_dtls.h:
src/coap_gnutls.c:
src/coap_io.c:
src/coap_notls.c:
src/coap_openssl.c:
src/coap_tinydtls.c:
Add in coap_tick_t now parameter to coap_dtls_get_timeout() for better
accuracy.
src/net.c:
Corect the length for the final block size.
Add in an ETAG and SIZE2 option into the response as suggested by RFC7959.
examples/client.c:
Warn if URI path is too long for internal buffer (found when testing that
a large WellKnown response triggered sending BLOCK2 correctly).
Increase internal buffersize to allow longer URIs.
To reproduce issue
coap-client -b 256 coap://127.0.0.1/.well-known/core
As reported by Zafi Ramarosandratana. See #360 which this fixes.
Once a ICMP Port Unreachable message is received, the session is
disconnected by a call to coap_session_disconnect(). However if the session
is of type CON, the logic currently tries to retransmit the packet, but
nothing gets sent out.
src/coap_session.c:
Make sure that any entries on the context->sendqueue for the disconnected
session are removed.
examples/client.c:
Add in a Nack handler so that the client immediately exits on the session
disconnect. Additionally this also tidies up the exit after transmission
retries.
src/coap_openssl.c:
Give the function that abstracts the Subject Alternative Name (SAN),
or the CN= if SAN is not available, a better descriptive name to prevent
possible confusion.
Commit 32e219a has resolved an issue with the size parameter for
inet_ntop() in a way that introduces errors on certain Linux
platforms. This change now passes the exact size for AF_INET
and AF_INET6 to fix that.
It appears that message_id was left in coap_context_t and coap_async_t
when coap_session_t was created.
include/coap2/async.h:
include/coap2/net.h:
Remove message_id.
src/net.c:
No longer just set message_id.
configure.ac:
Test for the presence of 'struct cmsghdr' and set HAVE_STRUCT_CMSGHDR
if appropriate.
src/coap_io.c:
Revert to recvfrom() and sendto() if HAVE_STRUCT_CMSGHDR is not defined,
instead of using recvmsg() and sendmsg().
endpoint->hello is used to hold the 5 tuple etc. information about a new
connection that has come in. Once the DTLS handshake has been completed
a new coap_session_t is created for the ongoing encrypted work.
However, if a second new DTLS request comes in before the first session
has completed the DTLS handshakes, it will overwrite the endpoint->hello
information causing the first request to stall / get lost.
GnuTLS already has to check that the initial DTLS packet is a Client Hello
before starting up a GnuTLS session, so moving this logic up a level to
the initial DTLS packet makes sense to create a coap_session_t at this
point and getting rid of the temporary endpoint->hello gets rid of this
issue.
Makefile.am:
Replace coap_endpoint_new_dtls_session with coap_session_new_dtls_session
include/coap2/coap_session.h:
Remove coap_session_t hello;
Replace coap_endpoint_new_dtls_session with coap_session_new_dtls_session
src/coap_gnutls.c:
Remove references to endpoint->hello
Remove Client Hello check code (move it to coap_endpoint_get_session())
src/coap_io.c:
Remove references to freeing off ep->hello
src/coap_session.c:
Remove endpoint->hello code.
Check for Client Hello in coap_endpoint_get_session() if no session, is DTLS
and don't build coap_session if not a Client Hello.
Otherwise, always build a new coap_session.
Timeout Client Hello session if inactive to prevent a DoS.
Replace coap_endpoint_new_dtls_session with coap_session_new_dtls_session
src/coap_net.c:
Replace coap_endpoint_new_dtls_session with coap_session_new_dtls_session
Code works as expected for confirmable observes as the sent pdu is
retained for potential re-transmission.
For non-confirmable observes, the RST is seen in the response packet but
previously had no way of finding the observe/subscription to cancel.
Keep the last sent message id in coap_subscription_t (as tid) and when the
RST comes in, search for the subscription that has the same message id as
the pdu and remove that subscription.
include/coap2/subscribe.h:
Add in tid to coap_subscription_t (as per coap_pdu_t).
src/net.c:
Match tid in incoming RST pdu with a subscription. If found, delete the
subscription.
src/resource.c:
Save tid in both pdu and subscription when sending off an observe response.
To test code, make the following temporary change to coap-client
diff --git a/examples/client.c b/examples/client.c
index 4d3e4c7..0020b68 100644
--- a/examples/client.c
+++ b/examples/client.c
@@ -348,7 +348,8 @@ message_handler(struct coap_context_t *ctx,
#endif
/* check if this is a response to our original request */
- if (!check_token(received)) {
+static int count = 0;
+ if (!check_token(received) || ++count == 5) {
/* drop if this was just some message, or send RST in case of notification */
if (!sent && (received->type == COAP_MESSAGE_CON ||
received->type == COAP_MESSAGE_NON))
and run (coap-server running on the same host)
coap-client -N -s 10 coap://127.0.0.1/time
Platforms that do not have getaddrinfo() most likely do not have
the netdb.h include file as well.
This change includes netdb.h only if HAVE_NETDB_H is defined
(usually by configure).
On RIOT, inet_ntop() expects the size parameter to reflect the
length of the given address. A larger value causes inet_ntop()
to return ENOSPC.
This change passes the address size as a workaround, or the actual
number of remaining bytes in the output buffer in case less than
address size bytes remain.
As coap-server now sets up 2 (or 4) endpoints, UDP and TCP based, all
subsequent endpoints are pre-pended to the ctx->endpoint list. Thus
ctx->endpoint will always be TCP based. Setting IPV6_JOIN_GROUP on a TCP
socket is a no-no.
As join() is complex function, it should be within libcoap so as to not require
detailed knowledge of how internal structures work (which really should be
opaque to the application writer).
include/coap2/net.h:
src/net.c:
libcoap-2.map:
libcoap-2.sym:
Create coap_join_mcast_group() in src/net.c (as it is a network layer
function using the (fixed) join() code. (Iterate through the ctx->endpoint list
looking for UDP based endpoints and only do the IPV6_JOIN_GROUP on them.)
There is no support for WITH_CONTIKI or WITH_LWIP at this point (returns -1).
examples/coap-server.c:
Remove join() code and replace call to join() with coap_join_mcast_group()
examples/coap-rd.c:
Remove join() code and replace call to join() with coap_join_mcast_group()
man/coap-rd.txt.in:
Correct a typo in the coap-ed man page
When there is a limited stack size, having large data items on the stack
can easily cause stack overflows.
This makes integration with any constrained stack O/S a lot easier.
include/coap2/coap_mutex.h:
Create coap_ mutex functions which are platform independent to protect
the (now) static variables if compiled with "-DCOAP_CONSTRAINED_STACK=1"
Makefile.am:
Include include/coap2/coap_mutex.h for distribution
coap_config.h.contiki:
coap_config.h.lwip:
As CONTIKI and LWIP have constrained stacks, set
"#define COAP_CONSTRAINED_STACK 1"
src/coap_debug.c:
src/coap_io.c:
src/net.c:
coap_show_pdu()
coap_log_impl()
coap_run_once()
coap_read_session()
coap_read_endpoint()
Move large data items out of the functions' stack and make them static
variables (defined within the function) if COAP_CONSTRAINED_STACK is defined.
Protect the usage of these static variables by mutexes.
Note: if "-DCOAP_CONSTRAINED_STACK=0" is used, then the stack will not
be constrained.
Following on from #324 where coap_session_mfree() had to be moved in
coap_session_free() to correctly allow for tinydtls cleanup, session->endpoint
and session->context should not be cleared out prior to call of
coap_sesson_free() in coap_free_endpoint().
src/coap_session.c:
Remove lines setting session->endpoint and session->context to NULL
While #321 prevented a core dump, that fix still caused memory corruption.
src/coap_gnutls.c:
Correct the code to correctly NULL terminate the created username.
As a server, idle sessions are left around in case the client wants to do
further work using the same 5 tuple IP information.
With constrained systems, the number of sessions is limited, and so it is
easy to run out of sessions.
src/coap_session.c:
If there is an idle session, context->max_idle_sessions is not set and
a new session cannot be created, free off the oldest session and retry
the creation again.
examples/contiki/README:
examples/lwip/README:
Tidy up the documentation
In coap_session_free(), as coap_session_mfree() is called after
the session has been deleted out the endpoint or context sessions,
dtls_send_to_peer() is unable to find the session to send out the
Alert/Warning Close Notify message packet.
src/coap_session.c:
Move coap_session_mfree() to before setting deleting session out of endpoint or context sessions in coap_session_free().
Note: TinyDTLS has been separately updated to not report ALRT on a
Close Notify - see https://github.com/eclipse/tinydtls/pull/5.
When compiling libcoap with format truncation warnings enabled,
GCC warns about the potential issue with "%u.%02u" format string,
since the first argument may produce more than one byte of output:
error: '%02u' directive output may be truncated writing 2 bytes
into a region of size between 0 and 3 [-Werror=format-truncation=]
The first argument (class) is limited to 3 bits according to the
specification. Mask the higher bits to fix the warning.
packet is allocated on the stack in coap_read_session(), and so is
uninitialized when processed by coap_network_read(). If there is not an
appropriate cmsg entry in mhdr.msg_control when returning from recvmsg()
packet->ifindex (nor for that matter packet->dst) does not get updated.
src/coap_io.c:
Preset mhdr.msg_control initial cmsghdr with invalid information and an
oversize length so that underlying recvmsg() implementations (e.g. minimal
IoT implementations) that do not update mhdr.msg_control's data, or do not
update it with the destination IP of the packet are correctly handled.
memset the node when a new optlist node is created, because the node->next maybe not NULL, so if it creates a new optlist node, and delete it, and then create it again, error will be occurred