COAP_RESOURCE(3)
π NAME π
okay so this is coap_resource(3) from the libcoap Manual, and itβs literally the whole resource-management friend group. The squad is: coap_resource, coap_resource_init, coap_resource_unknown_init, coap_resource_unknown_init2, coap_resource_proxy_uri_init, coap_resource_proxy_uri_init2, coap_resource_reverse_proxy_init, coap_add_resource, coap_delete_resource, coap_resource_set_mode, coap_resource_set_userdata, coap_resource_get_userdata, coap_resource_release_userdata_handler, coap_resource_get_uri_path, coap_get_resource_from_uri_path, and coap_print_wellknown β all here to work with CoAP resources β¨.
π SYNOPSIS π
#include <coap3/coap.h>
coap_resource_t *coap_resource_init(coap_str_const_t *uri_path, int flags);
coap_resource_t *coap_resource_unknown_init(coap_method_handler_t put_handler);
coap_resource_t *coap_resource_unknown_init2(coap_method_handler_t put_handler, int flags);
coap_resource_t *coap_resource_proxy_uri_init(coap_method_handler_t proxy_handler, size_t host_name_count, const char *host_name_list[]);
coap_resource_t *coap_resource_proxy_uri_init2(coap_method_handler_t proxy_handler, size_t host_name_count, const char *host_name_list[], int flags);
coap_resource_t *coap_resource_reverse_proxy_init(coap_method_handler_t rev_proxy_handler, int flags);
void coap_add_resource(coap_context_t *context, coap_resource_t *resource);
int coap_delete_resource(coap_context_t *context, coap_resource_t *resource);
void coap_resource_set_mode(coap_resource_t *resource, int mode);
void coap_resource_set_userdata(coap_resource_t *resource, void *data);
void *coap_resource_get_userdata(coap_resource_t *resource);
void coap_resource_release_userdata_handler(coap_context_t *context, coap_resource_release_userdata_handler_t callback);
coap_str_const_t *coap_resource_get_uri_path(coap_resource_t *resource);
coap_resource_t *coap_get_resource_from_uri_path(coap_context_t *context, coap_str_const_t *uri_path);
coap_print_status_t coap_print_wellknown(coap_context_t *context, unsigned char *buf, size_t *buflen, size_t offset, const coap_string_t *query_filter);
For specific (D)TLS library support, link with -lcoap-3-notls, -lcoap-3-gnutls, -lcoap-3-openssl, -lcoap-3-mbedtls, -lcoap-3-wolfssl or -lcoap-3-tinydtls. Otherwise, link with -lcoap-3 to get the default (D)TLS library support. π«Ά
π¬ DESCRIPTION π¬
CoAP resources on a CoAP Server are these little living entries that need to be created, updated, and deleted as appropriate. The URI in the request packet is what defines the resource to work with β and possibly the Query or data in the request is referring to a sub-resource. Slay. π
When resources are configured on the CoAP server, the URI to match against in the request packet is specified.
Callback Handlers are then added to the resource to handle the different request methods. See coap_register_request_handler(3) for further information.
Adding Attributes lets you put textual information onto the resource, and that can then be reported back to any client doing a GET .well-known/core request. See coap_add_attr(3) for further information.
If an incoming packet request matches a resourceβs URI and Method, then the appropriate callback resource handler is invoked to process the packet β and it should then update a suitable response packet for returning back to the requester.
There is support for handling incoming packets where the URI is unknown (no specific resource has been created). This could, for example, happen when a PUT request is trying to create a new resource. It is the responsibility of the unknown resource callback handler to either create a new resource for the URI or just manage things separately.
CoAP Observe (RFC7641) is not supported for unknown resources, so a new resource with GET handler must be created by the unknown resource callback handle matching the URI which then can be Observable. No cap.
There is support for handling incoming proxy based requests using the Proxy-Uri or Proxy-Scheme options. obsessed.
π οΈ FUNCTIONS π οΈ
β¨ Function: coap_resource_init() β¨
The coap_resource_init() function returns a newly created resource of type coap_resource_t *. uri_path specifies the uri string path to match against. Normally there is no need for the leading / β e.g. just "full/path/for/resource". flags can be zero or more of the following definitions ORβd together:
COAP_RESOURCE_FLAGS_NOTIFY_NONβ Set the notification message type to non-confirmable for any triggered "observe" responses with type set to confirmable every 5 packets as required by "RFC7641 4.5. Transmission". Seecoap_observe(3). NOTE: This flag is ignored ifCOAP_RESOURCE_FLAGS_NOTIFY_CONis set.COAP_RESOURCE_FLAGS_NOTIFY_NON_ALWAYSβ Set the notification message type to always non-confirmable for any triggered "observe" responses. This should only be used if a upper layer protocol requires it. Seecoap_observe(3). NOTE: This flag is ignored ifCOAP_RESOURCE_FLAGS_NOTIFY_CONis set.COAP_RESOURCE_FLAGS_NOTIFY_CONβ Set the notification message type to confirmable for any triggered "observe" responses. Seecoap_observe(3). NOTE:COAP_RESOURCE_FLAGS_NOTIFY_NONis assumed ifCOAP_RESOURCE_FLAGS_NOTIFY_CONis not set.COAP_RESOURCE_FLAGS_RELEASE_URIβ Free off thecoap_str_const_tforuri_pathwhen the resource is deleted.COAP_RESOURCE_FLAGS_FORCE_SINGLE_BODYβ Force all large traffic to this resource to be presented as a single body to the request handler.COAP_RESOURCE_FLAGS_OSCORE_ONLYβ Define this resource as an OSCORE enabled access only.COAP_RESOURCE_HANDLE_WELLKNOWN_COREβ Define this when invokingcoap_resource_unknown_init2()if.well-known/coreis to be passed to the unknown URI handler rather than processed locally. Used for easily passing on a request as a reverse-proxy request.
NOTE: The following flags are only tested against ifcoap_mcast_per_resource()has been called. Ifcoap_mcast_per_resource()has not been called, then all resources have multicast support, libcoap adds in random delays to the responses, and4.xx/5.xxresponses are dropped. π
NOTE: The pseudo resource for.well-known/corealways has multicast support enabled and is not configurable. It is possible for a server to create a resource for.well-known/corethat can then control the multicast support and the provided GET request handler can callcoap_print_wellknown()to produce the same information as the pseudo resource.
COAP_RESOURCE_FLAGS_HAS_MCAST_SUPPORTβ This resource has support for multicast requests.COAP_RESOURCE_FLAGS_LIB_DIS_MCAST_DELAYSβ Disable libcoap library from adding in delays to multicast requests before sending the response back to the client. It is then the responsibility of the app to delay the responses for multicast requests. See "RFC7252 8.2. Request/Response Layer". However, the pseudo resource for.well-known/corealways has multicast support enabled.COAP_RESOURCE_FLAGS_LIB_ENA_MCAST_SUPPRESS_2_05β Enable libcoap library suppression of205multicast responses that are empty (overridden byRFC7967No-Response option) for multicast requests.COAP_RESOURCE_FLAGS_LIB_ENA_MCAST_SUPPRESS_2_XXβ Enable libcoap library suppressing2.xxmulticast responses (overridden byRFC7967No-Response option) for multicast requests.COAP_RESOURCE_FLAGS_LIB_DIS_MCAST_SUPPRESS_4_XXβ Disable libcoap library suppressing4.xxmulticast responses (overridden byRFC7967No-Response option) for multicast requests.COAP_RESOURCE_FLAGS_LIB_DIS_MCAST_SUPPRESS_5_XXβ bestie, this one turns OFF libcoap's built-in habit of suppressing 5.xx multicast responses (and yes, the RFC7967 No-Response option overrides this anyway) for multicast requests π
β οΈ NOTE: ifuri_pathisn't 7-bit readable ASCII, then those binary bytes have to be hex encoded per the rules in"RFC3986 2.1. Percent-Encoding"β no shortcuts, fr fr πΈ
Function: coap_resource_unknown_init()
Returns a shiny newly-created resource of type coap_resource_t *. A put_handler gets automatically added onto it so it can handle PUT requests to resources that are, well... unknown π«Ά. You can still bolt on extra handlers to this resource if you need them β it's not a one-trick pony.
Function: coap_resource_unknown_init2()
Same energy as above: returns a brand new resource of type coap_resource_t *, put_handler is auto-added to catch PUT requests for unknown resources, and extra handlers can be added if you want β¨. The difference is flags, which can be zero or more of the COAP_RESOURCE_FLAGS MCAST definitions.
π NOTE: there can only be one reverse-proxy or unknown resource handler per context β attaching a new one just overrides the previous definition. So like, choose wisely π
Function: coap_resource_proxy_uri_init()
Returns a newly created resource of type coap_resource_t *. A proxy_handler is automatically added to it to handle PUT/POST/GET etc. requests that use the Proxy-Uri option β so no need to add explicit request-type handlers yourself, it's already got you π. One or more names the proxy is known by (IP address, DNS name etc.) must be supplied in the array defined by host_name_list[], which has a count of host_name_count. That list is what gets checked to figure out whether the current endpoint is the proxy target address, or whether the request has to be passed on to an upstream server. iykyk π
Function: coap_resource_proxy_uri_init2()
Exactly the proxy vibes as coap_resource_proxy_uri_init() β returns a new resource of type coap_resource_t *, proxy_handler auto-added to handle PUT/POST/GET etc. requests using the Proxy-Uri option, no explicit request-type handlers needed, and the names (IP address, DNS name etc.) go in the array defined by host_name_list[] with count host_name_count so it can tell if the current endpoint is the proxy target address or if the request must be passed upstream π₯. On top of that, flags can be zero or more COAP_RESOURCE_FLAGS MCAST definitions.
π NOTE: only one proxy resource handler per context, bestie β attach a new one and the old definition is gone. Overridden. Poof π¦
Function: coap_resource_reverse_proxy_init()
Returns a newly created resource of type coap_resource_t *. This time a rev_proxy_handler gets automatically added, and it handles all the PUT/POST/GET etc. requests, including .well-known/core β the whole menu, no cap π. No need to add explicit request type handlers. And flags can be zero or more COAP_RESOURCE_FLAGS MCAST definitions.
π NOTE: only one reverse-proxy or unknown resource handler per context β attaching a new one overrides the previous definition, periodt.
Function: coap_add_resource()
Registers the resource you hand it with the context π. That resource must have been created by coap_resource_init(), coap_resource_unknown_init(), coap_resource_unknown_init2(), coap_resource_proxy_uri_init() or coap_resource_proxy_uri_init2() β don't try to sneak in anything else π. The storage allocated for the resource gets released by coap_delete_resource().
And because the uri_path of a resource has to be unique across all the resources associated with a context, coap_add_resource() will delete any previous resource with the same uri_path before adding in the new one. Out with the old, in with the new π
Function: coap_delete_resource()
Deletes the resource identified by resource. Fun fact: the context parameter is straight-up ignored π. The storage allocated for that resource gets freed, along with any attributes associated with it. Clean slate β¨
Function: coap_resource_set_mode()
Changes the unsolicited notification message type of resource to the given mode, and that mode has to be one of COAP_RESOURCE_FLAGS_NOTIFY_NON, COAP_RESOURCE_FLAGS_NOTIFY_NON_ALWAYS or COAP_RESOURCE_FLAGS_NOTIFY_CON. Those three, that's the list, no substitutions π
Function: coap_resource_set_userdata()
Lets you associate a pointer to user data with a resource, and you can access it in any callback that includes resource as a parameter π«Ά. Super handy.
β οΈ NOTE: data must point to a static, or allocated, block of memory. Do not be out here pointing at stack locals, bestie π
Function: coap_resource_get_userdata()
Grabs the user data pointer off the resource β the same one you previously set up with coap_resource_set_userdata(). Round trip complete πΈ
Function: coap_resource_release_userdata_handler()
Defines the context-wide callback handler that gets called to release the allocated user data you added to the resource using coap_resource_set_userdata() when that resource is deleted π§. And callback can be NULL (which is the default) if there's nothing that needs freeing off. No leaks on her watch π
Function: coap_resource_get_uri_path()
Used to obtain the UriPath of the resource definition. That's it, that's the function β
Function: coap_get_resource_from_uri_path()
Returns the resource identified by the unique string uri_path associated with context. Like a little lookup, but make it iconic π
Function: coap_print_wellknown()
Prints the names of all the known resources of the given context into buf, which has a maximum size of buflen π. The first offset bytes are skipped from the output so block transfers can be handled β setting offset to 0 means the entire (matching) info gets output. Setting offset to UINT_MAX skips the (matching) output but calculates its size. And query_filter is usually defined by the CoAP Uri-Query options as a query. Big brain energy, honestly π§ β¨
π RETURN VALUES π
Okay so here's who returns what, because this part matters:
coap_resource_init(),coap_resource_unknown_init(),coap_resource_unknown_init2(),coap_resource_proxy_uri_init(),coap_resource_proxy_uri_init2()andcoap_resource_reverse_proxy_init()all return a newly created resource, orNULLif there's amallocfailure πcoap_delete_resource()returns0on failure (resource not found),1on success πcoap_resource_get_userdata()returns the value previously set by thecoap_resource_set_userdata()function, orNULLπ«Άcoap_resource_get_uri_path()returns theuri_path, orNULLif there was a failure πcoap_get_resource_from_uri_path()returns the resource, orNULLif it wasn't found πcoap_print_wellknown()returnsCOAP_PRINT_STATUS_ERRORon error. Otherwise, the lower 28 bits are set to the number of bytes that have actually been written, andCOAP_PRINT_STATUS_TRUNCis set when the output has been truncated βοΈ
π‘ tl;dr β if you seeNULL, something went wrong; if you see0fromcoap_delete_resource(), the resource wasn't there. Everything else is vibes and byte counts π
β¨ EXAMPLES β¨
Okay so, examples time, bestie β this is where the page shows the actual setups in code. Itβs giving βcopy this energy,β and every line below is kept exactly as the example gods intended. No cap. π«Ά
π Fixed Resources Set Up π
First up: the fixed-resource setup. The code is doing its thing, and the snippet is here in full:
#include <coap3/coap.h>
#define INDEX "This is an example server using libcoap\n"
static void
hnd_get_index(coap_resource_t *resource, coap_session_t *session,
const coap_pdu_t *request, const coap_string_t *query,
coap_pdu_t *response) {
unsigned char buf[3];
/* Remove (void) definition if variable is used */
(void)resource;
(void)session;
(void)request;
(void)query;
coap_pdu_set_code(response, COAP_RESPONSE_CODE_CONTENT);
coap_add_option(response,
COAP_OPTION_CONTENT_TYPE,
coap_encode_var_safe(buf, sizeof(buf),
COAP_MEDIATYPE_TEXT_PLAIN),
buf);
coap_add_option(response,
COAP_OPTION_MAXAGE,
coap_encode_var_safe(buf, sizeof(buf), 0x2ffff), buf);
coap_add_data(response, strlen(INDEX), (const uint8_t *)INDEX);
coap_pdu_set_code(response, COAP_RESPONSE_CODE_CONTENT);
}
static void
hnd_delete_time(coap_resource_t *resource, coap_session_t *session,
const coap_pdu_t *request, const coap_string_t *query,
coap_pdu_t *response) {
/* Remove (void) definition if variable is used */
(void)resource;
(void)session;
(void)request;
(void)query;
/* .. code .. */
coap_pdu_set_code(response, COAP_RESPONSE_CODE_DELETED);
}
static void
hnd_get_time(coap_resource_t *resource, coap_session_t *session,
const coap_pdu_t *request, const coap_string_t *query,
coap_pdu_t *response) {
/* Remove (void) definition if variable is used */
(void)resource;
(void)session;
(void)request;
(void)query;
(void)response;
/* .. code .. */
coap_pdu_set_code(response, COAP_RESPONSE_CODE_CONTENT);
}
static void
hnd_put_time(coap_resource_t *resource, coap_session_t *session,
const coap_pdu_t *request, const coap_string_t *query,
coap_pdu_t *response) {
/* Remove (void) definition if variable is used */
(void)resource;
(void)session;
(void)request;
(void)query;
(void)response;
/* .. code .. */
coap_pdu_set_code(response, COAP_RESPONSE_CODE_CHANGED);
}
static void
init_resources(coap_context_t *ctx) {
coap_resource_t *r;
/* Create a resource to return general information */
r = coap_resource_init(NULL, 0);
coap_register_request_handler(r, COAP_REQUEST_GET, hnd_get_index);
/* Document resource for '.well-known/core' request */
coap_add_attr(r, coap_make_str_const("ct"), coap_make_str_const("0"), 0);
coap_add_attr(r, coap_make_str_const("title"),
coap_make_str_const("\"General Info\""), 0);
coap_add_resource(ctx, r);
/* Create a resource to return return or update time */
r = coap_resource_init(coap_make_str_const("time"),
COAP_RESOURCE_FLAGS_NOTIFY_CON);
coap_resource_set_get_observable(r, 1);
coap_register_request_handler(r, COAP_REQUEST_GET, hnd_get_time);
coap_register_request_handler(r, COAP_REQUEST_PUT, hnd_put_time);
coap_register_request_handler(r, COAP_REQUEST_DELETE, hnd_delete_time);
/* Document resource for 'time' request */
coap_add_attr(r, coap_make_str_const("ct"), coap_make_str_const("0"), 0);
coap_add_attr(r, coap_make_str_const("title"),
coap_make_str_const("\"Internal Clock\""), 0);
coap_add_attr(r, coap_make_str_const("rt"), coap_make_str_const("\"secs\""),
0);
coap_add_attr(r, coap_make_str_const("if"), coap_make_str_const("\"clock\""),
0);
coap_add_resource(ctx, r);
}
π¦ Dynamic Resources Set Up π¦
Next up: the dynamic-resource setup. This one is the whole handler-heavy moment, and hereβs the example in full:
#include <coap3/coap.h>
/* Regular DELETE handler - used by resources created by the
* Unknown Resource PUT handler */
static void
hnd_delete(coap_resource_t *resource, coap_session_t *session,
const coap_pdu_t *request, const coap_string_t *query,
coap_pdu_t *response) {
/* Remove (void) definition if variable is used */
(void)session;
(void)request;
(void)query;
(void)response;
/* .. code .. */
/* Dynamic resource no longer required - delete it */
coap_delete_resource(NULL, resource);
coap_pdu_set_code(response, COAP_RESPONSE_CODE_DELETED);
}
/* Regular GET handler - used by resources created by the
* Unknown Resource PUT handler */
static void
hnd_get(coap_resource_t *resource, coap_session_t *session,
const coap_pdu_t *request, const coap_string_t *query,
coap_pdu_t *response) {
coap_str_const_t *get_uri_path;
/* Remove (void) definition if variable is used */
(void)resource;
(void)session;
(void)request;
(void)query;
/*
* Get the specific resource being requested to determine what the response is
* The uri_path string is a const pointer
*/
get_uri_path = coap_resource_get_uri_path(resource);
/* .. code .. */
coap_pdu_set_code(response, COAP_RESPONSE_CODE_CONTENT);
}
/* Regular PUT handler - used by resources created by the
* Unknown Resource PUT handler */
static void
hnd_put(coap_resource_t *resource, coap_session_t *session,
const coap_pdu_t *request, const coap_string_t *query,
coap_pdu_t *response) {
/* Remove (void) definition if variable is used */
(void)resource;
(void)session;
(void)query;
coap_string_t *put_uri_path;
size_t length;
const uint8_t *data;
size_t offset;
size_t total;
int new_resource = 0;
/* get the uri_path */
put_uri_path = coap_get_uri_path(request);
if (!put_uri_path) {
coap_pdu_set_code(response, COAP_RESPONSE_CODE_NOT_FOUND);
return;
}
coap_get_data_large(request, &length, &data, &offset, &total);
/* .. code .. */
/* Need to do this as coap_get_uri_path() created it */
coap_delete_string(put_uri_path);
if (length + offset < total)
coap_pdu_set_code(response, COAP_RESPONSE_CODE_CONTINUE);
else if (new_resource)
coap_pdu_set_code(response, COAP_RESPONSE_CODE_CREATED);
else
coap_pdu_set_code(response, COAP_RESPONSE_CODE_CHANGED);
}
static int
check_url_fn(coap_string_t *uri_path, uint8_t code) {
/* Remove (void) definition if variable is used */
(void)uri_path;
(void)code;
/* Code to determine whether the uri is valid or not */
return 1;
}
/* Unknown Resource PUT handler */
static void
hnd_put_unknown(coap_resource_t *resource, coap_session_t *session,
const coap_pdu_t *request, const coap_string_t *query,
coap_pdu_t *response) {
/* Remove (void) definition if variable is used */
(void)resource;
coap_pdu_code_t req_code = coap_pdu_get_code(request);
coap_resource_t *r;
coap_string_t *uri_path;
/* get the uri_path - which will get used by coap_resource_init() */
uri_path = coap_get_uri_path(request);
if (!uri_path) {
coap_pdu_set_code(response, COAP_RESPONSE_CODE_NOT_FOUND);
return;
}
/* Check if new URI Path is valid */
if (!check_url_fn(uri_path, req_code)) {
coap_pdu_set_code(response, COAP_RESPONSE_CODE_NOT_FOUND);
coap_delete_string(uri_path);
return;
}
/*
* Create a resource to handle the new URI
* uri_path will get deleted when the resource is removed
*/
r = coap_resource_init((coap_str_const_t *)uri_path,
COAP_RESOURCE_FLAGS_RELEASE_URI | COAP_RESOURCE_FLAGS_NOTIFY_NON);
coap_register_request_handler(r, COAP_REQUEST_PUT, hnd_put);
coap_register_request_handler(r, COAP_REQUEST_DELETE, hnd_delete);
/* We possibly want to Observe the GETs */
coap_resource_set_get_observable(r, 1);
coap_register_request_handler(r, COAP_REQUEST_GET, hnd_get);
coap_add_resource(coap_session_get_context(session), r);
/* Do the PUT for this first call */
hnd_put(r, session, request, query, response);
return;
}
/* Initialize single Unknown Resource PUT handler */
static void
init_resources(coap_context_t *ctx) {
coap_resource_t *r;
/* Create a resource to handle PUTs to unknown URIs */
r = coap_resource_unknown_init2(hnd_put_unknown, 0);
/*
* Additional handlers can be added - for example
* coap_register_request_handler(r, COAP_REQUEST_POST, hnd_post_unknown);
* coap_register_request_handler(r, COAP_REQUEST_GET, hnd_get_unknown);
* coap_register_request_handler(r, COAP_REQUEST_DELETE, hnd_delete_unknown);
*/
coap_add_resource(ctx, r);
}
π SEE ALSO π
Bestie, go peek at coap_attribute(3), coap_context(3), coap_handler(3) and coap_observe(3) β thatβs the little friend group this page points you toward. π
π FURTHER INFORMATION π
For the deep lore, see:
"RFC7252: The Constrained Application Protocol (CoAP)"
"RFC3986: Uniform Resource Identifier (URI): Generic Syntax"
for further information. β¨
π BUGS π
Please raise an issue on GitHub at https://github.com/obgm/libcoap/issues to report any bugs. π
Please raise a Pull Request at https://github.com/obgm/libcoap/pulls for any fixes. π«Ά
π AUTHORS π
The libcoap project <libcoap-developers@lists.sourceforge.net> π
One last cute lilβ sign-off: this page is serving coap_resource 4.3.5, dated 08/24/2026, and itβs chillinβ as COAP_RESOURCE(3). Slay. π
π
π¦ where this page comes from
- ubuntu stonking: libcoap3t64 4.3.5-4ubuntu1 Β· BSD-2-Clause
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms