'\" 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