Skip to content
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

nanocoap: define and use coap_request_ctx_t for request handlers #17957

Merged
merged 8 commits into from
Jul 17, 2022

Conversation

benpicco
Copy link
Contributor

@benpicco benpicco commented Apr 15, 2022

Contribution description

Currently a resource handler has no information about the resource it handles.
This leads to awkward work-around such as specifying the resource path in the user context again.

To avoid this, introduce a coap_resource_ctx_t struct that contains the user context and the resource path, that can be easily extended if more context is needed in the future.

Testing procedure

All CoAP applications should still work.
Since the user context was usually NULL, most will not even notice a change.

Issues/PRs references

#14397 (comment)
Can provide an alternative to #16827 (and also move tl_type out of coap_pkt_t into coap_resource_ctx_t)

depends on !11

@benpicco benpicco requested a review from chrysn April 15, 2022 19:21
@github-actions github-actions bot added Area: CoAP Area: Constrained Application Protocol implementations Area: examples Area: Example Applications Area: network Area: Networking Area: OTA Area: Over-the-air updates Area: sys Area: System Area: tests Area: tests and testing framework labels Apr 15, 2022
@benpicco benpicco added the CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR label Apr 15, 2022
@benpicco benpicco requested a review from fabian18 April 17, 2022 21:30
@fabian18
Copy link
Contributor

fabian18 commented Apr 18, 2022

The idea to present the resource path in a handler of a resource would only occur to me if there existed generic handlers, but usually a handler is written for a dedicated resource, so the path cast in stone.

const coap_resource_t coap_resources[] = {
    COAP_WELL_KNOWN_CORE_DEFAULT_HANDLER,
    { "/riot/board", COAP_GET, _riot_board_handler, NULL },

    /* this line adds the whole "/suit"-subtree */
    SUIT_COAP_SUBTREE,
};

Within _riot_board_handler we know that the path is "/riot/board".

Edit: Ok, but redefining a const char *path = "/my/resource" within _my_resource_handler() would theoretically duplicate the "" string, so it makes sense though.
Edit: Identical const char * are not duplicated, by the compiler.

I would keep it more general.

typedef struct {
    const coap_resource_t *resource;
} coap_request_ctx_t;
typedef ssize_t (*coap_handler_t)(coap_pkt_t *pkt, uint8_t *buf, size_t len,
                                  coap_request_ctx_t *context);

The name makes it possible to extend this struct with resource unrelated members, like endpoint addresses, as you have written in "Issues/PRs references".
And in the opposite direction, I would provide a coap_response_ctx_t which is constructed before memo->resp_handler() is called. But this has not to be done in this PR, I think.

@benpicco
Copy link
Contributor Author

benpicco commented Apr 18, 2022

The idea to present the resource path in a handler of a resource would only occur to me if there existed generic handlers, but usually a handler is written for a dedicated resource, so the path cast in stone.

The use case was the CoAP fileserver.
There you have a generic handler for e.g. /vfs that is then also going to be called for /vfs/path/to/file.

The fileserver is configured to serve a certain directory, e.g. /nvm0/srv

You can re-assemble the request path from the packet, but without knowing the resource there is no way to tell if you should now try to serve /nvm0/srv/vfs/path/to/file or /nvm0/srv/path/to/file.

I would keep it more general.

typedef struct {
    const coap_resource_t *resource;
} coap_request_ctx_t;

I thought that might generate a bit too much noise, but if there is a use case for the other fields of coap_resource_t this is of course pretty straightforward (and we can add helper functions for const char *coap_request_get_resource(const coap_resource_t *resource) to spare the user from typing out all the nested struct details.)

@benpicco benpicco changed the title nanocoap: define and use coap_resource_ctx_t for request handlers nanocoap: define and use coap_request_ctx_t for request handlers Apr 18, 2022
*
* @return Resource path of the request
*/
static inline const char *coap_request_get_path(const coap_resource_ctx_t *ctx)
Copy link
Contributor

Choose a reason for hiding this comment

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

I am not a big fan of get_member() functions. But they allow us to hide the details of coap_resource_ctx_t from the user, using just a forward declaration. Which is good to not cause API changes. Just having coap_request_get_resource() sufficient instead of ... get_path(), ...get_methods() and so on.

@fabian18
Copy link
Contributor

You forgot to update some functions:

static const coap_resource_t _resources[] = {
{ "/node/info", COAP_GET, _handler_info, NULL },
{ "/sense/hum", COAP_GET, _handler_dummy, NULL },
{ "/sense/temp", COAP_GET, _handler_dummy, NULL }
};

static const coap_resource_t resources[] = {
{ "/riot/bar", COAP_GET, handler_text, "foo" },
{ "/riot/foo", COAP_GET, handler_text, "bar" },
{ "/riot/info", COAP_GET, handler_info, NULL }
};

