1// -*- mode:doc; -*- 2// vim: set syntax=asciidoc tw=0 3 4coap_persist(3) 5=============== 6:doctype: manpage 7:man source: coap_persist 8:man version: @PACKAGE_VERSION@ 9:man manual: libcoap Manual 10 11NAME 12---- 13coap_persist, 14coap_persist_startup, 15coap_persist_stop, 16coap_persist_track_funcs, 17coap_persist_observe_add, 18coap_persist_set_observe_num 19- Work with CoAP persist support 20 21SYNOPSIS 22-------- 23*#include <coap@LIBCOAP_API_VERSION@/coap.h>* 24 25*int coap_persist_startup(coap_context_t *_context_, 26const char *_dyn_resource_save_file_, const char *_observe_save_file_, 27const char *_obs_cnt_save_file_, uint32_t _save_freq_);* 28 29*void coap_persist_stop(coap_context_t *_context_);* 30 31*void coap_persist_track_funcs(coap_context_t *_context_, 32coap_observe_added_t _observe_added_, coap_observe_deleted_t _observe_deleted_, 33coap_track_observe_value_t _track_observe_value_, 34coap_dyn_resource_added_t _dyn_resource_added_, 35coap_resource_deleted_t _resource_deleted_, 36uint32_t _save_freq_, void *_user_data_);* 37 38*coap_subscription_t *coap_persist_observe_add(coap_context_t *_context_, 39coap_proto_t _e_proto_, const coap_address_t *_e_listen_addr_, 40const coap_addr_tuple_t *_s_addr_info_, const coap_bin_const_t *_raw_packet_, 41const coap_bin_const_t *_oscore_info_);* 42 43*void coap_persist_set_observe_num(coap_resource_t *_resource_, 44uint32_t _start_observe_no_);* 45 46For specific (D)TLS library support, link with 47*-lcoap-@LIBCOAP_API_VERSION@-notls*, *-lcoap-@LIBCOAP_API_VERSION@-gnutls*, 48*-lcoap-@LIBCOAP_API_VERSION@-openssl*, *-lcoap-@LIBCOAP_API_VERSION@-mbedtls* 49or *-lcoap-@LIBCOAP_API_VERSION@-tinydtls*. Otherwise, link with 50*-lcoap-@LIBCOAP_API_VERSION@* to get the default (D)TLS library support. 51 52DESCRIPTION 53----------- 54When a coap-server is restarted, state information does not usually persist 55over the restart. libcoap has optional compiled in support for maintaining 56resources that were dynamically created, tracking ongoing observe subscriptions 57and maintaining OSCORE protection. 58 59There are callbacks provided to support doing this as an alternative persist 60storage in the coap-server application. 61 62*NOTE:* The observe persist support is only available for UDP sessions. 63 64When using the libcoap compiled in support, only two functions need to be 65called by the application. *coap_persist_startup*() defines the file names to 66use for maintaining the persist information over an application restart, and 67*coap_persist_stop*() is called to preserve any persist information over the 68server restart. 69 70FUNCTIONS 71--------- 72 73*Function: coap_persist_startup()* 74 75The *coap_persist_startup*() function is used to enable persist tracking for 76_context_ so when a coap-server is restarted, the persist tracked information 77can be added back in for the server logic. 78_dyn_resource_save_file_ is used to save the current list of resources created 79from a request to the unknown resource. 80_observe_save_file_ is used to save the current list of active observe 81subscriptions. 82_obs_cnt_save_file_ is used to save the current observe counter used when 83sending an observe unsolicited response. _obs_cnt_save_file_ only gets 84updated every _save_freq_ updates. 85 86If any of the files exist and are not empty, when *coap_persist_startup*() is 87called, the information is loaded back into the server logic, and for the 88active observe subscriptions a new server session is created for sending out 89the ongoing observe updates (UDP only supported). 90 91If a file is defined as NULL, then that particular persist information is not 92tracked by the libcoap module. This allows a combination of 93*coap_persist_track_funcs*() for customized persist tracking followed by a 94call to *coap_persist_startup*(). 95 96*Function: coap_persist_stop()* 97 98The *coap_persist_stop*() function is used to disable any current persist 99tracking as set up by *coap_persist_startup*() for _context_ and preserve the 100tracking for when the coap-server application restarts. 101 102If using *coap_persist_track_funcs*(), then calling *coap_persist_stop*() 103will stop any 4.04 unsolicited response messages being sent when a 104resource that has an active observe subscription is deleted (as happens 105when *coap_free_context*() is subsequentially called). 106 107*Function: coap_persist_track_funcs()* 108 109The *coap_persist_track_funcs*() function is used to setup callback functions 110associated with _context_ that track information so that the current tracked 111information state can be rebuilt following a server application restart. It is 112the responsibility of the server application to track the appropriate 113information. 114 115The _observe_added_ callback function prototype, called when a client 116subscribes to a resource for observation, is defined as: 117[source, c] 118---- 119typedef int (*coap_observe_added_t)(coap_session_t *session, 120 coap_subscription_t *observe_key, 121 coap_proto_t e_proto, 122 coap_address_t *e_listen_addr, 123 coap_addr_tuple_t *s_addr_info, 124 coap_bin_const_t *raw_packet, 125 coap_bin_const_t *oscore_info, 126 void *user_data); 127---- 128 129The _observe_deleted_ callback function prototype, called when a client 130removes the subscription to a resource for observation, is defined as: 131[source, c] 132---- 133typedef int (*coap_observe_deleted_t)(coap_session_t *session, 134 coap_subscription_t *observe_key, 135 void *user_data); 136---- 137 138The _track_observe_value_ callback function prototype, called when a new 139unsolicited observe response is went (every _save_freq_), is defined as: 140[source, c] 141---- 142typedef int (*coap_track_observe_value_t)(coap_context_t *context, 143 coap_str_const_t *resource_name, 144 uint32_t observe_num, 145 void *user_data); 146---- 147 148The _dyn_resource_added_ callback function prototype, called whenever a 149resource is created from a request that is calling the resource unknown 150handler, is defined as: 151[source, c] 152---- 153typedef int (*coap_dyn_resource_added_t)(coap_session_t *session, 154 coap_str_const_t *resource_name, 155 coap_bin_const_t *raw_packet, 156 void *user_data); 157---- 158 159The _resource_deleted_ callback function prototype, called whenever a 160resource is deleted, is defined as: 161[source, c] 162---- 163typedef int (*coap_resource_deleted_t)(coap_context_t *context, 164 coap_str_const_t *resource_name, 165 void *user_data); 166---- 167 168_save_freq_ defines the frequency of the update to the observe value when 169libcoap calls _track_observe_value_. _user_data_ is application defined and 170is passed into all of the callback handlers. 171 172*Function: coap_persist_observe_add()* 173 174The *coap_persist_observe_add*() function is used to set up a session and a 175observe subscription request (typically following a server reboot) so that a 176client can continue to receive unsolicited observe responses without having 177to establish a new session and issue a new observe subscription request. The 178new session is associated with the endpoint defined by _e_proto_ and 179_e_listen_address_. The session has the IP addresses as defined by 180_s_addr_info_. _raw_packet_ contains the layer 7 of the IP packet that was 181originally used to request the observe subscription. Optional _oscore_info_ 182defines the OSCORE information if packets are protected by OSCORE. 183 _e_proto_, _e_listen_addr_, _s_addr_info_, _raw_packet_ and _oscore_info_ 184are the same as passed into the _coap_observe_added_t_ callback. 185 186*Function: coap_persist_set_observe_num()* 187 188The *coap_persist_set_observe_num*() function is used to update the 189_resource_'s current observe counter to start from _start_observe_no_ 190instead of 0, 191 192RETURN VALUES 193------------- 194*coap_persist_startup*() returns 1 on success else 0. 195 196*coap_persist_observe_add*() returns a newly created observe 197subscription or NULL on failure. 198 199EXAMPLES 200-------- 201*Simple Time Server* 202 203[source, c] 204---- 205#include <coap@LIBCOAP_API_VERSION@/coap.h> 206 207#include <stdio.h> 208 209coap_resource_t *time_resource = NULL; 210 211/* specific GET "time" handler, called from hnd_get_generic() */ 212 213static void 214hnd_get_time(coap_resource_t *resource, coap_session_t *session, 215const coap_pdu_t *request, const coap_string_t *query, coap_pdu_t *response) { 216 217 unsigned char buf[40]; 218 size_t len; 219 time_t now; 220 (void)resource; 221 (void)session; 222 223 /* ... Additional analysis code for resource, request pdu etc. ... */ 224 225 /* After analysis, generate a suitable response */ 226 227 /* Note that token, if set, is already in the response pdu */ 228 229 now = time(NULL); 230 231 if (query != NULL && coap_string_equal(query, coap_make_str_const("secs"))) { 232 /* Output secs since Jan 1 1970 */ 233 len = snprintf((char *)buf, sizeof(buf), "%lu", now); 234 } 235 else { 236 /* Output human-readable time */ 237 struct tm *tmp; 238 tmp = gmtime(&now); 239 if (!tmp) { 240 /* If 'now' is not valid */ 241 coap_pdu_set_code(response, COAP_RESPONSE_CODE_NOT_FOUND); 242 return; 243 } 244 len = strftime((char *)buf, sizeof(buf), "%b %d %H:%M:%S", tmp); 245 } 246 coap_pdu_set_code(response, COAP_RESPONSE_CODE_CONTENT); 247 /* 248 * Invoke coap_add_data_large_response() to do all the hard work. 249 * 250 * Define the format - COAP_MEDIATYPE_TEXT_PLAIN - to add in 251 * Define how long this response is valid for (secs) - 1 - to add in. 252 * ETAG Option added internally with unique value as param set to 0 253 * 254 * OBSERVE Option added internally if needed within the function 255 * BLOCK2 Option added internally if output too large 256 * SIZE2 Option added internally 257 */ 258 coap_add_data_large_response(resource, session, request, response, 259 query, COAP_MEDIATYPE_TEXT_PLAIN, 1, 0, 260 len, 261 buf, NULL, NULL); 262} 263 264/* Generic GET handler */ 265 266static void 267hnd_get_generic(coap_resource_t *resource, coap_session_t *session, 268const coap_pdu_t *request, const coap_string_t *query, coap_pdu_t *response) { 269 270 coap_str_const_t *uri_path = coap_resource_get_uri_path(resource); 271 272 if (!uri_path) { 273 /* Unexpected Failure */ 274 coap_pdu_set_code(response, COAP_RESPONSE_CODE_BAD_REQUEST); 275 return; 276 } 277 278 /* Is this the "time" resource" ? */ 279 if (coap_string_equal(uri_path, coap_make_str_const("time"))) { 280 hnd_get_time(resource, session, request, query, response); 281 return; 282 } 283 284 /* Other resources code */ 285 286 /* Failure response */ 287 coap_pdu_set_code(response, COAP_RESPONSE_CODE_BAD_REQUEST); 288} 289 290/* Initialize generic GET handler */ 291 292static void 293init_resources(coap_context_t *ctx) 294{ 295 296 coap_resource_t *r; 297 298 /* Create a resource to return return or update time */ 299 r = coap_resource_init(coap_make_str_const("time"), 300 COAP_RESOURCE_FLAGS_NOTIFY_CON); 301 302 /* We are using a generic GET handler here */ 303 coap_register_request_handler(r, COAP_REQUEST_GET, hnd_get_generic); 304 305 coap_resource_set_get_observable(r, 1); 306 307 coap_add_resource(ctx, r); 308 time_resource = r; 309 310} 311 312int 313main(int argc, char *argv[]) { 314 315 coap_context_t *ctx = NULL; 316 coap_endpoint_t *ep = NULL; 317 coap_address_t addr; 318 unsigned wait_ms; 319 struct timeval tv_last = {0, 0}; 320 /* Remove (void) definition if variable is used */ 321 (void)argc; 322 (void)argv; 323 324 /* Initialize libcoap library */ 325 coap_startup(); 326 327 memset (&tv_last, 0, sizeof(tv_last)); 328 329 /* Create the libcoap context */ 330 ctx = coap_new_context(NULL); 331 if (!ctx) { 332 exit(1); 333 } 334 /* See coap_block(3) */ 335 coap_context_set_block_mode(ctx, 336 COAP_BLOCK_USE_LIBCOAP | COAP_BLOCK_SINGLE_BODY); 337 338 coap_address_init(&addr); 339 addr.addr.sa.sa_family = AF_INET; 340 addr.addr.sin.sin_port = ntohs(COAP_DEFAULT_PORT); 341 ep = coap_new_endpoint(ctx, &addr, COAP_PROTO_UDP); 342 343 /* Other Set up Code */ 344 345 init_resources(ctx); 346 347 if (!coap_persist_startup(ctx, 348 "/tmp/coap_dyn_resource_save_file", 349 "/tmp/coap_observe_save_file", 350 "/tmp/coap_obs_cnt_save_file", 10)) { 351 fprintf(stderr, "Unable to set up persist logic\n"); 352 exit(1); 353 } 354 355 wait_ms = COAP_RESOURCE_CHECK_TIME * 1000; 356 357 while (1) { 358 int result = coap_io_process( ctx, wait_ms ); 359 if ( result < 0 ) { 360 break; 361 } else if ( result && (unsigned)result < wait_ms ) { 362 /* decrement if there is a result wait time returned */ 363 wait_ms -= result; 364 } else { 365 /* 366 * result == 0, or result >= wait_ms 367 * (wait_ms could have decremented to a small value, below 368 * the granularity of the timer in coap_io_process() and hence 369 * result == 0) 370 */ 371 wait_ms = COAP_RESOURCE_CHECK_TIME * 1000; 372 } 373 if (time_resource) { 374 struct timeval tv_now; 375 if (gettimeofday (&tv_now, NULL) == 0) { 376 if (tv_last.tv_sec != tv_now.tv_sec) { 377 /* Happens once per second */ 378 tv_last = tv_now; 379 coap_resource_notify_observers(time_resource, NULL); 380 } 381 /* need to wait until next second starts if wait_ms is too large */ 382 unsigned next_sec_ms = 1000 - (tv_now.tv_usec / 1000); 383 384 if (next_sec_ms && next_sec_ms < wait_ms) 385 wait_ms = next_sec_ms; 386 } 387 } 388 } 389 coap_persist_stop(ctx); 390 coap_free_context(ctx); 391 coap_cleanup(); 392 exit(0); 393 394} 395---- 396 397SEE ALSO 398-------- 399*coap_block*(3), *coap_context*(3), *coap_handler*(3), *coap_init*(3), *coap_observe*(3), 400*coap_pdu_setup*(3), *coap_resource*(3) and *coap_session*(3) 401 402FURTHER INFORMATION 403------------------- 404See 405 406"https://rfc-editor.org/rfc/rfc7252[RFC7252: The Constrained Application Protocol (CoAP)]" 407 408"https://rfc-editor.org/rfc/rfc7641[RFC7641: Observing Resources in the Constrained Application Protocol (CoAP)]" 409 410"https://rfc-editor.org/rfc/rfc8613[RFC8613: Object Security for Constrained RESTful Environments (OSCORE)]" 411 412for further information. 413 414 415BUGS 416---- 417Please report bugs on the mailing list for libcoap: 418libcoap-developers@lists.sourceforge.net or raise an issue on GitHub at 419https://github.com/obgm/libcoap/issues 420 421AUTHORS 422------- 423The libcoap project <libcoap-developers@lists.sourceforge.net> 424