COAP_RESOURCE(3)
πΈ coap_resource β it's giving "let's talk about CoAP resources, bestie" π
okay so this is COAP_RESOURCE(3) from the libcoap Manual (section 3, iykyk), and we're about to become unreasonably knowledgeable about CoAP resources. grab a snack. π
β¨ NAME β¨
coap_resource, coap_resource_init, coap_resource_unknown_init, coap_add_resource, coap_delete_resource, coap_delete_all_resources, coap_resource_set_mode β literally just "Work with CoAP resources". that's the whole vibe. π¦
π SYNOPSIS π
#include <coap2/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);
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_delete_all_resources(coap_context_t *context);
void coap_resource_set_mode(coap_resource_t *resource, int mode);
and bestie, you gotta link this thing up β pick your fighter: -lcoap-2, -lcoap-2-gnutls, -lcoap-2-openssl or -lcoap-2-tinydtls, depending on your (D)TLS library type. β¨
π DESCRIPTION π
so. CoAP Resources on a CoAP Server need to be created, updated, all of that. the URI in the request packet is literally what defines which resource you're working with β and possibly the Query, which refers to a sub-resource. π
when resources are configured on the CoAP server, you specify the URI to match against in the request packet. then Callback Handlers get added to the resource to handle the different request methods. that's the whole loop. π
adding Attributes is how you slap textual information onto a resource, which can then get reported back to any client doing a GET .well-known/core request. very "here's my whole resume" energy. π
if an incoming packet request matches a resource's URI and Method, then the appropriate callback resource handler gets invoked to process the packet β and that handler should then update a suitable response packet for sending back to the requester. no cap. π«
there's also support for handling incoming packets where the URI is unknown. when does that happen? for example when a PUT request is trying to create a new resource. and it is the responsibility of the unknown resource callback handler to either create a new resource for the URI, or just manage things separately. your call, your problem, your moment. π«Ά
big one: CoAP Observe (RFC 7641) is not supported for unknown resources. so a new resource with a GET handler must be created by the unknown resource callback handle matching the URI β that one can then be Observable. π
π the functions, one by one π
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. flags is used to define whether the resource is of type Confirmable Message or Non-Confirmable Message for any "observe" responses. see coap_observe(3). flags can be one of the following definitions, or'ed together:
COAP_RESOURCE_FLAGS_NOTIFY_NONβ set the notification message type to non-confirmable for any triggered "observe" responses.COAP_RESOURCE_FLAGS_NOTIFY_CONβ set the notification message type to confirmable for any triggered "observe" responses.COAP_RESOURCE_FLAGS_RELEASE_URIβ free off thecoap_str_const_tforuri_pathwhen the resource is deleted.
NOTE: uri_path, if not 7 bit readable ASCII, binary bytes must be hex encoded according to the rules defined in RFC3968 Section 2.1. π
The coap_resource_unknown_init() returns a newly created resource of type coap_resource_t *. put_handler is automatically added to the resource to handle PUT requests to resources that are unknown. additional handlers can be added to this resource if required. π
The coap_add_resource() function registers the given resource with the context. the resource must have been created by coap_resource_init(), or coap_resource_unknown_init(). the storage allocated for the resource will be released by coap_delete_resource(). β¨
and listen β since the uri_path of the resource has to be unique across all of the resources associated with a context, coap_add_resource() (or coap_add_resource_release()) will delete any previous resource with the same uri_path before adding in the new resource. it's giving "out with the old, in with the new". π
The coap_delete_resource() function deletes a resource identified by resource from context. the storage allocated for that resource is freed, along with any attributes associated with the resource. gone. poof. π¦
The coap_delete_all_resources() function deletes all resources from context and frees their storage. total reset. main character spring cleaning. π§Ή
The coap_resource_set_mode() changes the notification message type of resource to the given mode β which must be one of COAP_RESOURCE_FLAGS_NOTIFY_NON or COAP_RESOURCE_FLAGS_NOTIFY_CON. those are the only two options, bestie. don't try anything else. π
β RETURN VALUES β
The coap_resource_init() and coap_resource_unknown_init() functions return a newly created resource, or NULL if there is a malloc failure. π
The coap_delete_resource() function return 0 on failure (resource not found), 1 on success. slay. π
β¨ EXAMPLES β¨
ok bestie this is the part where it all clicks, because nothing hits like seeing the actual code π
πΈ Fixed Resources Set Up πΈ
so here's the whole vibe: you got a server with two resources, one for general info and one for the clock, and every handler is just chillin' with the same signature. no cap, look:
#include <coap2/coap.h>
#define INDEX "This is an example server using libcoap\n"
void
hnd_get_index(coap_context_t *ctx, coap_resource_t *resource,
coap_session_t *session, coap_pdu_t *request, coap_string_t *token,
coap_string_t *query, coap_pdu_t *response) {
unsigned char buf[3];
response->code = COAP_RESPONSE_CODE(205);
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);
}
void
hnd_delete_time(coap_context_t *ctx, coap_resource_t *resource,
coap_session_t *session, coap_pdu_t *request, coap_string_t *token,
coap_string_t *query, coap_pdu_t *response) {
/* .. code .. */
}
void
hnd_get_time(coap_context_t *ctx, coap_resource_t *resource,
coap_session_t *session, coap_pdu_t *request, coap_string_t *token,
coap_string_t *query, coap_pdu_t *response) {
/* .. code .. */
}
void
hnd_put_time(coap_context_t *ctx, coap_resource_t *resource,
coap_session_t *session, coap_pdu_t *request, coap_string_t *token,
coap_string_t *query, coap_pdu_t *response) {
/* .. code .. */
}
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_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_handler(r, COAP_REQUEST_GET, hnd_get_time);
coap_register_handler(r, COAP_REQUEST_PUT, hnd_put_time);
coap_register_handler(r, COAP_REQUEST_DELETE, hnd_delete_time);
/* 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("\"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);
}
like, the hnd_get_index one is giving main character energy β it slaps a COAP_RESPONSE_CODE(205) on there, adds the COAP_OPTION_CONTENT_TYPE as COAP_MEDIATYPE_TEXT_PLAIN, sets COAP_OPTION_MAXAGE to 0x2ffff, and then dumps the INDEX string in with coap_add_data() π
and the time resource? she's the popular one fr β COAP_RESOURCE_FLAGS_NOTIFY_CON in the init, coap_resource_set_get_observable(r, 1) so besties can subscribe, and THREE handlers registered: COAP_REQUEST_GET, COAP_REQUEST_PUT, COAP_REQUEST_DELETE. queen behavior π
π¦ Dynamic Resources Set Up π¦
now THIS is the plot twist: resources that don't even exist until somebody PUTs them into existence. it's giving β¨manifestationβ¨
#include <coap2/coap.h>
/* Regular DELETE handler - used by resources created by the
* Unknown Resource PUT handler */
void
hnd_delete(coap_context_t *ctx, coap_resource_t *resource,
coap_session_t *session, coap_pdu_t *request, coap_string_t *token,
coap_string_t *query, coap_pdu_t *response) {
/* .. code .. */
/* Dynamic resource no longer required - delete it */
coap_delete_resource(ctx, resource);
}
/* Regular GET handler - used by resources created by the
* Unknown Resource PUT handler */
void
hnd_get(coap_context_t *ctx, coap_resource_t *resource,
coap_session_t *session, coap_pdu_t *request, coap_string_t *token,
coap_string_t *query, coap_pdu_t *response) {
coap_str_const_t *get_uri_path;
coap_string_t *get_query;
coap_opt_iterator_t opt_iter;
coap_opt_filter_t filter;
coap_opt_t *option;
int len;
/*
* request will be NULL if an Observe triggered request, so the uri_path,
* if needed, must be abstracted from the resource.
* The uri_path string is a const pointer
*/
get_uri_path = coap_resource_get_uri_path(resource);
get_query = query;
/* .. code .. */
}
/* Regular PUT handler - used by resources created by the
* Unknown Resource PUT handler */
void
hnd_put(coap_context_t *ctx, coap_resource_t *resource,
coap_session_t *session, coap_pdu_t *request, coap_string_t *token,
coap_string_t *query, coap_pdu_t *response) {
coap_string_t *put_uri_path;
/* get the uri_path */
put_uri_path = coap_get_uri_path(request);
if (!put_uri_path) {
response->code = COAP_RESPONSE_CODE(404);
return;
}
/* .. code .. */
/* Need to do this as coap_get_uri_path() created it */
coap_delete_string(put_uri_path);
}
/* Unknown Resource PUT handler */
void
hnd_unknown_put(coap_context_t *ctx, coap_resource_t *resource,
coap_session_t *session, coap_pdu_t *request, coap_string_t *token,
coap_string_t *query, coap_pdu_t *response) {
coap_resource_t *r;
int len;
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) {
response->code = COAP_RESPONSE_CODE(404);
return;
}
/* Check if new URI Path is valid */
if (!check_url_fn (uri_path, request->code)) {
response->code = COAP_RESPONSE_CODE(404);
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_handler(r, COAP_REQUEST_PUT, hnd_put);
coap_register_handler(r, COAP_REQUEST_DELETE, hnd_delete);
/* We possibly want to Observe the GETs */
coap_resource_set_get_observable(r, 1);
coap_register_handler(r, COAP_REQUEST_GET, hnd_get);
coap_add_resource(ctx, r);
/* Do the PUT for this first call */
hnd_put(ctx, r, session, request, token, 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_init(hnd_unknown_put);
/*
* Additional handlers can be added - for example
* coap_register_handler(r, COAP_REQUEST_POST, hnd_post_unknown);
* coap_register_handler(r, COAP_REQUEST_GET, hnd_get_unknown);
* coap_register_handler(r, COAP_REQUEST_DELETE, hnd_delete_unknown);
*/
coap_add_resource(ctx, r);
}
okay let me break down the drama for you bestie π
hnd_deleteβ the closer. when the resource isn't wanted anymore it literally callscoap_delete_resource(ctx, resource)and poof, gone πhnd_getβ the multitasker. it's got a whole stack of locals (get_uri_path,get_query,opt_iter,filter,option,len) and it pulls the path off the resource withcoap_resource_get_uri_path(resource). and the comment is SO important:requestwill beNULLif an Observe triggered request, so if you need the uri_path you gotta abstract it from the resource instead. the uri_path string is aconstpointer, iykyk π«Άhnd_putβ grabs the path viacoap_get_uri_path(request), and if it comes back falsy it setsCOAP_RESPONSE_CODE(404)and bails. then at the end itcoap_delete_string(put_uri_path)becausecoap_get_uri_path()created it β you must do this, it's not optional, don't leak that memory bestie πhnd_unknown_putβ the plot device. gets the uri_path, 404s if it's missing, runscheck_url_fn (uri_path, request->code)to validate and 404s (+coap_delete_string(uri_path)) if it's invalid, then builds a brand new resource withcoap_resource_init((coap_str_const_t*)uri_path, COAP_RESOURCE_FLAGS_RELEASE_URI | COAP_RESOURCE_FLAGS_NOTIFY_NON). note thaturi_pathgets deleted when the resource is removed. registershnd_putforCOAP_REQUEST_PUTandhnd_deleteforCOAP_REQUEST_DELETE, flips oncoap_resource_set_get_observable(r, 1)because we possibly want to Observe the GETs, registershnd_getforCOAP_REQUEST_GET, adds it, and then β iconic move β callshnd_put(ctx, r, session, request, token, query, response)so the very first call gets handled too π₯init_resourcesβ creates ONE resource withcoap_resource_unknown_init(hnd_unknown_put)to catch PUTs to unknown URIs. and the comment whispers that you can stack more handlers on it, likecoap_register_handler(r, COAP_REQUEST_POST, hnd_post_unknown),coap_register_handler(r, COAP_REQUEST_GET, hnd_get_unknown),coap_register_handler(r, COAP_REQUEST_DELETE, hnd_delete_unknown). slay π
π SEE ALSO π
go read those next, bestie, they're all part of the same friend group π«Ά
π FURTHER INFORMATION π
See "RFC7252: The Constrained Application Protocol (CoAP)" for further information. it's giving required reading, ngl π
π BUGS π
Please report bugs on the mailing list for libcoap:
libcoap-developers@lists.sourceforge.net
do NOT suffer in silence, we want the tea β
π AUTHORS π
The libcoap project <libcoap-developers@lists.sourceforge.net>
and that's a wrap on COAP_RESOURCE(3) bestie!! this whole page is from the libcoap project, coap_resource 4.2.1, dated 11/23/2021 β literally vintage, and she ate πβ¨ no cap, you're gonna build something gorgeous with this. go forth and register those handlers, you absolute icon ππ¦
π¦ where this page comes from
- ubuntu jammy: libcoap2 4.2.1-1build1 Β· BSD-2-Clause
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms