diff --git a/examples/gcoap/server.c b/examples/gcoap/server.c index 54b065b8a287..026bf5d0bd90 100644 --- a/examples/gcoap/server.c +++ b/examples/gcoap/server.c @@ -56,13 +56,13 @@ static const credman_credential_t credential = { }; #endif -static ssize_t _encode_link(const coap_resource_t *resource, char *buf, +static ssize_t _encode_link(const gcoap_resource_t *resource, char *buf, size_t maxlen, coap_link_encoder_ctx_t *context); static ssize_t _stats_handler(coap_pkt_t* pdu, uint8_t *buf, size_t len, void *ctx); static ssize_t _riot_board_handler(coap_pkt_t* pdu, uint8_t *buf, size_t len, void *ctx); /* CoAP resources. Must be sorted by path (ASCII order). */ -static const coap_resource_t _resources[] = { +static const gcoap_resource_t _resources[] = { { "/cli/stats", COAP_GET | COAP_PUT, _stats_handler, NULL }, { "/riot/board", COAP_GET, _riot_board_handler, NULL }, }; @@ -82,7 +82,7 @@ static gcoap_listener_t _listener = { /* Adds link format params to resource list */ -static ssize_t _encode_link(const coap_resource_t *resource, char *buf, +static ssize_t _encode_link(const gcoap_resource_t *resource, char *buf, size_t maxlen, coap_link_encoder_ctx_t *context) { ssize_t res = gcoap_encode_link(resource, buf, maxlen, context); if (res > 0) { diff --git a/sys/include/net/gcoap.h b/sys/include/net/gcoap.h index 13410fb7b53b..0cae0d83b4e6 100644 --- a/sys/include/net/gcoap.h +++ b/sys/include/net/gcoap.h @@ -48,7 +48,7 @@ * this by uncommenting the appropriate lines in gcoap's make file. * * gcoap allows an application to specify a collection of request resource paths - * it wants to be notified about. Create an array of resources (coap_resource_t + * it wants to be notified about. Create an array of resources (gcoap_resource_t * structs) ordered by the resource path, specifically the ASCII encoding of * the path characters (digit and capital precede lower case). Use * gcoap_register_listener() at application startup to pass in these resources, @@ -649,6 +649,32 @@ extern "C" { /** @} */ +/** + * @brief Resource handler type + * + * Functions that implement this must be prepared to be called multiple times + * for the same request, as the server implementations do not perform message + * deduplication. That optimization is [described in the CoAP + * specification](https://tools.ietf.org/html/rfc7252#section-4.5). + * + * This should be trivial for requests of the GET, PUT, DELETE, FETCH and + * iPATCH methods, as they are defined as idempotent methods in CoAP. + * + * For POST, PATCH and other non-idempotent methods, this is an additional + * requirement introduced by the contract of this type. + */ +typedef ssize_t (*gcoap_handler_t)(coap_pkt_t *pkt, uint8_t *rbuf, size_t rlen, void *context); + +/** + * @brief Type for CoAP resource entry + */ +typedef struct { + const char *path; /**< URI path of resource */ + coap_method_flags_t methods; /**< OR'ed methods this resource allows */ + gcoap_handler_t handler; /**< ptr to resource handler */ + void *context; /**< ptr to user defined context data */ +} gcoap_resource_t; + /** * @brief Context information required to write a resource link */ @@ -670,7 +696,7 @@ typedef struct { * @return count of bytes written to @p buf (or writable if @p buf is null) * @return -1 on error */ -typedef ssize_t (*gcoap_link_encoder_t)(const coap_resource_t *resource, char *buf, +typedef ssize_t (*gcoap_link_encoder_t)(const gcoap_resource_t *resource, char *buf, size_t maxlen, coap_link_encoder_ctx_t *context); /** @@ -701,14 +727,14 @@ typedef struct gcoap_listener gcoap_listener_t; * @return GCOAP_RESOURCE_ERROR on processing failure of the request */ typedef int (*gcoap_request_matcher_t)(gcoap_listener_t *listener, - const coap_resource_t **resource, + const gcoap_resource_t **resource, const coap_pkt_t *pdu); /** * @brief A modular collection of resources for a server */ struct gcoap_listener { - const coap_resource_t *resources; /**< First element in the array of + const gcoap_resource_t *resources; /**< First element in the array of * resources; must order alphabetically */ size_t resources_len; /**< Length of array */ gcoap_link_encoder_t link_encoder; /**< Writes a link for a resource */ @@ -775,7 +801,7 @@ struct gcoap_request_memo { */ typedef struct { sock_udp_ep_t *observer; /**< Client endpoint; unused if null */ - const coap_resource_t *resource; /**< Entity being observed */ + const gcoap_resource_t *resource; /**< Entity being observed */ uint8_t token[GCOAP_TOKENLEN_MAX]; /**< Client token for notifications */ unsigned token_len; /**< Actual length of token attribute */ } gcoap_observe_memo_t; @@ -971,7 +997,7 @@ static inline ssize_t gcoap_response(coap_pkt_t *pdu, uint8_t *buf, * @return GCOAP_OBS_INIT_UNUSED if no observer for resource */ int gcoap_obs_init(coap_pkt_t *pdu, uint8_t *buf, size_t len, - const coap_resource_t *resource); + const gcoap_resource_t *resource); /** * @brief Sends a buffer containing a CoAP Observe notification to the @@ -987,7 +1013,7 @@ int gcoap_obs_init(coap_pkt_t *pdu, uint8_t *buf, size_t len, * @return 0 if cannot send */ size_t gcoap_obs_send(const uint8_t *buf, size_t len, - const coap_resource_t *resource); + const gcoap_resource_t *resource); /** * @brief Provides important operational statistics @@ -1031,7 +1057,7 @@ int gcoap_get_resource_list(void *buf, size_t maxlen, uint8_t cf); * @return count of bytes written to @p buf (or writable if @p buf is null) * @return -1 on error */ -ssize_t gcoap_encode_link(const coap_resource_t *resource, char *buf, +ssize_t gcoap_encode_link(const gcoap_resource_t *resource, char *buf, size_t maxlen, coap_link_encoder_ctx_t *context); #if IS_USED(MODULE_GCOAP_DTLS) || defined(DOXYGEN) diff --git a/sys/net/application_layer/gcoap/gcoap.c b/sys/net/application_layer/gcoap/gcoap.c index 370b47a14279..5fdc765974ac 100644 --- a/sys/net/application_layer/gcoap/gcoap.c +++ b/sys/net/application_layer/gcoap/gcoap.c @@ -67,16 +67,16 @@ static void _expire_request(gcoap_request_memo_t *memo); static void _find_req_memo(gcoap_request_memo_t **memo_ptr, coap_pkt_t *pdu, const sock_udp_ep_t *remote, bool by_mid); static int _find_resource(const coap_pkt_t *pdu, - const coap_resource_t **resource_ptr, + const gcoap_resource_t **resource_ptr, gcoap_listener_t **listener_ptr); static int _find_observer(sock_udp_ep_t **observer, sock_udp_ep_t *remote); static int _find_obs_memo(gcoap_observe_memo_t **memo, sock_udp_ep_t *remote, coap_pkt_t *pdu); static void _find_obs_memo_resource(gcoap_observe_memo_t **memo, - const coap_resource_t *resource); + const gcoap_resource_t *resource); static int _request_matcher_default(gcoap_listener_t *listener, - const coap_resource_t **resource, + const gcoap_resource_t **resource, const coap_pkt_t *pdu); #if IS_USED(MODULE_GCOAP_DTLS) @@ -85,7 +85,7 @@ static void _dtls_free_up_session(void *arg); #endif /* Internal variables */ -const coap_resource_t _default_resources[] = { +const gcoap_resource_t _default_resources[] = { { "/.well-known/core", COAP_GET, _well_known_core_handler, NULL }, }; @@ -532,7 +532,7 @@ static void _cease_retransmission(gcoap_request_memo_t *memo) { static size_t _handle_req(coap_pkt_t *pdu, uint8_t *buf, size_t len, sock_udp_ep_t *remote) { - const coap_resource_t *resource = NULL; + const gcoap_resource_t *resource = NULL; gcoap_listener_t *listener = NULL; sock_udp_ep_t *observer = NULL; gcoap_observe_memo_t *memo = NULL; @@ -639,7 +639,7 @@ static size_t _handle_req(coap_pkt_t *pdu, uint8_t *buf, size_t len, } static int _request_matcher_default(gcoap_listener_t *listener, - const coap_resource_t **resource, + const gcoap_resource_t **resource, const coap_pkt_t *pdu) { uint8_t uri[CONFIG_NANOCOAP_URI_MAX]; @@ -658,7 +658,7 @@ static int _request_matcher_default(gcoap_listener_t *listener, for (size_t i = 0; i < listener->resources_len; i++) { *resource = &listener->resources[i]; - int res = coap_match_path(*resource, uri); + int res = coap_match_path((coap_resource_t *)*resource, uri); /* URI mismatch */ if (res > 0) { @@ -697,7 +697,7 @@ static int _request_matcher_default(gcoap_listener_t *listener, * resource was found. */ static int _find_resource(const coap_pkt_t *pdu, - const coap_resource_t **resource_ptr, + const gcoap_resource_t **resource_ptr, gcoap_listener_t **listener_ptr) { int ret = GCOAP_RESOURCE_NO_PATH; @@ -706,7 +706,7 @@ static int _find_resource(const coap_pkt_t *pdu, gcoap_listener_t *listener = _coap_state.listeners; while (listener) { - const coap_resource_t *resource; + const gcoap_resource_t *resource; int res = listener->request_matcher(listener, &resource, pdu); /* check next resource on mismatch */ @@ -908,7 +908,7 @@ static int _find_obs_memo(gcoap_observe_memo_t **memo, sock_udp_ep_t *remote, * resource[in] -- Resource to match */ static void _find_obs_memo_resource(gcoap_observe_memo_t **memo, - const coap_resource_t *resource) + const gcoap_resource_t *resource) { *memo = NULL; for (int i = 0; i < CONFIG_GCOAP_OBS_REGISTRATIONS_MAX; i++) { @@ -1249,7 +1249,7 @@ int gcoap_resp_init(coap_pkt_t *pdu, uint8_t *buf, size_t len, unsigned code) } int gcoap_obs_init(coap_pkt_t *pdu, uint8_t *buf, size_t len, - const coap_resource_t *resource) + const gcoap_resource_t *resource) { gcoap_observe_memo_t *memo = NULL; @@ -1280,7 +1280,7 @@ int gcoap_obs_init(coap_pkt_t *pdu, uint8_t *buf, size_t len, } size_t gcoap_obs_send(const uint8_t *buf, size_t len, - const coap_resource_t *resource) + const gcoap_resource_t *resource) { gcoap_observe_memo_t *memo = NULL; gcoap_socket_t socket; @@ -1352,7 +1352,7 @@ int gcoap_get_resource_list(void *buf, size_t maxlen, uint8_t cf) return (int)pos; } -ssize_t gcoap_encode_link(const coap_resource_t *resource, char *buf, +ssize_t gcoap_encode_link(const gcoap_resource_t *resource, char *buf, size_t maxlen, coap_link_encoder_ctx_t *context) { size_t path_len = strlen(resource->path); diff --git a/tests/unittests/tests-gcoap/tests-gcoap.c b/tests/unittests/tests-gcoap/tests-gcoap.c index 71c646457460..5077810864d9 100644 --- a/tests/unittests/tests-gcoap/tests-gcoap.c +++ b/tests/unittests/tests-gcoap/tests-gcoap.c @@ -25,13 +25,13 @@ /* * A test set of dummy resources. The resource handlers are set to NULL. */ -static const coap_resource_t resources[] = { +static const gcoap_resource_t resources[] = { { .path = "/act/switch", .methods = (COAP_GET | COAP_POST) }, { .path = "/sensor/temp", .methods = (COAP_GET) }, { .path = "/test/info/all", .methods = (COAP_GET) }, }; -static const coap_resource_t resources_second[] = { +static const gcoap_resource_t resources_second[] = { { .path = "/second/part", .methods = (COAP_GET)}, };