const coap_resource_t coap_resources[] = {
COAP_WELL_KNOWN_CORE_DEFAULT_HANDLER,
{ "/echo/", COAP_GET | COAP_MATCH_SUBTREE, _echo_handler, NULL },
{ "/riot/board", COAP_GET, _riot_board_handler, NULL },
{ "/riot/value", COAP_GET | COAP_PUT | COAP_POST, _riot_value_handler, NULL },
{ "/riot/ver", COAP_GET, _riot_block2_handler, NULL },
{ "/sha256", COAP_POST, _sha256_handler, NULL },
};

static ssize_t _forward_proxy_handler(coap_pkt_t* pdu, uint8_t *buf,
size_t len, void *ctx);

const coap_resource_t coap_resources[] = {
COAP_WELL_KNOWN_CORE_DEFAULT_HANDLER,
{ "/.well-known/edhoc", COAP_POST, _edhoc_handler, NULL },
};

const coap_resource_t coap_resources[] = {
COAP_WELL_KNOWN_CORE_DEFAULT_HANDLER,
{ "/flashwrite", COAP_POST, _flashwrite_handler, &_writer },
};

And if we decide to not expose the definition of coap_request_ctx_t to the user (which I would be in favor of), make use of the member access functions. But this would at latest be catched by the CI.

@fabian18 fabian18 removed the CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR label Apr 18, 2022
@fabian18
Copy link
Contributor

You may also squash if you like.

sys/include/net/nanocoap.h Show resolved Hide resolved
/**
* @brief CoAP resource request handler context
*/
struct _coap_request_ctx {
Copy link
Contributor

Choose a reason for hiding this comment

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

Shouldn't we have the order of the members swapped? Otherwise this would break applications that cast the user context, right?

Copy link
Contributor

@fabian18 fabian18 Apr 18, 2022

Choose a reason for hiding this comment

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

Applications cannot cast coap_request_ctx_t * to whatever they expect. But as of now, they can cast the void *context member of that struct to whatever they expect. But hiding the definition of coap_request_ctx_t and providing coap_request_get_context() would be better IMO.

Copy link
Contributor

Choose a reason for hiding this comment

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

Applications cannot cast coap_request_ctx_t * to whatever they expect

Yes, true. My bad. But then I'm worried this is a big API change for applications out there.

Copy link
Contributor

Choose a reason for hiding this comment

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

I think it is reasonable and beneficial. Users who are registering a function prototype with a void *context in their static const coap_resource_t _resources[] resource array are going to face a compilation error. And then they should look at the documentation and should be able to update the prototype.

Copy link
Member

Choose a reason for hiding this comment

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

But then I'm worried this is a big API change for applications out there.

There are pending use cases for an API change on this (like knowing which client requested this, esp. w/rt security). This change (that adds an extensible pointer) should be the one we need to compatibly add the others later.

@fabian18 fabian18 added the Process: needs >1 ACK Integration Process: This PR requires more than one ACK label Jun 10, 2022
@benpicco benpicco removed the CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR label Jun 10, 2022
Copy link
Contributor

@fabian18 fabian18 left a comment

Choose a reason for hiding this comment

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

Yup, this is good from my side. You may squash and on green Murdock I will give the first ACK.

@benpicco benpicco force-pushed the coap_resource_ctx_t branch from ee2f574 to 542916f Compare June 10, 2022 15:12
@benpicco benpicco added the CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR label Jun 10, 2022
@benpicco
Copy link
Contributor Author

@chrysn can this still make it into the next release?

@chrysn
Copy link
Member

chrysn commented Jul 11, 2022 via email

@benpicco
Copy link
Contributor Author

@chrysn so want to throw in a 2nd ACK? 😉

@benpicco benpicco added CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR and removed CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR labels Jul 17, 2022
@benpicco benpicco force-pushed the coap_resource_ctx_t branch from 542916f to 3806f7d Compare July 17, 2022 12:32
@benpicco
Copy link
Contributor Author

rebased to include #16705

Copy link
Member

@chrysn chrysn left a comment

Choose a reason for hiding this comment

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

The API change is warranted, and allows future evolution of the data provided to the handler without further API breaks.

Thanks, seconded.

@chrysn chrysn enabled auto-merge July 17, 2022 13:14
@chrysn chrysn merged commit eb12f44 into RIOT-OS:master Jul 17, 2022
@benpicco benpicco deleted the coap_resource_ctx_t branch July 17, 2022 14:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area: CoAP Area: Constrained Application Protocol implementations Area: examples Area: Example Applications Area: network Area: Networking Area: OTA Area: Over-the-air updates Area: sys Area: System Area: tests Area: tests and testing framework CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR Process: API change Integration Process: PR contains or issue proposes an API change. Should be handled with care. Process: needs >1 ACK Integration Process: This PR requires more than one ACK
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants