Skip to content

Conversation

carl-tud
Copy link
Contributor

@carl-tud carl-tud commented Jul 7, 2025

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 to unicoap is presented in #21389, including reasons why unicoap is needed and a performance analysis.

What does this PR include?

  • RFC 7252 messaging implementation
  • Implementation of the CoAP over UDP and CoAP over DTLS drivers, plus an additional zero-copy optimization for UDP
  • Basic server functionality, including XFA resource definitions and helpful debug logs
  • A sample server application
  • Structured documentation, including a tutorial from the first line of code to running the example and testing it using the included client script

The new API is more flexible. CoAP endpoints are abstracted into a unicoap_endpoint_t structure and transport-specific settings are controlled by flags. For example, this is a simple resource that responds with "Hello, World!".

// Define request handler for /hello
static int handle_hello_request(unicoap_message_t* message, 
    const unicoap_aux_t* aux, unicoap_request_context_t* ctx, void* arg) {
    // The aux parameter provides access to auxiliary information, such as local and remote endpoints,
    // transport-specific data and internal properties such as the message token.

    // Retrieve remote (client) endpoint and log string description of protocol number.
    printf("/hello resource invoked over %s\n", unicoap_string_from_proto(aux->remote->proto));

    // Craft response using convenience initializer. Vectored payloads are supported, too.
    unicoap_response_init_string(message, UNICOAP_STATUS_CONTENT, "Hello, World!");

    // Send response.
    return unicoap_send_response(message, ctx);
}

// Statically define resource, but dynamic registrations are also possible.
UNICOAP_RESOURCE(hello) {
    .path = "/hello",
    
    // Instruct unicoap to send confirmable messages when communicating over UDP or DTLS.
    // This flag abstracts the transport-specific message type.
    .flags = UNICOAP_RESOURCE_FLAG_RELIABLE,
    
    // Specify what methods to allow. In unicoap, there are no duplicate defines for method flags.
    .methods = UNICOAP_METHODS(UNICOAP_METHOD_GET, UNICOAP_METHOD_PUT),
    
    // Optionally, you can also restrict the resource to a set of transports.
    .protocols = UNICOAP_PROTOCOLS(UNICOAP_PROTO_DTLS, UNICOAP_PROTO_UDP),
    
    .handler = handle_hello_request,
    .handler_arg = NULL
};

More in the documentation (CI build not available yet).

@github-actions github-actions bot added Area: network Area: Networking Area: doc Area: Documentation Area: tests Area: tests and testing framework Area: build system Area: Build system Area: CoAP Area: Constrained Application Protocol implementations Area: sys Area: System Area: examples Area: Example Applications Area: Kconfig Area: Kconfig integration labels Jul 7, 2025
@carl-tud carl-tud changed the title net/unicoap: Messaging and Minimal Server (pt 2) net/unicoap: Unified and Modular CoAP stack: Messaging and Minimal Server (pt 2) Jul 7, 2025
@crasbe crasbe added Type: new feature The issue requests / The PR implemements a new feature for RIOT CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR labels Jul 7, 2025
@riot-ci
Copy link

riot-ci commented Jul 7, 2025

Murdock results

FAILED

8d3db35 fixup: net/unicoap: server tutorial docs: remove trailing whitespace

Success Failures Total Runtime
10469 0 10523 16m:17s

Artifacts

@carl-tud carl-tud force-pushed the unicoap-02-server-minimal branch from da014c7 to 4d00949 Compare July 9, 2025 14:37
@github-actions github-actions bot removed the Area: tests Area: tests and testing framework label Jul 9, 2025
@carl-tud carl-tud marked this pull request as ready for review July 9, 2025 14:42
@carl-tud
Copy link
Contributor Author

carl-tud commented Jul 9, 2025

@LasseRosenow
Does this fit your use case?

/**
* @brief Adds UDP socket for client and server functionality
* @pre Socket must be pre-allocated and must remain allocated until the UDP driver has been
* deinitialized or the socket is closed by you.
*
* @param[in,out] socket Pre-allocated socket to use
* @param[in] local Initialized endpoint, does not need to outlive this function call
*
* You can call this function at any time after `unicoap` has been initialized.
*/
# if IS_USED(MODULE_UNICOAP_DRIVER_UDP) || defined(DOXYGEN)
int unicoap_transport_udp_add_socket(sock_udp_t* socket, sock_udp_ep_t* local);

