 |
|
| |
COAP_PERSIST(3) |
libcoap Manual |
COAP_PERSIST(3) |
coap_persist, coap_persist_startup, coap_persist_stop,
coap_persist_track_funcs, coap_persist_observe_add,
coap_persist_set_observe_num - Work with CoAP persist support
#include <coap3/coap.h>
int coap_persist_startup(coap_context_t
*context, const char
*dyn_resource_save_file, const char
*observe_save_file, const char
*obs_cnt_save_file, uint32_t
save_freq);
void coap_persist_stop(coap_context_t
*context);
void coap_persist_track_funcs(coap_context_t
*context, coap_observe_added_t
observe_added, coap_observe_deleted_t
observe_deleted, coap_track_observe_value_t
track_observe_value, coap_dyn_resource_added_t
dyn_resource_added, coap_resource_deleted_t
resource_deleted, uint32_t
save_freq, void
*user_data);
coap_subscription_t *coap_persist_observe_add(coap_context_t
*context, coap_proto_t e_proto,
const coap_address_t *e_listen_addr, const
coap_addr_tuple_t *s_addr_info, const coap_bin_const_t
*raw_packet, const coap_bin_const_t
*oscore_info);
void coap_persist_set_observe_num(coap_resource_t
*resource, uint32_t
start_observe_no);
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.
When a coap-server is restarted, state information does not
usually persist over the restart. libcoap has optional compiled in support
for maintaining resources that were dynamically created, tracking ongoing
observe subscriptions and maintaining OSCORE protection.
There are callbacks provided to support doing this as an
alternative persist storage in the coap-server application.
NOTE: The observe persist support is only available for UDP
sessions.
When using the libcoap compiled in support, only two functions
need to be called by the application. coap_persist_startup() defines
the file names to use for maintaining the persist information over an
application restart, and coap_persist_stop() is called to preserve
any persist information over the server restart.
Function: coap_persist_startup()
The coap_persist_startup() function is used to enable
persist tracking for context so when a coap-server is restarted, the
persist tracked information can be added back in for the server logic.
dyn_resource_save_file is used to save the current list of resources
created from a request to the unknown resource. observe_save_file is
used to save the current list of active observe subscriptions.
obs_cnt_save_file is used to save the current observe counter used
when sending an observe unsolicited response. obs_cnt_save_file only
gets updated every save_freq updates.
If any of the files exist and are not empty, when
coap_persist_startup() is called, the information is loaded back into
the server logic, and for the active observe subscriptions a new server
session is created for sending out the ongoing observe updates (UDP only
supported).
If a file is defined as NULL, then that particular persist
information is not tracked by the libcoap module. This allows a combination
of coap_persist_track_funcs() for customized persist tracking
followed by a call to coap_persist_startup().
Function: coap_persist_stop()
The coap_persist_stop() function is used to disable any
current persist tracking as set up by coap_persist_startup() for
context and preserve the tracking for when the coap-server
application restarts.
If using coap_persist_track_funcs(), then calling
coap_persist_stop() will stop any 4.04 unsolicited response messages
being sent when a resource that has an active observe subscription is
deleted (as happens when coap_free_context() is subsequentially
called).
Function: coap_persist_track_funcs()
The coap_persist_track_funcs() function is used to setup
callback functions associated with context that track information so
that the current tracked information state can be rebuilt following a server
application restart. It is the responsibility of the server application to
track the appropriate information.
The observe_added callback function prototype, called when
a client subscribes to a resource for observation, is defined as:
/**
* Callback handler definition called when a new observe has been set up,
* as defined in coap_persist_track_funcs().
*
* @param session The current session.
* @param observe_key The pointer to the subscription.
* @param e_proto The CoAP protocol in use for the session / endpoint.
* @param e_listen_addr The IP/port that the endpoint is listening on.
* @param s_addr_info Local / Remote IP addresses. ports etc. of session.
* @param raw_packet L7 packet as seen on the wire (could be concatenated if
* Block1 FETCH is being used).
* @param oscore_info Has OSCORE information if OSCORE is protecting the
* session or NULL if OSCORE is not in use.
* @param user_data Application provided information from
* coap_persist_track_funcs().
*
* @return @c 1 if success else @c 0.
*/
typedef int (*coap_observe_added_t)(coap_session_t *session,
coap_subscription_t *observe_key,
coap_proto_t e_proto,
coap_address_t *e_listen_addr,
coap_addr_tuple_t *s_addr_info,
coap_bin_const_t *raw_packet,
coap_bin_const_t *oscore_info,
void *user_data);
The observe_deleted callback function prototype, called
when a client removes the subscription to a resource for observation, is
defined as:
/**
* Callback handler definition called when an observe is being removed,
* as defined in coap_persist_track_funcs().
*
* @param session The current session.
* @param observe_key The pointer to the subscription.
* @param user_data Application provided information from
* coap_persist_track_funcs().
*
* @return @c 1 if success else @c 0.
*/
typedef int (*coap_observe_deleted_t)(coap_session_t *session,
coap_subscription_t *observe_key,
void *user_data);
The track_observe_value callback function prototype, called
when a new unsolicited observe response is went (every save_freq), is
defined as:
/**
* Callback handler definition called when an observe unsolicited response is
* being sent, as defined in coap_persist_track_funcs().
*
* Note: This will only get called every save_freq as defined by
* coap_persist_track_funcs().
*
* @param context The current CoAP context.
* @param resource_name The uri path name of the resource.
* @param observe_num The current observe value just sent.
* @param user_data Application provided information from
* coap_persist_track_funcs().
*
* @return @c 1 if success else @c 0.
*/
typedef int (*coap_track_observe_value_t)(coap_context_t *context,
coap_str_const_t *resource_name,
uint32_t observe_num,
void *user_data);
The dyn_resource_added callback function prototype, called
whenever a resource is created from a request that is calling the resource
unknown handler, is defined as:
/**
* Callback handler definition called when a dynamic resource is getting
* created, as defined in coap_persist_track_funcs().
*
* @param session The current CoAP session.
* @param resource_name The uri path name of the resource.
* @param raw_packet L7 packet as seen on the wire (could be concatenated if
* Block1 PUT/POST/FETCH used to create resource).
* @param user_data Application provided information from
* coap_persist_track_funcs().
*
* @return @c 1 if success else @c 0.
*/
typedef int (*coap_dyn_resource_added_t)(coap_session_t *session,
coap_str_const_t *resource_name,
coap_bin_const_t *raw_packet,
void *user_data);
The resource_deleted callback function prototype, called
whenever a resource is deleted, is defined as:
/**
* Callback handler definition called when resource is removed,
* as defined in coap_persist_track_funcs().
*
* This will remove any dynamic resources that are being tracked as well
* as any observe value tracking.
*
* @param context The current CoAP context.
* @param resource_name The uri path name of the resource.
* @param user_data Application provided information from
* coap_persist_track_funcs().
*
* @return @c 1 if success else @c 0.
*/
typedef int (*coap_resource_deleted_t)(coap_context_t *context,
coap_str_const_t *resource_name,
void *user_data);
save_freq defines the frequency of the update to the
observe value when libcoap calls track_observe_value.
user_data is application defined and is passed into all of the
callback handlers.
Function: coap_persist_observe_add()
The coap_persist_observe_add() function is used to set up a
session and a observe subscription request (typically following a server
reboot) so that a client can continue to receive unsolicited observe
responses without having to establish a new session and issue a new observe
subscription request. The new session is associated with the endpoint
defined by e_proto and e_listen_address. The session has the
IP addresses as defined by s_addr_info. raw_packet contains
the layer 7 of the IP packet that was originally used to request the observe
subscription. Optional oscore_info defines the OSCORE information if
packets are protected by OSCORE. e_proto, e_listen_addr,
s_addr_info, raw_packet and oscore_info are the same as
passed into the coap_observe_added_t callback.
Function: coap_persist_set_observe_num()
The coap_persist_set_observe_num() function is used to
update the resource's current observe counter to start from
start_observe_no instead of 0,
coap_persist_startup() returns 1 on success else 0.
coap_persist_observe_add() returns a newly created observe
subscription or NULL on failure.
Simple Time Server
#include <coap3/coap.h>
#include <stdio.h>
coap_resource_t *time_resource = NULL;
/* specific GET "time" handler, called from hnd_get_generic() */
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) {
unsigned char buf[40];
size_t len;
time_t now;
(void)resource;
(void)session;
/* ... Additional analysis code for resource, request pdu etc. ... */
/* After analysis, generate a suitable response */
/* Note that token, if set, is already in the response pdu */
now = time(NULL);
if (query != NULL && coap_string_equal(query, coap_make_str_const("secs"))) {
/* Output secs since Jan 1 1970 */
len = snprintf((char *)buf, sizeof(buf), "%lu", now);
} else {
/* Output human-readable time */
struct tm *tmp;
tmp = gmtime(&now);
if (!tmp) {
/* If 'now' is not valid */
coap_pdu_set_code(response, COAP_RESPONSE_CODE_NOT_FOUND);
return;
}
len = strftime((char *)buf, sizeof(buf), "%b %d %H:%M:%S", tmp);
}
coap_pdu_set_code(response, COAP_RESPONSE_CODE_CONTENT);
/*
* Invoke coap_add_data_large_response() to do all the hard work.
*
* Define the format - COAP_MEDIATYPE_TEXT_PLAIN - to add in
* Define how long this response is valid for (secs) - 1 - to add in.
* ETAG Option added internally with unique value as param set to 0
*
* OBSERVE Option added internally if needed within the function
* BLOCK2 Option added internally if output too large
* SIZE2 Option added internally
*/
coap_add_data_large_response(resource, session, request, response,
query, COAP_MEDIATYPE_TEXT_PLAIN, 1, 0,
len,
buf, NULL, NULL);
}
/* Generic GET handler */
static void
hnd_get_generic(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 *uri_path = coap_resource_get_uri_path(resource);
if (!uri_path) {
/* Unexpected Failure */
coap_pdu_set_code(response, COAP_RESPONSE_CODE_BAD_REQUEST);
return;
}
/* Is this the "time" resource" ? */
if (coap_string_equal(uri_path, coap_make_str_const("time"))) {
hnd_get_time(resource, session, request, query, response);
return;
}
/* Other resources code */
/* Failure response */
coap_pdu_set_code(response, COAP_RESPONSE_CODE_BAD_REQUEST);
}
/* Initialize generic GET handler */
static void
init_resources(coap_context_t *ctx) {
coap_resource_t *r;
/* Create a resource to return return or update time */
r = coap_resource_init(coap_make_str_const("time"),
COAP_RESOURCE_FLAGS_NOTIFY_CON);
/* We are using a generic GET handler here */
coap_register_request_handler(r, COAP_REQUEST_GET, hnd_get_generic);
coap_resource_set_get_observable(r, 1);
coap_add_resource(ctx, r);
time_resource = r;
}
int
main(int argc, char *argv[]) {
coap_context_t *ctx = NULL;
coap_endpoint_t *ep = NULL;
coap_address_t addr;
unsigned wait_ms;
struct timeval tv_last = {0, 0};
/* Remove (void) definition if variable is used */
(void)argc;
(void)argv;
/* Initialize libcoap library */
coap_startup();
memset(&tv_last, 0, sizeof(tv_last));
/* Create the libcoap context */
ctx = coap_new_context(NULL);
if (!ctx) {
exit(1);
}
/* See coap_block(3) */
coap_context_set_block_mode(ctx,
COAP_BLOCK_USE_LIBCOAP | COAP_BLOCK_SINGLE_BODY);
coap_address_init(&addr);
addr.addr.sa.sa_family = AF_INET;
addr.addr.sin.sin_port = ntohs(COAP_DEFAULT_PORT);
ep = coap_new_endpoint(ctx, &addr, COAP_PROTO_UDP);
/* Other Set up Code */
init_resources(ctx);
if (!coap_persist_startup(ctx,
"/tmp/coap_dyn_resource_save_file",
"/tmp/coap_observe_save_file",
"/tmp/coap_obs_cnt_save_file", 10)) {
fprintf(stderr, "Unable to set up persist logic\n");
exit(1);
}
wait_ms = COAP_RESOURCE_CHECK_TIME * 1000;
while (1) {
int result = coap_io_process(ctx, wait_ms);
if (result < 0) {
break;
} else if (result && (unsigned)result < wait_ms) {
/* decrement if there is a result wait time returned */
wait_ms -= result;
} else {
/*
* result == 0, or result >= wait_ms
* (wait_ms could have decremented to a small value, below
* the granularity of the timer in coap_io_process() and hence
* result == 0)
*/
wait_ms = COAP_RESOURCE_CHECK_TIME * 1000;
}
if (time_resource) {
struct timeval tv_now;
if (gettimeofday(&tv_now, NULL) == 0) {
if (tv_last.tv_sec != tv_now.tv_sec) {
/* Happens once per second */
tv_last = tv_now;
coap_resource_notify_observers(time_resource, NULL);
}
/* need to wait until next second starts if wait_ms is too large */
unsigned next_sec_ms = 1000 - (tv_now.tv_usec / 1000);
if (next_sec_ms && next_sec_ms < wait_ms)
wait_ms = next_sec_ms;
}
}
}
coap_persist_stop(ctx);
coap_free_context(ctx);
coap_cleanup();
exit(0);
}
coap_block(3), coap_context(3),
coap_handler(3), coap_init(3), coap_observe(3),
coap_pdu_setup(3), coap_resource(3) and
coap_session(3)
See
"RFC7252: The Constrained Application Protocol
(CoAP)"
"RFC7641: Observing Resources in the Constrained Application
Protocol (CoAP)"
"RFC8613: Object Security for Constrained RESTful
Environments (OSCORE)"
for further information.
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.
The libcoap project
<libcoap-developers@lists.sourceforge.net>
Visit the GSP FreeBSD Man Page Interface. Output converted with ManDoc.
|