-
Notifications
You must be signed in to change notification settings - Fork 2.1k
net/unicoap: Unified and Modular CoAP stack: Messaging and Minimal Server (pt 2) #21582
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
da014c7 to
4d00949
Compare
| const uint8_t* component = NULL; | ||
| ssize_t res = -1; | ||
| while ((res =unicoap_options_get_next_by_number(iterator, number, | ||
| (const uint8_t**)&component)) >= 0) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| (const uint8_t**)&component)) >= 0) { | |
| &component)) >= 0) { |
or why would you still need this cast now that component is const uint8_t *?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, I remember you saying you a doing this kind of casts in other places across unicoap, have you double-checked and changed?
| if (length > 0) { | ||
| size_t i = length - 1; | ||
| while (i > 0) { | ||
| if (path[i] == '/') { | ||
| i -= 1; | ||
| } else { | ||
| break; | ||
| } | ||
| } | ||
| return i + 1; | ||
| } else { | ||
| return length; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| if (length > 0) { | |
| size_t i = length - 1; | |
| while (i > 0) { | |
| if (path[i] == '/') { | |
| i -= 1; | |
| } else { | |
| break; | |
| } | |
| } | |
| return i + 1; | |
| } else { | |
| return length; | |
| } | |
| if (length == 0) { | |
| return length; | |
| } | |
| size_t i = length - 1; | |
| while (i > 0) { | |
| if (path[i] == '/') { | |
| i -= 1; | |
| } | |
| else { | |
| break; | |
| } | |
| } | |
| return i + 1; |
less indentation
| return false; | ||
| } | ||
|
|
||
| /* The actual path (LHS) is now either as long or longer. If it is longer, then we |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| /* The actual path (LHS) is now either as long or longer. If it is longer, then we | |
| /* The actual path (LHS) is now either as long or longer than RHS. If it is longer, then we |
| assert(resource); | ||
| assert(lhs_path); | ||
|
|
||
| /* We are comparing the left-hand side (path from request) to the right-hand side (resource). */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since this is pretty bound to LHS = request path and RHS = resource definition path, why not reflecting that in the variable name instead of LHS and RHS? Would probably ease understanding.
| * expect a slash to indicate a subtree. Either the RHS path already ends with a slash | ||
| * or the LHS has a slash that succeeds the last RHS character. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't get that part. Isn't LHS trimmed to have no slashes at the end?
| * LHS: /a -> RHS ends in slash, every path that is longer than RHS is a subpath | ||
| * RHS: / |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| * LHS: /a -> RHS ends in slash, every path that is longer than RHS is a subpath | |
| * RHS: / | |
| * RHS: /, LHS: /a -> RHS ends in slash, every path that is longer than RHS is a subpath |
similar below
| * LHS: /a/a -> RHS ends in slash, every path that is longer than RHS is a subpath | ||
| * RHS: /a/ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Isn't this basically the same case as the one above?
| return cursor == (end + 1); | ||
| /* Make sure we read all options, i.e., the actual path is not longer than the resource's. | ||
| */ | ||
| return unicoap_options_get_next_uri_path_component(&iterator, &component) == -1; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you're welcome for the unittest nagging :P
| }; | ||
| UNICOAP_OPTIONS_ALLOC(options, 10); | ||
|
|
||
| printf("not working\n"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| printf("not working\n"); |
?
|
Followup of #21582 (comment) regarding dTLS: The $ python3 examples/networking/coap/unicoap_server/client.py -m GET -u "coaps://[fe80::5c64:bbff:fe11:9231%tap0]/.well-known/core"
usage: client.py -m <GET|PUT|POST|DELETE|PATCH|iPATCH|FETCH> -u <URI> [--type <NON|CON>] [--observe] [-p <PAYLOAD>]
DEBUG:asyncio:Using selector: EpollSelector
using NON GET request
timeout set to 4.0s
INFO:websockets.server:server listening on [::]:8600
DEBUG:coap-server:Server ready to receive requests
/home/mikolai/TUD/Code/RIOT/examples/networking/coap/unicoap_server/client.py:107: DeprecationWarning: Initializing messages with an mtype is deprecated. Instead, set transport_tuning=aiocoap.Reliable oraiocoap. Unreliable.
request = Message(
INFO:coap-server:No DTLS connection active to (fe80::5c64:bbff:fe11:9231%tap0, 5684, b'Client_identity'), creating one
DEBUG:coap-server:Sending request - Token: be49, Remote: <aiocoap.transports.tinydtls.DTLSClientConnection object at 0x7fdf1f8cc5d0>
DEBUG:coap-server:Sending message <aiocoap.Message: GET to <aiocoap.transports.tinydtls.DTLSClientConnection object at 0x7fdf1f8cc5d0>, 1 option(s), token be49, NON, MID 0xa9e1>
WARNING:coap-server:Unhandled alert level 1 code 0
error: timeout exceeded after waiting 4.0s
Exception ignored in: <function DTLSClientConnection.__del__ at 0x7fdf1fab9580>
Traceback (most recent call last):
File "/home/mikolai/.local/share/virtualenvs/RIOT-Q3sUo0rz/lib/python3.11/site-packages/aiocoap/transports/tinydtls.py", line 263, in __del__
self.shutdown()
File "/home/mikolai/.local/share/virtualenvs/RIOT-Q3sUo0rz/lib/python3.11/site-packages/aiocoap/transports/tinydtls.py", line 256, in shutdown
self._transport.close()
File "/usr/lib/python3.11/asyncio/selector_events.py", line 839, in close
self._loop.call_soon(self._call_connection_lost, None)
File "/usr/lib/python3.11/asyncio/base_events.py", line 761, in call_soon
self._check_closed()
File "/usr/lib/python3.11/asyncio/base_events.py", line 519, in _check_closed
raise RuntimeError('Event loop is closed')
RuntimeError: Event loop is closedInterestingly enough, for On my machine, dTLS with your script and $ python3 examples/networking/coap/unicoap_server/client.py -m GET -u "coaps://[fe80::5c64:bbff:fe11:9231%tap0]/.well-known/core"
usage: client.py -m <GET|PUT|POST|DELETE|PATCH|iPATCH|FETCH> -u <URI> [--type <NON|CON>] [--observe] [-p <PAYLOAD>]
DEBUG:asyncio:Using selector: EpollSelector
using NON GET request
timeout set to 4.0s
INFO:websockets.server:server listening on [::]:8600
DEBUG:coap-server:Server ready to receive requests
/home/mikolai/TUD/Code/RIOT/examples/networking/coap/unicoap_server/client.py:107: DeprecationWarning: Initializing messages with an mtype is deprecated. Instead, set transport_tuning=aiocoap.Reliable oraiocoap. Unreliable.
request = Message(
INFO:coap-server:No DTLS connection active to (fe80::5c64:bbff:fe11:9231%tap0, 5684, b'Client_identity'), creating one
DEBUG:coap-server:Sending request - Token: 8647, Remote: <aiocoap.transports.tinydtls.DTLSClientConnection object at 0x7fb24d0d03d0>
DEBUG:coap-server:Sending message <aiocoap.Message: GET to <aiocoap.transports.tinydtls.DTLSClientConnection object at 0x7fb24d0d03d0>, 1 option(s), token 8647, NON, MID 0x9f40>
DEBUG:coap-server:Incoming message <aiocoap.Message: 2.05 Content from <aiocoap.transports.tinydtls.DTLSClientConnection object at 0x7fb24d0d03d0>, 1 option(s), 46 byte(s) payload, token 8647, NON, MID 0x9f40>
DEBUG:coap-server:Received Response: <aiocoap.Message: 2.05 Content from <aiocoap.transports.tinydtls.DTLSClientConnection object at 0x7fb24d0d03d0>, 1 option(s), 46 byte(s) payload, token 8647, NON, MID 0x9f40>
DEBUG:coap-server:Response <aiocoap.Message: 2.05 Content from <aiocoap.transports.tinydtls.DTLSClientConnection object at 0x7fb24d0d03d0>, 1 option(s), 46 byte(s) payload, token 8647, NON, MID 0x9f40> matched to request <Pipe at 0x7fb24d0bb490 around <aiocoap.Message: GET to <aiocoap.transports.tinydtls.DTLSClientConnection object at 0x7fb24d0d03d0>, 1 option(s), token 8647, NON, MID 0x9f40> with 2 callbacks (thereof 1 interests)>
response: 2.05 Content
b'</cli/stats>;ct=0;rt="count";obs,</riot/board>'
/home/mikolai/.local/share/virtualenvs/RIOT-Q3sUo0rz/lib/python3.11/site-packages/aiocoap/transports/tinydtls.py:169: UserWarning: DTLS module did not shut down the DTLSSocket perfectly; it still tried to call _write in vain
warnings.warn(
Exception ignored in: <function DTLSClientConnection.__del__ at 0x7fb24d2bd580>
Traceback (most recent call last):
File "/home/mikolai/.local/share/virtualenvs/RIOT-Q3sUo0rz/lib/python3.11/site-packages/aiocoap/transports/tinydtls.py", line 263, in __del__
self.shutdown()
File "/home/mikolai/.local/share/virtualenvs/RIOT-Q3sUo0rz/lib/python3.11/site-packages/aiocoap/transports/tinydtls.py", line 256, in shutdown
self._transport.close()
File "/usr/lib/python3.11/asyncio/selector_events.py", line 839, in close
self._loop.call_soon(self._call_connection_lost, None)
File "/usr/lib/python3.11/asyncio/base_events.py", line 761, in call_soon
self._check_closed()
File "/usr/lib/python3.11/asyncio/base_events.py", line 519, in _check_closed
raise RuntimeError('Event loop is closed')
RuntimeError: Event loop is closed |
|
The assertion failure problem from #21582 (comment) seems fixed, so now I was able to test dTLS on the nrf52840dk as well. The output suggests some kind of buffer overflow Client side python3 examples/networking/coap/unicoap_server/client.py -m GET -u "coaps://[2001:db8::2]/greeting?name=RIOT"
usage: client.py -m <GET|PUT|POST|DELETE|PATCH|iPATCH|FETCH> -u <URI> [--type <NON|CON>] [--observe] [-p <PAYLOAD>]
DEBUG:asyncio:Using selector: EpollSelector
using NON GET request
timeout set to 4.0s
INFO:websockets.server:server listening on [::]:8600
DEBUG:coap-server:Server ready to receive requests
/home/mikolai/TUD/Code/RIOT/examples/networking/coap/unicoap_server/client.py:107: DeprecationWarning: Initializing messages with an mtype is deprecated. Instead, set transport_tuning=aiocoap.Reliable oraiocoap. Unreliable.
request = Message(
INFO:coap-server:No DTLS connection active to (2001:db8::2, 5684, b'Client_identity'), creating one
DEBUG:coap-server:Sending request - Token: 03d5, Remote: <aiocoap.transports.tinydtls.DTLSClientConnection object at 0x7fd3db0d0490>
DEBUG:coap-server:Sending message <aiocoap.Message: GET to <aiocoap.transports.tinydtls.DTLSClientConnection object at 0x7fd3db0d0490>, 2 option(s), token 03d5, NON, MID 0xe54d>
error: timeout exceeded after waiting 4.0sserver (unicoap) side: looks like some kind of buffer overflow to me? like in, undefined behavior, that just happens to behave differently on native and on hardware (Aaaah, I cannot reply to a comment that is not to a file in Github? o.O) |
there we go (with debug/assist enabled): note that Here is the pcap after commenting that line out: unicoap-dtls.pcapng.zip Python side gives me |
Co-authored-by: Mikolai Gütschow <[email protected]>
|
For future reference: mguetschow@92e63e5 contains some fixes to the dtls stack to make unicoap over dtls mostly work: I've encountered spurious deadlocks (I think) when sending multiple dtls requests one after another. Other open issues encountered on the way:
|
|
#21827 together with mguetschow@30044de should be the right fixes to get dTLS to work properly. |
|
Testing on /home/mikolai/TUD/Code/RIOT/sys/net/application_layer/unicoap/drivers/rfc7252/udp/transport.c:29: error: "UDP_DEBUG" redefined [-Werror]
29 | #define UDP_DEBUG(...) _UNICOAP_PREFIX_DEBUG(".transport.udp", __VA_ARGS__)
|
In file included from /home/mikolai/.riot/pkg/lwip/src/include/lwip/api.h:40,
from /home/mikolai/TUD/Code/RIOT/pkg/lwip/include/sock_types.h:22,
from /home/mikolai/TUD/Code/RIOT/sys/include/net/sock/udp.h:845,
from /home/mikolai/TUD/Code/RIOT/sys/include/net/sock/dtls.h:546,
from /home/mikolai/TUD/Code/RIOT/sys/include/net/sock/async/event.h:174,
from /home/mikolai/TUD/Code/RIOT/sys/include/net/unicoap/transport.h:22,
from /home/mikolai/TUD/Code/RIOT/sys/net/application_layer/unicoap/drivers/rfc7252/udp/transport.c:20:
/home/mikolai/.riot/pkg/lwip/src/include/lwip/opt.h:3535: note: this is the location of the previous definition
3535 | #define UDP_DEBUG LWIP_DBG_OFFbut otherwise works like a charm (after applying #21833) |
|
@carl-tud May I also interest you about |
|
On Edit: this is with slipdev enabled, when not using that one but only the default 802.15.4 radio, this PR needs to be rebased on current With that applied, I still get |
| error: | ||
| SERVER_DEBUG("failed to send response, trying to send 5.05 unreliably\n"); | ||
|
|
||
| /* try to send 5.05, */ | ||
| unicoap_response_init_empty(packet->message, UNICOAP_STATUS_INTERNAL_SERVER_ERROR); | ||
| unicoap_messaging_send(packet, _messaging_flags_resource(resource->flags) & | ||
| ~UNICOAP_MESSAGING_FLAG_RELIABLE); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| error: | |
| SERVER_DEBUG("failed to send response, trying to send 5.05 unreliably\n"); | |
| /* try to send 5.05, */ | |
| unicoap_response_init_empty(packet->message, UNICOAP_STATUS_INTERNAL_SERVER_ERROR); | |
| unicoap_messaging_send(packet, _messaging_flags_resource(resource->flags) & | |
| ~UNICOAP_MESSAGING_FLAG_RELIABLE); | |
| error: | |
| SERVER_DEBUG("failed to send response, trying to send 5.00 unreliably\n"); | |
| /* try to send 5.00 */ | |
| unicoap_response_init_empty(packet->message, UNICOAP_STATUS_INTERNAL_SERVER_ERROR); | |
| unicoap_messaging_send(packet, _messaging_flags_resource(resource->flags) & | |
| ~UNICOAP_MESSAGING_FLAG_RELIABLE); |
5.05 (Proxying not supported) would not fit here, I guess.
Also it may be debatable if it makes sense to try sending a message after sending a message failed, but I guess that depends on the error condition. With lwip, I get
coap.messaging.rfc7252: received <NON REQ mid=11684 token=D453 code=0.01 GET payload=(0 bytes) options=(0; 0 bytes)>
coap.messaging: received in channel:
remote=UDP <sock_tl_ep port=5683 netif=2 ipv6=fe80::5c2f:e804:c321:2ab>
local=UDP <sock_tl_ep port=5683 netif=0 ipv6=fe80::6462:cc4f:30e5:f533>
coap.server: /: found
coap.server: invoking handler
app: GET /, 0 bytes
coap.server: sending immediate response
coap.messaging: sending in channel:
remote=UDP <sock_tl_ep port=5683 netif=2 ipv6=fe80::5c2f:e804:c321:2ab>
local=UDP <sock_tl_ep port=5683 netif=0 ipv6=fe80::6462:cc4f:30e5:f533>
coap.messaging.rfc7252: sending <CON RESP mid=7598 token=D453 code=2.05 Content payload=(13 bytes) options=(0; 0 bytes)>
coap.transport.udp: sendv: 20 bytes
coap.transport.udp: udp_sendv_aux failed: -EHOSTUNREACH
coap.messaging.rfc7252: sending failed
coap.messaging.rfc7252: [MID 7598] transmission ended
coap.server: error: could not send response
coap.server: failed to send response, trying to send 5.05 unreliably
coap.messaging: sending in channel:
remote=UDP <sock_tl_ep port=5683 netif=2 ipv6=fe80::5c2f:e804:c321:2ab>
local=UDP <sock_tl_ep port=5683 netif=0 ipv6=fe80::6462:cc4f:30e5:f533>
coap.messaging.rfc7252: sending <ACK RESP mid=7598 token=D453 code=5.00 Internal Server Error payload=(0 bytes) options=(0; 0 bytes)>
coap.transport.udp: sendv: 6 bytes
coap.transport.udp: udp_sendv_aux failed: -EHOSTUNREACH
coap.messaging.rfc7252: sending failed
This PR is the second in a series to introduce
unicoap, a unified and modular CoAP implementation for RIOT. An overview of all PRs related tounicoapis presented in #21389, including reasons whyunicoapis needed and a performance analysis.What does this PR include?
unicoapon a thread of your choice, e.g., the main thread.The new API is more flexible. CoAP endpoints are abstracted into a
unicoap_endpoint_tstructure and transport-specific settings are controlled by flags. For example, this is a simple resource that responds with "Hello, World!".More in the documentation (CI build now available).