Copy link
Contributor

@mguetschow mguetschow left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the next PR! Great code quality as usual! Reviewed up to and including unicoap/docs.

@@ -0,0 +1,2 @@
CONFIG_UNICOAP_DEBUG_LOGGING=y
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe turning this off would also shrink the Makefile.ci.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes this a good idea.

Copy link
Contributor Author

@carl-tud carl-tud Jul 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a way I can let the CI generate the Makefile.ci for me? I'm asking because this is taking me ages locally @crasbe

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes and no, you can let the CI do a "full build" with "no fast fail" and extract the failed boards from the list. However due to our limited CI resources currently, that takes about 6 hours.

Unfortunately my Thinkpad is still at work (I'm on vacation) and our skyleaf server is offline, so I can't really generate it for you.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, thanks, good to know. I don’t really need it atm. I guess now I have an excuse to buy more expensive hardware urgh


If the built-in
behavior does not fit your scenario, you can customize the matching algorithm per listener.
To do this, set the @ref unicoap_listener_t.request_matcher property. By default, if this property
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
To do this, set the @ref unicoap_listener_t.request_matcher property. By default, if this property
To do this, set the @ref unicoap_listener_t::request_matcher property. By default, if this property


### Responding

There are multiple techniques for responding.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, here is the explanation I was asking for in the guide / example code. Maybe just refer to here then.


2. **Call send**: Initialize a response message with the status code, and
optionally, also payload and options. You can repurpose the memory used by the `message`
parameter for the response, but you must not write into the payload buffer of mutate options.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
parameter for the response, but you must not write into the payload buffer of mutate options.
parameter for the response, but you must not write into the payload buffer or mutate options.

You may also directly return the result of @ref unicoap_send_response.
Please be aware any processing performed inside this handler is executed in the server's
processing loop and will thus block it. Given an expensive operation, we encourage you to switch
to the third technique. Nevertheless, this should be the preferred response technique for all
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
to the third technique. Nevertheless, this should be the preferred response technique for all
to the third technique. Nevertheless, this should be the preferred response technique for most

?



@remark
`unicoap` runs a CoAP server for you in the background. Each driver asynchronously forwards packets
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

...if it is not disabled via the config.

Copy link
Contributor

@crasbe crasbe left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A first look-through. Mikolai already commented about the indentation of the preprocessor commands, but I only saw that once I went through it 😅

There are probably some functions that slipped through, but I'll do a second round when most of the comments are resolved. It's becoming a bit crowded.

Comment on lines +273 to +274
* @returns Null-terminated transport description, such as `"UDP"` or `"DTLS"`
* @returns `"?"` if protocol number is unknown
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* @returns Null-terminated transport description, such as `"UDP"` or `"DTLS"`
* @returns `"?"` if protocol number is unknown
* @retval Null-terminated transport description, such as `"UDP"` or `"DTLS"`
* @retval `"?"` if protocol number is unknown

Comment on lines 408 to 409
* @return Zero if resource is found and matcher determined request matches resource definition
* @return Non-zero CoAP status code appropriate for the mismatch
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* @return Zero if resource is found and matcher determined request matches resource definition
* @return Non-zero CoAP status code appropriate for the mismatch
* @retval Zero if resource is found and matcher determined request matches resource definition
* @retval Non-zero CoAP status code appropriate for the mismatch

Copy link
Contributor

@mguetschow mguetschow left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now this is (only?) missing review of */transport.c, server.c, and state.c.

@@ -1,4 +1,4 @@
@defgroup net_unicoap_drivers_dtls CoAP over DTLS Driver
g@defgroup net_unicoap_drivers_dtls CoAP over DTLS Driver
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
g@defgroup net_unicoap_drivers_dtls CoAP over DTLS Driver
@defgroup net_unicoap_drivers_dtls CoAP over DTLS Driver

uint8_t* pdu;

/**
* @brief Size of @ref unicoap_messaging_state_udp_dtls_t.pdu
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* @brief Size of @ref unicoap_messaging_state_udp_dtls_t.pdu
* @brief Size of @ref unicoap_messaging_state_udp_dtls_t::pdu

or rather?

Suggested change
* @brief Size of @ref unicoap_messaging_state_udp_dtls_t.pdu
* @brief Size of @ref transmission_t::pdu

uint8_t remaining_retransmissions : 5;

bool is_used : 1;
} transmission_t;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
} transmission_t;
} _transmission_t;

to signal this is a private type.

/** @brief Message ID unicoap is going to use for the next outbound request or response */
atomic_uint next_message_id;

# if CONFIG_UNICOAP_CARBON_COPIES_MAX > 0
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
# if CONFIG_UNICOAP_CARBON_COPIES_MAX > 0
#if CONFIG_UNICOAP_CARBON_COPIES_MAX > 0

and in all other places


typedef struct {
/** @brief Message ID unicoap is going to use for the next outbound request or response */
atomic_uint next_message_id;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe document from which thread contexts this is supposed to be accessed that warrants it being an atomic_uint.

UNICOAP_PREPROCESSING_ERROR_UNSUPPORTED = -0x1002,

/**
* @brief The given message is unknown and cannot be processed
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* @brief The given message is unknown and cannot be processed
* @brief The given message is unexpected and cannot be processed

UNICOAP_PREPROCESSING_ERROR_RESPONSE_UNEXPECTED = -0x1004,

/**
* @brief Unknown notification, no known client exchange (observation)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* @brief Unknown notification, no known client exchange (observation)
* @brief Unexpected notification, no known client exchange (observation)

Comment on lines +158 to +160
* @brief The given message is unknown and cannot be processed
*
* There's no known client exchange running.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

copy pasta

*
* @param[in] endpoint Remote endpoint to release buffers for
*/
void unicoap_exchange_forget_endpoint(const unicoap_endpoint_t* endpoint);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How does this differ from void unicoap_exchange_forget_failed_endpoint(const unicoap_endpoint_t* endpoint); above?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My mistake, same fucntions

Comment on lines +251 to +252
int unicoap_messaging_process_rfc7252(const uint8_t* pdu, size_t size, bool truncated,
unicoap_packet_t* packet);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this missing a "Mark: extension point driver"?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes

Copy link
Contributor

@mguetschow mguetschow left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've now gone once through all files, consider this a first round and feel free to start pushing fixups :)

{
(void)event;
sock_dtls_session_t session;
if (dsm_get_num_available_slots() < CONFIG_UNICOAP_DTLS_MINIMUM_AVAILABLE_SESSIONS) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I still find the naming of the constant confusing.

sizeof(unicoap_receiver_buffer),
CONFIG_UNICOAP_DTLS_HANDSHAKE_TIMEOUT_MS);
_UNICOAP_DEBUG_HEX(unicoap_receiver_buffer, res);
DEBUG("^ this really looks like a PDU...\n");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how could you tell? :P (consider removing)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

True, this is from when DTLS stopped working during some hack n ack

dsm_state_t prev_state = dsm_store(sock, &session, SESSION_STATE_ESTABLISHED, false);

/* If session is already stored and the state was SESSION_STATE_HANDSHAKE
before, the handshake has been initiated internally by a gcoap client request
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
before, the handshake has been initiated internally by a gcoap client request
before, the handshake has been initiated internally by a unicoap client request

is this still true though?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we shall not relapse


unicoap_endpoint_t endpoint = { .proto = UNICOAP_PROTO_DTLS };
sock_dtls_session_get_udp_ep(&session, unicoap_endpoint_get_dtls(&endpoint));
unicoap_exchange_forget_failed_endpoint(&endpoint);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why failed? Couldn't it just be a finished connection?

unicoap_packet_t packet = { .remote = &remote, .dtls_session = &session };

#if IS_ACTIVE(CONFIG_UNICOAP_GET_LOCAL_ENDPOINTS)
unicoap_endpoint_t local = { .proto = UNICOAP_PROTO_UDP };
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why UDP? if on purpose, please add an explaining comment.

{
/* generate initial notification value */
return unicoap_options_set_observe(
options, (ztimer_now(ZTIMER_MSEC) >> UNICOAP_OBS_TICK_EXPONENT) & 0xFFFFFF);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
options, (ztimer_now(ZTIMER_MSEC) >> UNICOAP_OBS_TICK_EXPONENT) & 0xFFFFFF);
options, (ztimer_now(UNICOAP_CLOCK) >> UNICOAP_OBS_TICK_EXPONENT) & 0xFFFFFF);

