1COAP_PERSIST(3)                 libcoap Manual                 COAP_PERSIST(3)
2
3
4

NAME

6       coap_persist, coap_persist_startup, coap_persist_stop,
7       coap_persist_track_funcs, coap_persist_observe_add,
8       coap_persist_set_observe_num - Work with CoAP persist support
9

SYNOPSIS

11       #include <coap3/coap.h>
12
13       int coap_persist_startup(coap_context_t *context, const char
14       *dyn_resource_save_file, const char *observe_save_file, const char
15       *obs_cnt_save_file, uint32_t save_freq);
16
17       void coap_persist_stop(coap_context_t *context);
18
19       void coap_persist_track_funcs(coap_context_t *context,
20       coap_observe_added_t observe_added, coap_observe_deleted_t
21       observe_deleted, coap_track_observe_value_t track_observe_value,
22       coap_dyn_resource_added_t dyn_resource_added, coap_resource_deleted_t
23       resource_deleted, uint32_t save_freq, void *user_data);
24
25       coap_subscription_t *coap_persist_observe_add(coap_context_t *context,
26       coap_proto_t e_proto, const coap_address_t *e_listen_addr, const
27       coap_addr_tuple_t *s_addr_info, const coap_bin_const_t *raw_packet,
28       const coap_bin_const_t *oscore_info);
29
30       void coap_persist_set_observe_num(coap_resource_t *resource, uint32_t
31       start_observe_no);
32
33       For specific (D)TLS library support, link with -lcoap-3-notls,
34       -lcoap-3-gnutls, -lcoap-3-openssl, -lcoap-3-mbedtls or
35       -lcoap-3-tinydtls. Otherwise, link with -lcoap-3 to get the default
36       (D)TLS library support.
37

DESCRIPTION

39       When a coap-server is restarted, state information does not usually
40       persist over the restart. libcoap has optional compiled in support for
41       maintaining resources that were dynamically created, tracking ongoing
42       observe subscriptions and maintaining OSCORE protection.
43
44       There are callbacks provided to support doing this as an alternative
45       persist storage in the coap-server application.
46
47       NOTE: The observe persist support is only available for UDP sessions.
48
49       When using the libcoap compiled in support, only two functions need to
50       be called by the application. coap_persist_startup() defines the file
51       names to use for maintaining the persist information over an
52       application restart, and coap_persist_stop() is called to preserve any
53       persist information over the server restart.
54

FUNCTIONS

56       Function: coap_persist_startup()
57
58       The coap_persist_startup() function is used to enable persist tracking
59       for context so when a coap-server is restarted, the persist tracked
60       information can be added back in for the server logic.
61       dyn_resource_save_file is used to save the current list of resources
62       created from a request to the unknown resource. observe_save_file is
63       used to save the current list of active observe subscriptions.
64       obs_cnt_save_file is used to save the current observe counter used when
65       sending an observe unsolicited response. obs_cnt_save_file only gets
66       updated every save_freq updates.
67
68       If any of the files exist and are not empty, when
69       coap_persist_startup() is called, the information is loaded back into
70       the server logic, and for the active observe subscriptions a new server
71       session is created for sending out the ongoing observe updates (UDP
72       only supported).
73
74       If a file is defined as NULL, then that particular persist information
75       is not tracked by the libcoap module. This allows a combination of
76       coap_persist_track_funcs() for customized persist tracking followed by
77       a call to coap_persist_startup().
78
79       Function: coap_persist_stop()
80
81       The coap_persist_stop() function is used to disable any current persist
82       tracking as set up by coap_persist_startup() for context and preserve
83       the tracking for when the coap-server application restarts.
84
85       If using coap_persist_track_funcs(), then calling coap_persist_stop()
86       will stop any 4.04 unsolicited response messages being sent when a
87       resource that has an active observe subscription is deleted (as happens
88       when coap_free_context() is subsequentially called).
89
90       Function: coap_persist_track_funcs()
91
92       The coap_persist_track_funcs() function is used to setup callback
93       functions associated with context that track information so that the
94       current tracked information state can be rebuilt following a server
95       application restart. It is the responsibility of the server application
96       to track the appropriate information.
97
98       The observe_added callback function prototype, called when a client
99       subscribes to a resource for observation, is defined as:
100
101           typedef int (*coap_observe_added_t)(coap_session_t *session,
102                                               coap_subscription_t *observe_key,
103                                               coap_proto_t e_proto,
104                                               coap_address_t *e_listen_addr,
105                                               coap_addr_tuple_t *s_addr_info,
106                                               coap_bin_const_t *raw_packet,
107                                               coap_bin_const_t *oscore_info,
108                                               void *user_data);
109
110       The observe_deleted callback function prototype, called when a client
111       removes the subscription to a resource for observation, is defined as:
112
113           typedef int (*coap_observe_deleted_t)(coap_session_t *session,
114                                                 coap_subscription_t *observe_key,
115                                                 void *user_data);
116
117       The track_observe_value callback function prototype, called when a new
118       unsolicited observe response is went (every save_freq), is defined as:
119
120           typedef int (*coap_track_observe_value_t)(coap_context_t *context,
121                                                     coap_str_const_t *resource_name,
122                                                     uint32_t observe_num,
123                                                     void *user_data);
124
125       The dyn_resource_added callback function prototype, called whenever a
126       resource is created from a request that is calling the resource unknown
127       handler, is defined as:
128
129           typedef int (*coap_dyn_resource_added_t)(coap_session_t *session,
130                                                    coap_str_const_t *resource_name,
131                                                    coap_bin_const_t *raw_packet,
132                                                    void *user_data);
133
134       The resource_deleted callback function prototype, called whenever a
135       resource is deleted, is defined as:
136
137           typedef int (*coap_resource_deleted_t)(coap_context_t *context,
138                                                  coap_str_const_t *resource_name,
139                                                  void *user_data);
140
141       save_freq defines the frequency of the update to the observe value when
142       libcoap calls track_observe_value. user_data is application defined and
143       is passed into all of the callback handlers.
144
145       Function: coap_persist_observe_add()
146
147       The coap_persist_observe_add() function is used to set up a session and
148       a observe subscription request (typically following a server reboot) so
149       that a client can continue to receive unsolicited observe responses
150       without having to establish a new session and issue a new observe
151       subscription request. The new session is associated with the endpoint
152       defined by e_proto and e_listen_address. The session has the IP
153       addresses as defined by s_addr_info. raw_packet contains the layer 7 of
154       the IP packet that was originally used to request the observe
155       subscription. Optional oscore_info defines the OSCORE information if
156       packets are protected by OSCORE. e_proto, e_listen_addr, s_addr_info,
157       raw_packet and oscore_info are the same as passed into the
158       coap_observe_added_t callback.
159
160       Function: coap_persist_set_observe_num()
161
162       The coap_persist_set_observe_num() function is used to update the
163       resource's current observe counter to start from start_observe_no
164       instead of 0,
165

