'\" t
.\" Title: coap_persist
.\" Author: [see the "AUTHORS" section]
.\" Generator: DocBook XSL Stylesheets vsnapshot
.\" Date: 10/28/2023
.\" Manual: libcoap Manual
.\" Source: coap_persist 4.3.4
.\" Language: English
.\"
.TH "COAP_PERSIST" "3" "10/28/2023" "coap_persist 4\&.3\&.4" "libcoap Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.\" http://bugs.debian.org/507673
.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.ie \n(.g .ds Aq \(aq
.el .ds Aq '
.\" -----------------------------------------------------------------
.\" * set default formatting
.\" -----------------------------------------------------------------
.\" disable hyphenation
.nh
.\" disable justification (adjust text to left margin only)
.ad l
.\" -----------------------------------------------------------------
.\" * MAIN CONTENT STARTS HERE *
.\" -----------------------------------------------------------------
.SH "NAME"
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
.SH "SYNOPSIS"
.sp
\fB#include \fR
.sp
\fBint coap_persist_startup(coap_context_t *\fR\fB\fIcontext\fR\fR\fB, const char *\fR\fB\fIdyn_resource_save_file\fR\fR\fB, const char *\fR\fB\fIobserve_save_file\fR\fR\fB, const char *\fR\fB\fIobs_cnt_save_file\fR\fR\fB, uint32_t \fR\fB\fIsave_freq\fR\fR\fB);\fR
.sp
\fBvoid coap_persist_stop(coap_context_t *\fR\fB\fIcontext\fR\fR\fB);\fR
.sp
\fBvoid coap_persist_track_funcs(coap_context_t *\fR\fB\fIcontext\fR\fR\fB, coap_observe_added_t \fR\fB\fIobserve_added\fR\fR\fB, coap_observe_deleted_t \fR\fB\fIobserve_deleted\fR\fR\fB, coap_track_observe_value_t \fR\fB\fItrack_observe_value\fR\fR\fB, coap_dyn_resource_added_t \fR\fB\fIdyn_resource_added\fR\fR\fB, coap_resource_deleted_t \fR\fB\fIresource_deleted\fR\fR\fB, uint32_t \fR\fB\fIsave_freq\fR\fR\fB, void *\fR\fB\fIuser_data\fR\fR\fB);\fR
.sp
\fBcoap_subscription_t *coap_persist_observe_add(coap_context_t *\fR\fB\fIcontext\fR\fR\fB, coap_proto_t \fR\fB\fIe_proto\fR\fR\fB, const coap_address_t *\fR\fB\fIe_listen_addr\fR\fR\fB, const coap_addr_tuple_t *\fR\fB\fIs_addr_info\fR\fR\fB, const coap_bin_const_t *\fR\fB\fIraw_packet\fR\fR\fB, const coap_bin_const_t *\fR\fB\fIoscore_info\fR\fR\fB);\fR
.sp
\fBvoid coap_persist_set_observe_num(coap_resource_t *\fR\fB\fIresource\fR\fR\fB, uint32_t \fR\fB\fIstart_observe_no\fR\fR\fB);\fR
.sp
For specific (D)TLS library support, link with \fB\-lcoap\-3\-notls\fR, \fB\-lcoap\-3\-gnutls\fR, \fB\-lcoap\-3\-openssl\fR, \fB\-lcoap\-3\-mbedtls\fR or \fB\-lcoap\-3\-tinydtls\fR\&. Otherwise, link with \fB\-lcoap\-3\fR to get the default (D)TLS library support\&.
.SH "DESCRIPTION"
.sp
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\&.
.sp
There are callbacks provided to support doing this as an alternative persist storage in the coap\-server application\&.
.sp
\fBNOTE:\fR The observe persist support is only available for UDP sessions\&.
.sp
When using the libcoap compiled in support, only two functions need to be called by the application\&. \fBcoap_persist_startup\fR() defines the file names to use for maintaining the persist information over an application restart, and \fBcoap_persist_stop\fR() is called to preserve any persist information over the server restart\&.
.SH "FUNCTIONS"
.sp
\fBFunction: coap_persist_startup()\fR
.sp
The \fBcoap_persist_startup\fR() function is used to enable persist tracking for \fIcontext\fR so when a coap\-server is restarted, the persist tracked information can be added back in for the server logic\&. \fIdyn_resource_save_file\fR is used to save the current list of resources created from a request to the unknown resource\&. \fIobserve_save_file\fR is used to save the current list of active observe subscriptions\&. \fIobs_cnt_save_file\fR is used to save the current observe counter used when sending an observe unsolicited response\&. \fIobs_cnt_save_file\fR only gets updated every \fIsave_freq\fR updates\&.
.sp
If any of the files exist and are not empty, when \fBcoap_persist_startup\fR() 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)\&.
.sp
If a file is defined as NULL, then that particular persist information is not tracked by the libcoap module\&. This allows a combination of \fBcoap_persist_track_funcs\fR() for customized persist tracking followed by a call to \fBcoap_persist_startup\fR()\&.
.sp
\fBFunction: coap_persist_stop()\fR
.sp
The \fBcoap_persist_stop\fR() function is used to disable any current persist tracking as set up by \fBcoap_persist_startup\fR() for \fIcontext\fR and preserve the tracking for when the coap\-server application restarts\&.
.sp
If using \fBcoap_persist_track_funcs\fR(), then calling \fBcoap_persist_stop\fR() will stop any 4\&.04 unsolicited response messages being sent when a resource that has an active observe subscription is deleted (as happens when \fBcoap_free_context\fR() is subsequentially called)\&.
.sp
\fBFunction: coap_persist_track_funcs()\fR
.sp
The \fBcoap_persist_track_funcs\fR() function is used to setup callback functions associated with \fIcontext\fR 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\&.
.sp
The \fIobserve_added\fR callback function prototype, called when a client subscribes to a resource for observation, is defined as:
.sp
.if n \{\
.RS 4
.\}
.nf
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);
.fi
.if n \{\
.RE
.\}
.sp
The \fIobserve_deleted\fR callback function prototype, called when a client removes the subscription to a resource for observation, is defined as:
.sp
.if n \{\
.RS 4
.\}
.nf
typedef int (*coap_observe_deleted_t)(coap_session_t *session,
coap_subscription_t *observe_key,
void *user_data);
.fi
.if n \{\
.RE
.\}
.sp
The \fItrack_observe_value\fR callback function prototype, called when a new unsolicited observe response is went (every \fIsave_freq\fR), is defined as:
.sp
.if n \{\
.RS 4
.\}
.nf
typedef int (*coap_track_observe_value_t)(coap_context_t *context,
coap_str_const_t *resource_name,
uint32_t observe_num,
void *user_data);
.fi
.if n \{\
.RE
.\}
.sp
The \fIdyn_resource_added\fR callback function prototype, called whenever a resource is created from a request that is calling the resource unknown handler, is defined as:
.sp
.if n \{\
.RS 4
.\}
.nf
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);
.fi
.if n \{\
.RE
.\}
.sp
The \fIresource_deleted\fR callback function prototype, called whenever a resource is deleted, is defined as:
.sp
.if n \{\
.RS 4
.\}
.nf
typedef int (*coap_resource_deleted_t)(coap_context_t *context,
coap_str_const_t *resource_name,
void *user_data);
.fi
.if n \{\
.RE
.\}
.sp
\fIsave_freq\fR defines the frequency of the update to the observe value when libcoap calls \fItrack_observe_value\fR\&. \fIuser_data\fR is application defined and is passed into all of the callback handlers\&.
.sp
\fBFunction: coap_persist_observe_add()\fR
.sp
The \fBcoap_persist_observe_add\fR() 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 \fIe_proto\fR and \fIe_listen_address\fR\&. The session has the IP addresses as defined by \fIs_addr_info\fR\&. \fIraw_packet\fR contains the layer 7 of the IP packet that was originally used to request the observe subscription\&. Optional \fIoscore_info\fR defines the OSCORE information if packets are protected by OSCORE\&. \fIe_proto\fR, \fIe_listen_addr\fR, \fIs_addr_info\fR, \fIraw_packet\fR and \fIoscore_info\fR are the same as passed into the \fIcoap_observe_added_t\fR callback\&.
.sp
\fBFunction: coap_persist_set_observe_num()\fR
.sp
The \fBcoap_persist_set_observe_num\fR() function is used to update the \fIresource\fR\*(Aqs current observe counter to start from \fIstart_observe_no\fR instead of 0,
.SH "RETURN VALUES"
.sp
\fBcoap_persist_startup\fR() returns 1 on success else 0\&.
.sp
\fBcoap_persist_observe_add\fR() returns a newly created observe subscription or NULL on failure\&.
.SH "EXAMPLES"
.sp
\fBSimple Time Server\fR
.sp
.if n \{\
.RS 4
.\}
.nf
#include
#include
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 \*(Aqnow\*(Aq 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\en");
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);
}
.fi
.if n \{\
.RE
.\}
.SH "SEE ALSO"
.sp
\fBcoap_block\fR(3), \fBcoap_context\fR(3), \fBcoap_handler\fR(3), \fBcoap_init\fR(3), \fBcoap_observe\fR(3), \fBcoap_pdu_setup\fR(3), \fBcoap_resource\fR(3) and \fBcoap_session\fR(3)
.SH "FURTHER INFORMATION"
.sp
See
.sp
"RFC7252: The Constrained Application Protocol (CoAP)"
.sp
"RFC7641: Observing Resources in the Constrained Application Protocol (CoAP)"
.sp
"RFC8613: Object Security for Constrained RESTful Environments (OSCORE)"
.sp
for further information\&.
.SH "BUGS"
.sp
Please report bugs on the mailing list for libcoap: libcoap\-developers@lists\&.sourceforge\&.net or raise an issue on GitHub at https://github\&.com/obgm/libcoap/issues
.SH "AUTHORS"
.sp
The libcoap project