? Also, why is this part of state.c?

Comment on lines +423 to +426
unicoap_link_encoder_ctx_t ctx;
ctx.content_format = UNICOAP_FORMAT_LINK;
/* indicate initial link for the list */
ctx.uninitialized = true;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
unicoap_link_encoder_ctx_t ctx;
ctx.content_format = UNICOAP_FORMAT_LINK;
/* indicate initial link for the list */
ctx.uninitialized = true;
unicoap_link_encoder_ctx_t ctx = {
.content_format = UNICOAP_FORMAT_LINK,
/* indicate initial link for the list */
.uninitialized = true,
}

why not?

continue;
}
ssize_t res;
if (out) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

buffer is not documented to be allowed as NULL.

Comment on lines +478 to +482
/* The Uri-Path options are longer than
* CONFIG_UNIOCOAP_PATH_SIZE_MAX, and thus do not match anything
* that could be found by this handler. */
SERVER_DEBUG("could not copy Uri-Path\n");
return UNICOAP_STATUS_PATH_NOT_FOUND;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we instead fall-back to the less efficient options parsing approach?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

but that would scale horribly if you have multiple resources wouldn’t it

why would you prefer the less efficient version instead

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, but only if the path is too long to fit in the buffer.

(*resource_ptr)->flags & UNICOAP_RESOURCE_FLAG_MATCH_SUBTREE ? "/**" : "",
unicoap_string_from_method(unicoap_request_get_method(packet->message)));
break;
case UNICOAP_STATUS_PATH_NOT_FOUND:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this cannot happen, since ret is only set to res in case of UNICOAP_STATUS_METHOD_NOT_ALLOWED.