RETURN VALUES

167       coap_persist_startup() returns 1 on success else 0.
168
169       coap_persist_observe_add() returns a newly created observe subscription
170       or NULL on failure.
171

EXAMPLES

173       Simple Time Server
174
175           #include <coap3/coap.h>
176
177           #include <stdio.h>
178
179           coap_resource_t *time_resource = NULL;
180
181           /* specific GET "time" handler, called from hnd_get_generic() */
182
183           static void
184           hnd_get_time(coap_resource_t *resource, coap_session_t *session,
185           const coap_pdu_t *request, const coap_string_t *query, coap_pdu_t *response) {
186
187             unsigned char buf[40];
188             size_t len;
189             time_t now;
190             (void)resource;
191             (void)session;
192
193             /* ... Additional analysis code for resource, request pdu etc.  ... */
194
195             /* After analysis, generate a suitable response */
196
197             /* Note that token, if set, is already in the response pdu */
198
199             now = time(NULL);
200
201             if (query != NULL && coap_string_equal(query, coap_make_str_const("secs"))) {
202               /* Output secs since Jan 1 1970 */
203               len = snprintf((char *)buf, sizeof(buf), "%lu", now);
204             }
205             else {
206               /* Output human-readable time */
207               struct tm *tmp;
208               tmp = gmtime(&now);
209               if (!tmp) {
210                 /* If 'now' is not valid */
211                 coap_pdu_set_code(response, COAP_RESPONSE_CODE_NOT_FOUND);
212                 return;
213               }
214               len = strftime((char *)buf, sizeof(buf), "%b %d %H:%M:%S", tmp);
215             }
216             coap_pdu_set_code(response, COAP_RESPONSE_CODE_CONTENT);
217             /*
218              * Invoke coap_add_data_large_response() to do all the hard work.
219              *
220              * Define the format - COAP_MEDIATYPE_TEXT_PLAIN - to add in
221              * Define how long this response is valid for (secs) - 1 - to add in.
222              * ETAG Option added internally with unique value as param set to 0
223              *
224              * OBSERVE Option added internally if needed within the function
225              * BLOCK2 Option added internally if output too large
226              * SIZE2 Option added internally
227              */
228             coap_add_data_large_response(resource, session, request, response,
229                                          query, COAP_MEDIATYPE_TEXT_PLAIN, 1, 0,
230                                          len,
231                                          buf, NULL, NULL);
232           }
233
234           /* Generic GET handler */
235
236           static void
237           hnd_get_generic(coap_resource_t *resource, coap_session_t *session,
238           const coap_pdu_t *request, const coap_string_t *query, coap_pdu_t *response) {
239
240             coap_str_const_t *uri_path = coap_resource_get_uri_path(resource);
241
242             if (!uri_path) {
243               /* Unexpected Failure */
244               coap_pdu_set_code(response, COAP_RESPONSE_CODE_BAD_REQUEST);
245               return;
246             }
247
248             /* Is this the "time" resource" ? */
249             if (coap_string_equal(uri_path, coap_make_str_const("time"))) {
250               hnd_get_time(resource, session, request, query, response);
251               return;
252             }
253
254             /* Other resources code */
255
256             /* Failure response */
257             coap_pdu_set_code(response, COAP_RESPONSE_CODE_BAD_REQUEST);
258           }
259
260           /* Initialize generic GET handler */
261
262           static void
263           init_resources(coap_context_t *ctx)
264           {
265
266             coap_resource_t *r;
267
268             /* Create a resource to return return or update time */
269             r = coap_resource_init(coap_make_str_const("time"),
270                                    COAP_RESOURCE_FLAGS_NOTIFY_CON);
271
272             /* We are using a generic GET handler here */
273             coap_register_request_handler(r, COAP_REQUEST_GET, hnd_get_generic);
274
275             coap_resource_set_get_observable(r, 1);
276
277             coap_add_resource(ctx, r);
278             time_resource = r;
279
280           }
281
282           int
283           main(int argc, char *argv[]) {
284
285             coap_context_t *ctx = NULL;
286             coap_endpoint_t *ep = NULL;
287             coap_address_t addr;
288             unsigned wait_ms;
289             struct timeval tv_last = {0, 0};
290             /* Remove (void) definition if variable is used */
291             (void)argc;
292             (void)argv;
293
294             /* Initialize libcoap library */
295             coap_startup();
296
297             memset (&tv_last, 0, sizeof(tv_last));
298
299             /* Create the libcoap context */
300             ctx = coap_new_context(NULL);
301             if (!ctx) {
302               exit(1);
303             }
304             /* See coap_block(3) */
305             coap_context_set_block_mode(ctx,
306                                         COAP_BLOCK_USE_LIBCOAP | COAP_BLOCK_SINGLE_BODY);
307
308             coap_address_init(&addr);
309             addr.addr.sa.sa_family = AF_INET;
310             addr.addr.sin.sin_port = ntohs(COAP_DEFAULT_PORT);
311             ep = coap_new_endpoint(ctx, &addr, COAP_PROTO_UDP);
312
313             /* Other Set up Code */
314
315             init_resources(ctx);
316
317             if (!coap_persist_startup(ctx,
318                                       "/tmp/coap_dyn_resource_save_file",
319                                       "/tmp/coap_observe_save_file",
320                                       "/tmp/coap_obs_cnt_save_file", 10)) {
321               fprintf(stderr, "Unable to set up persist logic\n");
322               exit(1);
323             }
324
325             wait_ms = COAP_RESOURCE_CHECK_TIME * 1000;
326
327             while (1) {
328               int result = coap_io_process( ctx, wait_ms );
329               if ( result < 0 ) {
330                 break;
331               } else if ( result && (unsigned)result < wait_ms ) {
332                 /* decrement if there is a result wait time returned */
333                 wait_ms -= result;
334               } else {
335                 /*
336                  * result == 0, or result >= wait_ms
337                  * (wait_ms could have decremented to a small value, below
338                  * the granularity of the timer in coap_io_process() and hence
339                  * result == 0)
340                  */
341                 wait_ms = COAP_RESOURCE_CHECK_TIME * 1000;
342               }
343               if (time_resource) {
344                 struct timeval tv_now;
345                 if (gettimeofday (&tv_now, NULL) == 0) {
346                   if (tv_last.tv_sec != tv_now.tv_sec) {
347                     /* Happens once per second */
348                     tv_last = tv_now;
349                     coap_resource_notify_observers(time_resource, NULL);
350                   }
351                   /* need to wait until next second starts if wait_ms is too large */
352                   unsigned next_sec_ms = 1000 - (tv_now.tv_usec / 1000);
353
354                   if (next_sec_ms && next_sec_ms < wait_ms)
355                     wait_ms = next_sec_ms;
356                 }
357               }
358             }
359             coap_persist_stop(ctx);
360             coap_free_context(ctx);
361             coap_cleanup();
362             exit(0);
363
364           }
365

SEE ALSO

367       coap_block(3), coap_context(3), coap_handler(3), coap_init(3),
368       coap_observe(3), coap_pdu_setup(3), coap_resource(3) and
369       coap_session(3)
370

FURTHER INFORMATION

372       See
373
374       "RFC7252: The Constrained Application Protocol (CoAP)"
375
376       "RFC7641: Observing Resources in the Constrained Application Protocol
377       (CoAP)"
378
379       "RFC8613: Object Security for Constrained RESTful Environments
380       (OSCORE)"
381
382       for further information.
383

BUGS

385       Please report bugs on the mailing list for libcoap:
386       libcoap-developers@lists.sourceforge.net or raise an issue on GitHub at
387       https://github.com/obgm/libcoap/issues
388

AUTHORS

390       The libcoap project <libcoap-developers@lists.sourceforge.net>
391
392
393
394coap_persist 4.3.4                10/09/2023                   COAP_PERSIST(3)
Impressum