1COAP_PERSIST(3) libcoap Manual COAP_PERSIST(3)
2
3
4
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
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
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
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
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
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
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
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
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
390 The libcoap project <libcoap-developers@lists.sourceforge.net>
391
392
393
394coap_persist 4.3.4 10/09/2023 COAP_PERSIST(3)