```

where `fe80::c0:ff:ee` is the IPv6 address of the RIOT interface behind the tap interface.
If you run the `examples/default` shell application and type `ifconfig` you should see a list of
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
If you run the `examples/default` shell application and type `ifconfig` you should see a list of
If you run the `examples/basic/default` shell application and type `ifconfig` you should see a list of

also, that one didn't show me the IP address, I used examples/networking/gnrc/gnrc_networking for this purpose.

@mguetschow
Copy link
Contributor

One test datapoint:

$ python3 examples/networking/coap/unicoap_server/client.py -m GET -u "coap://[fe80::5c64:bbff:fe11:9231%tap0]/" 
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
DEBUG:coap-server:Server ready to receive requests
DEBUG:coap-server:Sending request - Token: 1d4c, Remote: <UDP6EndpointAddress [fe80::5c64:bbff:fe11:9231%tap0] (locally ::%tap0)>
DEBUG:coap-server:Sending message <aiocoap.Message at 0x7fbaf33c74d0: NON GET (MID 43720, token 1d4c) remote <UDP6EndpointAddress [fe80::5c64:bbff:fe11:9231%tap0] (locally ::%tap0)>>
DEBUG:coap-server:Incoming message <aiocoap.Message at 0x7fbaf33ded90: CON 4.00 Bad Request (MID 4769, token 1d4c) remote <UDP6EndpointAddress [fe80::5c64:bbff:fe11:9231%tap0] (locally fe80::5c64:bbff:fe11:9230%tap0)>>
DEBUG:coap-server:Received Response: <aiocoap.Message at 0x7fbaf33ded90: CON 4.00 Bad Request (MID 4769, token 1d4c) remote <UDP6EndpointAddress [fe80::5c64:bbff:fe11:9231%tap0] (locally fe80::5c64:bbff:fe11:9230%tap0)>>
DEBUG:coap-server:Response <aiocoap.Message at 0x7fbaf33ded90: CON 4.00 Bad Request (MID 4769, token 1d4c) remote <UDP6EndpointAddress [fe80::5c64:bbff:fe11:9231%tap0] (locally fe80::5c64:bbff:fe11:9230%tap0)>> matched to request <Pipe at 0x7fbaf33dec90 around <aiocoap.Message at 0x7fbaf33c74d0: NON GET (MID 43720, token 1d4c) remote <UDP6EndpointAddress [fe80::5c64:bbff:fe11:9231%tap0] (locally ::%tap0)>> with 2 callbacks (thereof 1 interests)>
DEBUG:coap-server:Sending empty ACK: acknowledging incoming response
DEBUG:coap-server:Sending message <aiocoap.Message at 0x7fbaf331e990: ACK EMPTY (MID 4769, empty token) remote <UDP6EndpointAddress [fe80::5c64:bbff:fe11:9231%tap0] (locally fe80::5c64:bbff:fe11:9230%tap0)>>
response: 4.00 Bad Request
b''
2025-07-15 09:53:50,226 # coap.messaging.rfc7252: received <NON REQ mid=43720 token=1D4C code=0.01 GET payload=(0 bytes) options=(0; 0 bytes)>
2025-07-15 09:53:50,226 # coap.messaging: received in channel:
2025-07-15 09:53:50,226 #       remote=UDP <sock_tl_ep port=5600 netif=7 ipv6=fe80::5c64:bbff:fe11:9230>
2025-07-15 09:53:50,227 #       local=UDP <sock_tl_ep port=5683 netif=0 ipv6=fe80::5c64:bbff:fe11:9231>
2025-07-15 09:53:50,227 # coap.server: /greeting: found
2025-07-15 09:53:50,227 # coap.server: invoking handler
2025-07-15 09:53:50,227 # app: GET /greeting, 0 bytes
2025-07-15 09:53:50,227 # error: could not get 'name' query: -2 (No such file or directory)
2025-07-15 09:53:50,227 # coap.server: sending response 4.00 from return value
2025-07-15 09:53:50,227 # coap.messaging: sending in channel:
2025-07-15 09:53:50,227 #       remote=UDP <sock_tl_ep port=5600 netif=7 ipv6=fe80::5c64:bbff:fe11:9230>
2025-07-15 09:53:50,227 #       local=UDP <sock_tl_ep port=5683 netif=0 ipv6=fe80::5c64:bbff:fe11:9231>
2025-07-15 09:53:50,227 # coap.messaging.rfc7252: sending <CON RESP mid=4769 token=1D4C code=4.00 Bad Request payload=(0 bytes) options=(0; 0 bytes)>
2025-07-15 09:53:50,227 # coap.transport.udp: sendv: 6 bytes
2025-07-15 09:53:50,227 # coap.messaging.rfc7252: <carbon_copy size=6>
2025-07-15 09:53:50,227 # coap.messaging.rfc7252: received <ACK EMPTY mid=4769 token= code=0.00 Empty payload=(0 bytes) options=(0; 0 bytes)>
2025-07-15 09:53:50,228 # coap.messaging.rfc7252: [MID 4769] received ACK, stopping retransmission
2025-07-15 09:53:50,228 # coap.messaging.rfc7252: [MID 4769] transmission ended

@carl-tud carl-tud removed the CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR label Jul 17, 2025
@carl-tud
Copy link
Contributor Author

@mguetschow You forgot the ?name= query parameter. Hence, the application, as expected, responds throws a 400.

@carl-tud
Copy link
Contributor Author

@mguetschow You forgot the ?name= query parameter. Hence, the application, as expected, responds throws a 400.

Okay, maybe this is stupid.

@mguetschow
Copy link
Contributor

@mguetschow You forgot the ?name= query parameter. Hence, the application, as expected, responds throws a 400.

But I tried to get the root resource which does not require query parameters:

$ python3 examples/networking/coap/unicoap_server/client.py -m GET -u "coap://[fe80::5c64:bbff:fe11:9231%tap0]/"

(TL;DR: something in the resource matching is off)

```
This will compile and run the application.

Then, create a tap interface (to which RIOT will connect):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't you need to create the tap interface first?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area: build system Area: Build system Area: CoAP Area: Constrained Application Protocol implementations Area: doc Area: Documentation Area: examples Area: Example Applications Area: Kconfig Area: Kconfig integration Area: network Area: Networking Area: sys Area: System Type: new feature The issue requests / The PR implemements a new feature for RIOT
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants