libcoap 4.3.5-develop-19cef11
coap_subscribe.c
Go to the documentation of this file.
1/* coap_subscribe.c -- subscription handling for CoAP
2 * see RFC7641
3 *
4 * Copyright (C) 2010-2019,2022-2024 Olaf Bergmann <bergmann@tzi.org>
5 *
6 * SPDX-License-Identifier: BSD-2-Clause
7 *
8 * This file is part of the CoAP library libcoap. Please see
9 * README for terms of use.
10 */
11
18
19#ifndef min
20#define min(a,b) ((a) < (b) ? (a) : (b))
21#endif
22
23int
25#if COAP_SERVER_SUPPORT && COAP_WITH_OBSERVE_PERSIST
26 return 1;
27#else /* ! (COAP_SERVER_SUPPORT && COAP_WITH_OBSERVE_PERSIST) */
28 return 0;
29#endif /* ! (COAP_SERVER_SUPPORT && COAP_WITH_OBSERVE_PERSIST) */
30}
31
32#if COAP_SERVER_SUPPORT
33void
35 assert(s);
36 memset(s, 0, sizeof(coap_subscription_t));
37}
38
39void
41 coap_observe_added_t observe_added,
42 coap_observe_deleted_t observe_deleted,
43 coap_track_observe_value_t track_observe_value,
44 coap_dyn_resource_added_t dyn_resource_added,
45 coap_resource_deleted_t resource_deleted,
46 uint32_t save_freq,
47 void *user_data) {
48 context->observe_added = observe_added;
49 context->observe_deleted = observe_deleted;
50 context->observe_user_data = user_data;
51 context->observe_save_freq = save_freq ? save_freq : 1;
52 context->track_observe_value = track_observe_value;
53 context->dyn_resource_added = dyn_resource_added;
54 context->resource_deleted = resource_deleted;
55}
56
59 coap_proto_t e_proto,
60 const coap_address_t *e_listen_addr,
61 const coap_addr_tuple_t *s_addr_info,
62 const coap_bin_const_t *raw_packet,
63 const coap_bin_const_t *oscore_info) {
65
66 coap_lock_lock(context, return NULL);
67 subs = coap_persist_observe_add_lkd(context,
68 e_proto,
69 e_listen_addr,
70 s_addr_info,
71 raw_packet,
72 oscore_info);
73 coap_lock_unlock(context);
74 return subs;
75}
76
79 coap_proto_t e_proto,
80 const coap_address_t *e_listen_addr,
81 const coap_addr_tuple_t *s_addr_info,
82 const coap_bin_const_t *raw_packet,
83 const coap_bin_const_t *oscore_info) {
84 coap_session_t *session = NULL;
85 const uint8_t *data;
86 size_t data_len;
87 coap_pdu_t *pdu = NULL;
88#if COAP_CONSTRAINED_STACK
89 /* e_packet can be protected by global_lock if needed */
90 static coap_packet_t e_packet;
91#else /* ! COAP_CONSTRAINED_STACK */
92 coap_packet_t e_packet;
93#endif /* ! COAP_CONSTRAINED_STACK */
94 coap_packet_t *packet = &e_packet;
95 coap_tick_t now;
96 coap_string_t *uri_path = NULL;
97 coap_opt_iterator_t opt_iter;
98 coap_opt_t *observe;
99 int observe_action;
102 coap_endpoint_t *ep;
103
104 coap_lock_check_locked(context);
105 if (e_listen_addr == NULL || s_addr_info == NULL || raw_packet == NULL)
106 return NULL;
107
108 /* Will be creating a local 'open' session */
109 if (e_proto != COAP_PROTO_UDP)
110 return NULL;
111
112 ep = context->endpoint;
113 while (ep) {
114 if (ep->proto == e_proto &&
115 memcmp(e_listen_addr, &ep->bind_addr, sizeof(ep->bind_addr)) == 0)
116 break;
117 ep = ep->next;
118 }
119 if (!ep)
120 return NULL;
121
122 /* Build up packet */
123 memcpy(&packet->addr_info, s_addr_info, sizeof(packet->addr_info));
124 packet->ifindex = 0;
125 memcpy(&packet->payload, &raw_packet->s, sizeof(packet->payload));
126 packet->length = raw_packet->length;
127
128 data = raw_packet->s;
129 data_len = raw_packet->length;
130 if (data_len < 4)
131 goto malformed;
132
133 /* Get the session */
134
135 coap_ticks(&now);
136 session = coap_endpoint_get_session(ep, packet, now);
137 if (session == NULL)
138 goto fail;
139 /* Need max space incase PDU is updated with updated token, huge size etc. */
140 pdu = coap_pdu_init(0, 0, 0, 0);
141 if (!pdu)
142 goto fail;
143
144 if (!coap_pdu_parse(session->proto, data, data_len, pdu)) {
145 goto malformed;
146 }
147 pdu->max_size = pdu->used_size;
148
149 if (pdu->code != COAP_REQUEST_CODE_GET &&
151 goto malformed;
152
153 observe = coap_check_option(pdu, COAP_OPTION_OBSERVE, &opt_iter);
154 if (observe == NULL)
155 goto malformed;
156 observe_action = coap_decode_var_bytes(coap_opt_value(observe),
157 coap_opt_length(observe));
158 if (observe_action != COAP_OBSERVE_ESTABLISH)
159 goto malformed;
160
161 /* Get the resource */
162
163 uri_path = coap_get_uri_path(pdu);
164 if (!uri_path)
165 goto malformed;
166
168 (coap_str_const_t *)uri_path);
169 if (r == NULL) {
170 coap_log_warn("coap_persist_observe_add: resource '%s' not defined\n",
171 uri_path->s);
172 goto fail;
173 }
174 if (!r->observable) {
175 coap_log_warn("coap_persist_observe_add: resource '%s' not observable\n",
176 uri_path->s);
177 goto fail;
178 }
179 coap_delete_string(uri_path);
180 uri_path = NULL;
181
182 /* Create / update subscription for observing */
183 /* Now set up the subscription */
184 s = coap_add_observer(r, session, &pdu->actual_token, pdu);
185 if (s == NULL)
186 goto fail;
187
188#if COAP_OSCORE_SUPPORT
189 if (oscore_info) {
190 coap_log_debug("persist: OSCORE association being updated\n");
191 /*
192 * Need to track the association used for tracking this observe, done as
193 * a CBOR array. Written in coap_add_observer().
194 *
195 * If an entry is null, then use nil, else a set of bytes
196 *
197 * Currently tracking 5 items
198 * recipient_id
199 * id_context
200 * aad (from oscore_association_t)
201 * partial_iv (from oscore_association_t)
202 * nonce (from oscore_association_t)
203 */
204 oscore_ctx_t *osc_ctx;
205 const uint8_t *info_buf = oscore_info->s;
206 size_t info_buf_len = oscore_info->length;
207 size_t ret = 0;
208 coap_bin_const_t oscore_key_id;
209 coap_bin_const_t partial_iv;
211 coap_bin_const_t id_context;
212 coap_bin_const_t nonce;
213 int have_aad = 0;
214 int have_partial_iv = 0;
215 int have_id_context = 0;
216 int have_nonce = 0;
217
218 ret = oscore_cbor_get_next_element(&info_buf, &info_buf_len);
219 if (ret != CBOR_ARRAY)
220 goto oscore_fail;
221 if (oscore_cbor_get_element_size(&info_buf, &info_buf_len) != 5)
222 goto oscore_fail;
223
224 /* recipient_id */
225 ret = oscore_cbor_get_next_element(&info_buf, &info_buf_len);
226 if (ret != CBOR_BYTE_STRING)
227 goto oscore_fail;
228 oscore_key_id.length = oscore_cbor_get_element_size(&info_buf,
229 &info_buf_len);
230 oscore_key_id.s = info_buf;
231 info_buf += oscore_key_id.length;
232
233 /* id_context */
234 ret = oscore_cbor_get_next_element(&info_buf, &info_buf_len);
235 if (ret == CBOR_BYTE_STRING) {
236 id_context.length = oscore_cbor_get_element_size(&info_buf,
237 &info_buf_len);
238 id_context.s = info_buf;
239 info_buf += id_context.length;
240 have_id_context = 1;
241 } else if (ret == CBOR_SIMPLE_VALUE &&
243 &info_buf_len) == CBOR_NULL) {
244 } else
245 goto oscore_fail;
246
247 /* aad */
248 ret = oscore_cbor_get_next_element(&info_buf, &info_buf_len);
249 if (ret == CBOR_BYTE_STRING) {
250 aad.length = oscore_cbor_get_element_size(&info_buf, &info_buf_len);
251 aad.s = info_buf;
252 info_buf += aad.length;
253 have_aad = 1;
254 } else if (ret == CBOR_SIMPLE_VALUE &&
256 &info_buf_len) == CBOR_NULL) {
257 } else
258 goto oscore_fail;
259
260 /* partial_iv */
261 ret = oscore_cbor_get_next_element(&info_buf, &info_buf_len);
262 if (ret == CBOR_BYTE_STRING) {
263 partial_iv.length = oscore_cbor_get_element_size(&info_buf,
264 &info_buf_len);
265 partial_iv.s = info_buf;
266 info_buf += partial_iv.length;
267 have_partial_iv = 1;
268 } else if (ret == CBOR_SIMPLE_VALUE &&
270 &info_buf_len) == CBOR_NULL) {
271 } else
272 goto oscore_fail;
273
274 /* nonce */
275 ret = oscore_cbor_get_next_element(&info_buf, &info_buf_len);
276 if (ret == CBOR_BYTE_STRING) {
277 nonce.length = oscore_cbor_get_element_size(&info_buf,
278 &info_buf_len);
279 nonce.s = info_buf;
280 info_buf += nonce.length;
281 have_nonce = 1;
282 } else if (ret == CBOR_SIMPLE_VALUE &&
284 &info_buf_len) == CBOR_NULL) {
285 } else
286 goto oscore_fail;
287
288 osc_ctx = oscore_find_context(session->context, oscore_key_id,
289 have_id_context ? &id_context : NULL, NULL,
290 &session->recipient_ctx);
291 if (osc_ctx) {
292 session->oscore_encryption = 1;
293 oscore_new_association(session, pdu, &pdu->actual_token,
294 session->recipient_ctx,
295 have_aad ? &aad : NULL,
296 have_nonce ? &nonce : NULL,
297 have_partial_iv ? &partial_iv : NULL,
298 1);
299 coap_log_debug("persist: OSCORE association added\n");
301 have_partial_iv ? &partial_iv : NULL);
302 }
303 }
304oscore_fail:
305#else /* ! COAP_OSCORE_SUPPORT */
306 (void)oscore_info;
307#endif /* ! COAP_OSCORE_SUPPORT */
308 coap_delete_pdu(pdu);
309 return s;
310
311malformed:
312 coap_log_warn("coap_persist_observe_add: discard malformed PDU\n");
313fail:
314 coap_delete_string(uri_path);
315 coap_delete_pdu(pdu);
316 return NULL;
317}
318
319#if COAP_WITH_OBSERVE_PERSIST
320#include <stdio.h>
321
322/*
323 * read in active observe entry.
324 */
325static int
326coap_op_observe_read(FILE *fp, coap_subscription_t **observe_key,
327 coap_proto_t *e_proto, coap_address_t *e_listen_addr,
328 coap_addr_tuple_t *s_addr_info,
329 coap_bin_const_t **raw_packet, coap_bin_const_t **oscore_info) {
330 ssize_t size;
331 coap_binary_t *scratch = NULL;
332
333 assert(fp && observe_key && e_proto && e_listen_addr && s_addr_info &&
334 raw_packet && oscore_info);
335
336 *raw_packet = NULL;
337 *oscore_info = NULL;
338
339 if (fread(observe_key, sizeof(*observe_key), 1, fp) == 1) {
340 /* New record 'key proto listen addr_info len raw_packet len oscore' */
341 if (fread(e_proto, sizeof(*e_proto), 1, fp) != 1)
342 goto fail;
343 if (fread(e_listen_addr, sizeof(*e_listen_addr), 1, fp) != 1)
344 goto fail;
345 if (fread(s_addr_info, sizeof(*s_addr_info), 1, fp) != 1)
346 goto fail;
347 if (fread(&size, sizeof(size), 1, fp) != 1)
348 goto fail;
349 if (size < 0 || size > 0x10000)
350 goto fail;
351 scratch = coap_new_binary(size);
352 if ((scratch) == NULL)
353 goto fail;
354 if (fread(scratch->s, scratch->length, 1, fp) != 1)
355 goto fail;
356 *raw_packet = (coap_bin_const_t *)scratch;
357 scratch = NULL;
358 if (fread(&size, sizeof(size), 1, fp) != 1)
359 goto fail;
360 /* If size == -1, then no oscore information */
361 if (size == -1)
362 return 1;
363 else if (size < 0 || size > 0x10000)
364 goto fail;
365 else {
366 scratch = coap_new_binary(size);
367 if (scratch == NULL)
368 goto fail;
369 if (fread(scratch->s, scratch->length, 1, fp) != 1)
370 goto fail;
371 *oscore_info = (coap_bin_const_t *)scratch;
372 }
373 return 1;
374 }
375fail:
376 coap_delete_bin_const(*raw_packet);
377 coap_delete_binary(scratch);
378
379 *observe_key = NULL;
380 memset(e_proto, 0, sizeof(*e_proto));
381 memset(e_listen_addr, 0, sizeof(*e_listen_addr));
382 memset(s_addr_info, 0, sizeof(*s_addr_info));
383 *raw_packet = NULL;
384 return 0;
385}
386
387/*
388 * write out active observe entry.
389 */
390static int
391coap_op_observe_write(FILE *fp, coap_subscription_t *observe_key,
392 coap_proto_t e_proto, coap_address_t e_listen_addr,
393 coap_addr_tuple_t s_addr_info,
394 coap_bin_const_t *raw_packet, coap_bin_const_t *oscore_info) {
395 if (fwrite(&observe_key, sizeof(observe_key), 1, fp) != 1)
396 goto fail;
397 if (fwrite(&e_proto, sizeof(e_proto), 1, fp) != 1)
398 goto fail;
399 if (fwrite(&e_listen_addr, sizeof(e_listen_addr),
400 1, fp) != 1)
401 goto fail;
402 if (fwrite(&s_addr_info, sizeof(s_addr_info), 1, fp) != 1)
403 goto fail;
404 if (fwrite(&raw_packet->length, sizeof(raw_packet->length), 1, fp) != 1)
405 goto fail;
406 if (fwrite(raw_packet->s, raw_packet->length, 1, fp) != 1)
407 goto fail;
408 if (oscore_info) {
409 if (fwrite(&oscore_info->length, sizeof(oscore_info->length), 1, fp) != 1)
410 goto fail;
411 if (fwrite(oscore_info->s, oscore_info->length, 1, fp) != 1)
412 goto fail;
413 } else {
414 ssize_t not_defined = -1;
415
416 if (fwrite(&not_defined, sizeof(not_defined), 1, fp) != 1)
417 goto fail;
418 }
419 return 1;
420fail:
421 return 0;
422}
423
424/*
425 * This should be called before coap_persist_track_funcs() to prevent
426 * coap_op_observe_added() getting unnecessarily called.
427 * It should be called after init_resources() and coap_op_resource_load_disk()
428 * so that all the resources are in place.
429 */
430static void
431coap_op_observe_load_disk(coap_context_t *ctx) {
432 FILE *fp_orig = fopen((const char *)ctx->observe_save_file->s, "r");
433 FILE *fp_new = NULL;
434 coap_subscription_t *observe_key = NULL;
435 coap_proto_t e_proto;
436 coap_address_t e_listen_addr;
437 coap_addr_tuple_t s_addr_info;
438 coap_bin_const_t *raw_packet = NULL;
439 coap_bin_const_t *oscore_info = NULL;
440 char *new = NULL;
441
442 if (fp_orig == NULL)
443 goto fail;
444
445 new = coap_malloc_type(COAP_STRING, ctx->observe_save_file->length + 5);
446 if (!new)
447 goto fail;
448
449 strcpy(new, (const char *)ctx->observe_save_file->s);
450 strcat(new, ".tmp");
451 fp_new = fopen(new, "w+");
452 if (fp_new == NULL)
453 goto fail;
454
455 /* Go through and load oscore entry, updating key on the way */
456 while (1) {
457 if (!coap_op_observe_read(fp_orig, &observe_key, &e_proto, &e_listen_addr,
458 &s_addr_info, &raw_packet, &oscore_info))
459 break;
460 coap_log_debug("persist: New session/observe being created\n");
461 observe_key = coap_persist_observe_add_lkd(ctx, e_proto,
462 &e_listen_addr,
463 &s_addr_info,
464 raw_packet,
465 oscore_info);
466 if (observe_key) {
467 if (!coap_op_observe_write(fp_new, observe_key, e_proto, e_listen_addr,
468 s_addr_info, raw_packet, oscore_info))
469 goto fail;
470 coap_delete_bin_const(raw_packet);
471 raw_packet = NULL;
472 coap_delete_bin_const(oscore_info);
473 oscore_info = NULL;
474 }
475 }
476 coap_delete_bin_const(raw_packet);
477 raw_packet = NULL;
478 coap_delete_bin_const(oscore_info);
479 oscore_info = NULL;
480
481 if (fflush(fp_new) == EOF)
482 goto fail;
483 fclose(fp_new);
484 fclose(fp_orig);
485 /* Either old or new is in place */
486 (void)rename(new, (const char *)ctx->observe_save_file->s);
488 return;
489
490fail:
491 coap_delete_bin_const(raw_packet);
492 coap_delete_bin_const(oscore_info);
493 if (fp_new)
494 fclose(fp_new);
495 if (fp_orig)
496 fclose(fp_orig);
497 if (new) {
498 (void)remove(new);
499 }
501 return;
502}
503
504/*
505 * client has registered a new observe subscription request.
506 */
507static int
508coap_op_observe_added(coap_session_t *session,
509 coap_subscription_t *a_observe_key,
510 coap_proto_t a_e_proto, coap_address_t *a_e_listen_addr,
511 coap_addr_tuple_t *a_s_addr_info,
512 coap_bin_const_t *a_raw_packet,
513 coap_bin_const_t *a_oscore_info, void *user_data) {
514 FILE *fp_orig = fopen((const char *)session->context->observe_save_file->s,
515 "r");
516 FILE *fp_new = NULL;
517 coap_subscription_t *observe_key = NULL;
518 coap_proto_t e_proto;
519 coap_address_t e_listen_addr;
520 coap_addr_tuple_t s_addr_info;
521 coap_bin_const_t *raw_packet = NULL;
522 coap_bin_const_t *oscore_info = NULL;
523 char *new = NULL;
524
525 (void)user_data;
526
528 session->context->observe_save_file->length + 5);
529 if (!new)
530 goto fail;
531
532 strcpy(new, (const char *)session->context->observe_save_file->s);
533 strcat(new, ".tmp");
534 fp_new = fopen(new, "w+");
535 if (fp_new == NULL)
536 goto fail;
537
538 /* Go through and delete observe entry if it exists */
539 while (fp_orig) {
540 if (!coap_op_observe_read(fp_orig, &observe_key, &e_proto, &e_listen_addr,
541 &s_addr_info, &raw_packet, &oscore_info))
542 break;
543 if (observe_key != a_observe_key) {
544 if (!coap_op_observe_write(fp_new, observe_key, e_proto, e_listen_addr,
545 s_addr_info, raw_packet, oscore_info))
546 goto fail;
547 }
548 coap_delete_bin_const(raw_packet);
549 raw_packet = NULL;
550 coap_delete_bin_const(oscore_info);
551 oscore_info = NULL;
552 }
553 coap_delete_bin_const(raw_packet);
554 raw_packet = NULL;
555 coap_delete_bin_const(oscore_info);
556 oscore_info = NULL;
557
558 /* Add in new entry to the end */
559 if (!coap_op_observe_write(fp_new, a_observe_key, a_e_proto, *a_e_listen_addr,
560 *a_s_addr_info, a_raw_packet, a_oscore_info))
561 goto fail;
562
563 if (fflush(fp_new) == EOF)
564 goto fail;
565 fclose(fp_new);
566 if (fp_orig)
567 fclose(fp_orig);
568 /* Either old or new is in place */
569 (void)rename(new, (const char *)session->context->observe_save_file->s);
571 return 1;
572
573fail:
574 coap_delete_bin_const(raw_packet);
575 coap_delete_bin_const(oscore_info);
576 if (fp_new)
577 fclose(fp_new);
578 if (fp_orig)
579 fclose(fp_orig);
580 if (new) {
581 (void)remove(new);
582 }
584 return 0;
585}
586
587/*
588 * client has de-registered a observe subscription request.
589 */
590static int
591coap_op_observe_deleted(coap_session_t *session,
592 coap_subscription_t *d_observe_key,
593 void *user_data) {
594 FILE *fp_orig = fopen((const char *)session->context->observe_save_file->s,
595 "r");
596 FILE *fp_new = NULL;
597 coap_subscription_t *observe_key = NULL;
598 coap_proto_t e_proto;
599 coap_address_t e_listen_addr;
600 coap_addr_tuple_t s_addr_info;
601 coap_bin_const_t *raw_packet = NULL;
602 coap_bin_const_t *oscore_info = NULL;
603 char *new = NULL;
604
605 (void)user_data;
606
607 if (fp_orig == NULL)
608 goto fail;
610 session->context->observe_save_file->length + 5);
611 if (!new)
612 goto fail;
613
614 strcpy(new, (const char *)session->context->observe_save_file->s);
615 strcat(new, ".tmp");
616 fp_new = fopen(new, "w+");
617 if (fp_new == NULL)
618 goto fail;
619
620 /* Go through and locate observe entry to delete and not copy it across */
621 while (1) {
622 if (!coap_op_observe_read(fp_orig, &observe_key, &e_proto, &e_listen_addr,
623 &s_addr_info, &raw_packet, &oscore_info))
624 break;
625 if (observe_key != d_observe_key) {
626 if (!coap_op_observe_write(fp_new, observe_key, e_proto, e_listen_addr,
627 s_addr_info, (coap_bin_const_t *)raw_packet,
628 (coap_bin_const_t *)oscore_info))
629 goto fail;
630 }
631 coap_delete_bin_const(raw_packet);
632 raw_packet = NULL;
633 coap_delete_bin_const(oscore_info);
634 oscore_info = NULL;
635 }
636 coap_delete_bin_const(raw_packet);
637 raw_packet = NULL;
638 coap_delete_bin_const(oscore_info);
639 oscore_info = NULL;
640
641 if (fflush(fp_new) == EOF)
642 goto fail;
643 fclose(fp_new);
644 fclose(fp_orig);
645 /* Either old or new is in place */
646 (void)rename(new, (const char *)session->context->observe_save_file->s);
648 return 1;
649
650fail:
651 coap_delete_bin_const(raw_packet);
652 coap_delete_bin_const(oscore_info);
653 if (fp_new)
654 fclose(fp_new);
655 if (fp_orig)
656 fclose(fp_orig);
657 if (new) {
658 (void)remove(new);
659 }
661 return 0;
662}
663
664/*
665 * This should be called before coap_persist_track_funcs() to prevent
666 * coap_op_obs_cnt_track_observe() getting unnecessarily called.
667 * Should be called after coap_op_dyn_resource_load_disk() to make sure that
668 * all the resources are in the right place.
669 */
670static void
671coap_op_obs_cnt_load_disk(coap_context_t *context) {
672 FILE *fp = fopen((const char *)context->obs_cnt_save_file->s, "r");
673 char buf[1500];
674
675 if (fp == NULL)
676 return;
677
678 while (fgets(buf, sizeof(buf), fp) != NULL) {
679 char *cp = strchr(buf, ' ');
680 coap_str_const_t resource_key;
681 uint32_t observe_num;
683
684 if (!cp)
685 break;
686
687 *cp = '\000';
688 cp++;
689 observe_num = atoi(cp);
690 /*
691 * Need to assume 0 .. (context->observe_save_freq-1) have in addition
692 * been sent so need to round up to latest possible send value
693 */
694 observe_num = ((observe_num + context->observe_save_freq) /
695 context->observe_save_freq) *
696 context->observe_save_freq - 1;
697 resource_key.s = (uint8_t *)buf;
698 resource_key.length = strlen(buf);
699 r = coap_get_resource_from_uri_path_lkd(context, &resource_key);
700 if (r) {
701 coap_log_debug("persist: Initial observe number being updated\n");
702 coap_persist_set_observe_num(r, observe_num);
703 }
704 }
705 fclose(fp);
706}
707
708/*
709 * Called when the observe value of a resource has been changed, but limited
710 * to be called every context->context->observe_save_freq to reduce update
711 * overheads.
712 */
713static int
714coap_op_obs_cnt_track_observe(coap_context_t *context,
715 coap_str_const_t *resource_name,
716 uint32_t n_observe_num,
717 void *user_data) {
718 FILE *fp_orig = fopen((const char *)context->obs_cnt_save_file->s, "r");
719 FILE *fp_new = NULL;
720 char buf[1500];
721 char *new = NULL;
722
723 (void)user_data;
724
725 new = coap_malloc_type(COAP_STRING, context->obs_cnt_save_file->length + 5);
726 if (!new)
727 goto fail;
728
729 strcpy(new, (const char *)context->obs_cnt_save_file->s);
730 strcat(new, ".tmp");
731 fp_new = fopen(new, "w+");
732 if (fp_new == NULL)
733 goto fail;
734
735 /* Go through and locate resource entry to update */
736 while (fp_orig && fgets(buf, sizeof(buf), fp_orig) != NULL) {
737 char *cp = strchr(buf, ' ');
738 uint32_t observe_num;
739 coap_bin_const_t resource_key;
740
741 if (!cp)
742 break;
743
744 *cp = '\000';
745 cp++;
746 observe_num = atoi(cp);
747 resource_key.s = (uint8_t *)buf;
748 resource_key.length = strlen(buf);
749 if (!coap_binary_equal(resource_name, &resource_key)) {
750 if (fprintf(fp_new, "%s %u\n", resource_key.s, observe_num) < 0)
751 goto fail;
752 }
753 }
754 if (fprintf(fp_new, "%s %u\n", resource_name->s, n_observe_num) < 0)
755 goto fail;
756 if (fflush(fp_new) == EOF)
757 goto fail;
758 fclose(fp_new);
759 if (fp_orig)
760 fclose(fp_orig);
761 /* Either old or new is in place */
762 (void)rename(new, (const char *)context->obs_cnt_save_file->s);
764 return 1;
765
766fail:
767 if (fp_new)
768 fclose(fp_new);
769 if (fp_orig)
770 fclose(fp_orig);
771 if (new) {
772 (void)remove(new);
773 }
775 return 0;
776}
777
778/*
779 * Called when a resource has been deleted.
780 */
781static int
782coap_op_obs_cnt_deleted(coap_context_t *context,
783 coap_str_const_t *resource_name) {
784 FILE *fp_orig = fopen((const char *)context->obs_cnt_save_file->s, "r");
785 FILE *fp_new = NULL;
786 char buf[1500];
787 char *new = NULL;
788
789 if (fp_orig == NULL)
790 goto fail;
791 new = coap_malloc_type(COAP_STRING, context->obs_cnt_save_file->length + 5);
792 if (!new)
793 goto fail;
794
795 strcpy(new, (const char *)context->obs_cnt_save_file->s);
796 strcat(new, ".tmp");
797 fp_new = fopen(new, "w+");
798 if (fp_new == NULL)
799 goto fail;
800
801 /* Go through and locate resource entry to delete */
802 while (fgets(buf, sizeof(buf), fp_orig) != NULL) {
803 char *cp = strchr(buf, ' ');
804 uint32_t observe_num;
805 coap_bin_const_t resource_key;
806
807 if (!cp)
808 break;
809
810 *cp = '\000';
811 cp++;
812 observe_num = atoi(cp);
813 resource_key.s = (uint8_t *)buf;
814 resource_key.length = strlen(buf);
815 if (!coap_binary_equal(resource_name, &resource_key)) {
816 if (fprintf(fp_new, "%s %u\n", resource_key.s, observe_num) < 0)
817 goto fail;
818 }
819 }
820 if (fflush(fp_new) == EOF)
821 goto fail;
822 fclose(fp_new);
823 fclose(fp_orig);
824 /* Either old or new is in place */
825 (void)rename(new, (const char *)context->obs_cnt_save_file->s);
827 return 1;
828
829fail:
830 if (fp_new)
831 fclose(fp_new);
832 if (fp_orig)
833 fclose(fp_orig);
834 if (new) {
835 (void)remove(new);
836 }
838 return 0;
839}
840
841/*
842 * read in dynamic resource entry, allocating name & raw_packet
843 * which need to be freed off by caller.
844 */
845static int
846coap_op_dyn_resource_read(FILE *fp, coap_proto_t *e_proto,
847 coap_string_t **name,
848 coap_binary_t **raw_packet) {
849 ssize_t size;
850
851 *name = NULL;
852 *raw_packet = NULL;
853
854 if (fread(e_proto, sizeof(*e_proto), 1, fp) == 1) {
855 /* New record 'proto len resource_name len raw_packet' */
856 if (fread(&size, sizeof(size), 1, fp) != 1)
857 goto fail;
858 if (size < 0 || size > 0x10000)
859 goto fail;
860 *name = coap_new_string(size);
861 if (!(*name))
862 goto fail;
863 if (fread((*name)->s, size, 1, fp) != 1)
864 goto fail;
865 if (fread(&size, sizeof(size), 1, fp) != 1)
866 goto fail;
867 if (size < 0 || size > 0x10000)
868 goto fail;
869 *raw_packet = coap_new_binary(size);
870 if (!(*raw_packet))
871 goto fail;
872 if (fread((*raw_packet)->s, size, 1, fp) != 1)
873 goto fail;
874 return 1;
875 }
876fail:
877 return 0;
878}
879
880/*
881 * write out dynamic resource entry.
882 */
883static int
884coap_op_dyn_resource_write(FILE *fp, coap_proto_t e_proto,
885 coap_str_const_t *name,
886 coap_bin_const_t *raw_packet) {
887 if (fwrite(&e_proto, sizeof(e_proto), 1, fp) != 1)
888 goto fail;
889 if (fwrite(&name->length, sizeof(name->length), 1, fp) != 1)
890 goto fail;
891 if (fwrite(name->s, name->length, 1, fp) != 1)
892 goto fail;
893 if (fwrite(&raw_packet->length, sizeof(raw_packet->length), 1, fp) != 1)
894 goto fail;
895 if (fwrite(raw_packet->s, raw_packet->length, 1, fp) != 1)
896 goto fail;
897 return 1;
898fail:
899 return 0;
900}
901
902/*
903 * This should be called before coap_persist_track_funcs() to prevent
904 * coap_op_dyn_resource_added() getting unnecessarily called.
905 *
906 * Each record 'proto len resource_name len raw_packet'
907 */
908static void
909coap_op_dyn_resource_load_disk(coap_context_t *ctx) {
910 FILE *fp_orig = NULL;
911 coap_proto_t e_proto;
912 coap_string_t *name = NULL;
913 coap_binary_t *raw_packet = NULL;
915 coap_session_t *session = NULL;
916 coap_pdu_t *request = NULL;
917 coap_pdu_t *response = NULL;
918 coap_string_t *query = NULL;
919
920 if (!ctx->unknown_resource)
921 return;
922
923 fp_orig = fopen((const char *)ctx->dyn_resource_save_file->s, "r");
924 if (fp_orig == NULL)
925 return;
927 sizeof(coap_session_t));
928 if (!session)
929 goto fail;
930 memset(session, 0, sizeof(coap_session_t));
931 session->context = ctx;
932
933 /* Go through and create each dynamic resource if it does not exist*/
934 while (1) {
935 if (!coap_op_dyn_resource_read(fp_orig, &e_proto, &name, &raw_packet))
936 break;
938 if (!r) {
939 /* Create the new resource using the application logic */
940
941 coap_log_debug("persist: dynamic resource being re-created\n");
942 /*
943 * Need max space incase PDU is updated with updated token,
944 * huge size etc.
945 * */
946 request = coap_pdu_init(0, 0, 0, 0);
947 if (!request)
948 goto fail;
949
950 session->proto = e_proto;
951 if (!coap_pdu_parse(session->proto, raw_packet->s,
952 raw_packet->length, request)) {
953 goto fail;
954 }
955 if (!ctx->unknown_resource->handler[request->code-1])
956 goto fail;
957 response = coap_pdu_init(0, 0, 0, 0);
958 if (!response)
959 goto fail;
960 query = coap_get_query(request);
961 /* Call the application handler to set up this dynamic resource */
963 ctx->unknown_resource->handler[request->code-1](ctx->unknown_resource,
964 session, request,
965 query, response),
966 /* context is being freed off */
967 goto fail);
968 coap_delete_string(query);
969 query = NULL;
970 coap_delete_pdu(request);
971 request = NULL;
972 coap_delete_pdu(response);
973 response = NULL;
974 }
975 coap_delete_string(name);
976 coap_delete_binary(raw_packet);
977 }
978fail:
979 coap_delete_string(name);
980 coap_delete_binary(raw_packet);
981 coap_delete_string(query);
982 coap_delete_pdu(request);
983 coap_delete_pdu(response);
984 fclose(fp_orig);
986}
987
988/*
989 * Server has set up a new dynamic resource agains a request for an unknown
990 * resource.
991 */
992static int
993coap_op_dyn_resource_added(coap_session_t *session,
994 coap_str_const_t *resource_name,
995 coap_bin_const_t *packet,
996 void *user_data) {
997 FILE *fp_orig;
998 FILE *fp_new = NULL;
999 char *new = NULL;
1000 coap_context_t *context = session->context;
1001 coap_string_t *name = NULL;
1002 coap_binary_t *raw_packet = NULL;
1003 coap_proto_t e_proto;
1004
1005 (void)user_data;
1006
1007 fp_orig = fopen((const char *)context->dyn_resource_save_file->s, "a");
1008 if (fp_orig == NULL)
1009 return 0;
1010
1012 context->dyn_resource_save_file->length + 5);
1013 if (!new)
1014 goto fail;
1015
1016 strcpy(new, (const char *)context->dyn_resource_save_file->s);
1017 strcat(new, ".tmp");
1018 fp_new = fopen(new, "w+");
1019 if (fp_new == NULL)
1020 goto fail;
1021
1022 /* Go through and locate duplicate resource to delete */
1023 while (1) {
1024 if (!coap_op_dyn_resource_read(fp_orig, &e_proto, &name, &raw_packet))
1025 break;
1026 if (!coap_string_equal(resource_name, name)) {
1027 /* Copy across non-matching entry */
1028 if (!coap_op_dyn_resource_write(fp_new, e_proto, (coap_str_const_t *)name,
1029 (coap_bin_const_t *)raw_packet))
1030 break;
1031 }
1032 coap_delete_string(name);
1033 name = NULL;
1034 coap_delete_binary(raw_packet);
1035 raw_packet = NULL;
1036 }
1037 coap_delete_string(name);
1038 coap_delete_binary(raw_packet);
1039 /* Add new entry to the end */
1040 if (!coap_op_dyn_resource_write(fp_new, session->proto,
1041 resource_name, packet))
1042 goto fail;
1043
1044 if (fflush(fp_new) == EOF)
1045 goto fail;
1046 fclose(fp_new);
1047 fclose(fp_orig);
1048 /* Either old or new is in place */
1049 (void)rename(new, (const char *)context->dyn_resource_save_file->s);
1051 return 1;
1052
1053fail:
1054 if (fp_new)
1055 fclose(fp_new);
1056 if (fp_orig)
1057 fclose(fp_orig);
1058 if (new) {
1059 (void)remove(new);
1060 }
1062 return 0;
1063}
1064
1065/*
1066 * Server has deleted a resource
1067 */
1068static int
1069coap_op_resource_deleted(coap_context_t *context,
1070 coap_str_const_t *resource_name,
1071 void *user_data) {
1072 FILE *fp_orig = NULL;
1073 FILE *fp_new = NULL;
1074 char *new = NULL;
1075 coap_proto_t e_proto;
1076 coap_string_t *name = NULL;
1077 coap_binary_t *raw_packet = NULL;
1078 (void)user_data;
1079
1080 coap_op_obs_cnt_deleted(context, resource_name);
1081
1082 fp_orig = fopen((const char *)context->dyn_resource_save_file->s, "r");
1083 if (fp_orig == NULL)
1084 return 1;
1085
1087 context->dyn_resource_save_file->length + 5);
1088 if (!new)
1089 goto fail;
1090
1091 strcpy(new, (const char *)context->dyn_resource_save_file->s);
1092 strcat(new, ".tmp");
1093 fp_new = fopen(new, "w+");
1094 if (fp_new == NULL)
1095 goto fail;
1096
1097 /* Go through and locate resource to delete and not copy it across */
1098 while (1) {
1099 if (!coap_op_dyn_resource_read(fp_orig, &e_proto, &name, &raw_packet))
1100 break;
1101 if (!coap_string_equal(resource_name, name)) {
1102 /* Copy across non-matching entry */
1103 if (!coap_op_dyn_resource_write(fp_new, e_proto, (coap_str_const_t *)name,
1104 (coap_bin_const_t *)raw_packet))
1105 break;
1106 }
1107 coap_delete_string(name);
1108 name = NULL;
1109 coap_delete_binary(raw_packet);
1110 raw_packet = NULL;
1111 }
1112 coap_delete_string(name);
1113 coap_delete_binary(raw_packet);
1114
1115 if (fflush(fp_new) == EOF)
1116 goto fail;
1117 fclose(fp_new);
1118 fclose(fp_orig);
1119 /* Either old or new is in place */
1120 (void)rename(new, (const char *)context->dyn_resource_save_file->s);
1122 return 1;
1123
1124fail:
1125 if (fp_new)
1126 fclose(fp_new);
1127 if (fp_orig)
1128 fclose(fp_orig);
1129 if (new) {
1130 (void)remove(new);
1131 }
1133 return 0;
1134}
1135
1136COAP_API int
1138 const char *dyn_resource_save_file,
1139 const char *observe_save_file,
1140 const char *obs_cnt_save_file,
1141 uint32_t save_freq) {
1142 int ret;
1143
1144 coap_lock_lock(context, return 0);
1145 ret = coap_persist_startup_lkd(context,
1146 dyn_resource_save_file,
1147 observe_save_file,
1148 obs_cnt_save_file,
1149 save_freq);
1150 coap_lock_unlock(context);
1151 return ret;
1152}
1153
1154int
1156 const char *dyn_resource_save_file,
1157 const char *observe_save_file,
1158 const char *obs_cnt_save_file,
1159 uint32_t save_freq) {
1160 coap_lock_check_locked(context);
1161 if (dyn_resource_save_file) {
1162 context->dyn_resource_save_file =
1163 coap_new_bin_const((const uint8_t *)dyn_resource_save_file,
1164 strlen(dyn_resource_save_file));
1165 if (!context->dyn_resource_save_file)
1166 return 0;
1167 coap_op_dyn_resource_load_disk(context);
1168 context->dyn_resource_added = coap_op_dyn_resource_added;
1169 context->resource_deleted = coap_op_resource_deleted;
1170 }
1171 if (obs_cnt_save_file) {
1172 context->obs_cnt_save_file =
1173 coap_new_bin_const((const uint8_t *)obs_cnt_save_file,
1174 strlen(obs_cnt_save_file));
1175 if (!context->obs_cnt_save_file)
1176 return 0;
1177 context->observe_save_freq = save_freq ? save_freq : 1;
1178 coap_op_obs_cnt_load_disk(context);
1179 context->track_observe_value = coap_op_obs_cnt_track_observe;
1180 context->resource_deleted = coap_op_resource_deleted;
1181 }
1182 if (observe_save_file) {
1183 context->observe_save_file =
1184 coap_new_bin_const((const uint8_t *)observe_save_file,
1185 strlen(observe_save_file));
1186 if (!context->observe_save_file)
1187 return 0;
1188 coap_op_observe_load_disk(context);
1189 context->observe_added = coap_op_observe_added;
1190 context->observe_deleted = coap_op_observe_deleted;
1191 }
1192 return 1;
1193}
1194
1195void
1197 coap_delete_bin_const(context->dyn_resource_save_file);
1198 coap_delete_bin_const(context->obs_cnt_save_file);
1199 coap_delete_bin_const(context->observe_save_file);
1200 context->dyn_resource_save_file = NULL;
1201 context->obs_cnt_save_file = NULL;
1202 context->observe_save_file = NULL;
1203
1204 /* Close down any tracking */
1205 coap_persist_track_funcs(context, NULL, NULL, NULL, NULL,
1206 NULL, 0, NULL);
1207}
1208
1209COAP_API void
1211 if (!context)
1212 return;
1213 coap_lock_lock(context, return);
1214 coap_persist_stop_lkd(context);
1215 coap_lock_unlock(context);
1216}
1217
1218void
1220 if (context == NULL)
1221 return;
1222 coap_lock_check_locked(context);
1223 context->observe_no_clear = 1;
1224 coap_persist_cleanup(context);
1225}
1226#else /* ! COAP_WITH_OBSERVE_PERSIST */
1227COAP_API int
1229 const char *dyn_resource_save_file,
1230 const char *observe_save_file,
1231 const char *obs_cnt_save_file,
1232 uint32_t save_freq) {
1233 (void)context;
1234 (void)dyn_resource_save_file;
1235 (void)observe_save_file;
1236 (void)obs_cnt_save_file;
1237 (void)save_freq;
1238 return 0;
1239}
1240
1241COAP_API void
1243 context->observe_no_clear = 1;
1244 /* Close down any tracking */
1245 coap_persist_track_funcs(context, NULL, NULL, NULL, NULL,
1246 NULL, 0, NULL);
1247}
1248
1249#endif /* ! COAP_WITH_OBSERVE_PERSIST */
1250
1251#endif /* COAP_SERVER_SUPPORT */
Library specific build wrapper for coap_internal.h.
#define COAP_API
@ COAP_SESSION
Definition: coap_mem.h:51
@ COAP_STRING
Definition: coap_mem.h:39
void * coap_malloc_type(coap_memory_tag_t type, size_t size)
Allocates a chunk of size bytes and returns a pointer to the newly allocated memory.
void coap_free_type(coap_memory_tag_t type, void *p)
Releases the memory that was allocated by coap_malloc_type().
uint8_t coap_opt_t
Use byte-oriented access methods here because sliding a complex struct coap_opt_t over the data buffe...
Definition: coap_option.h:26
uint64_t coap_tick_t
This data type represents internal timer ticks with COAP_TICKS_PER_SECOND resolution.
Definition: coap_time.h:143
coap_resource_t * coap_get_resource_from_uri_path_lkd(coap_context_t *context, coap_str_const_t *uri_path)
Returns the resource identified by the unique string uri_path.
void coap_ticks(coap_tick_t *)
Returns the current value of an internal tick counter.
unsigned int coap_decode_var_bytes(const uint8_t *buf, size_t len)
Decodes multiple-length byte sequences.
Definition: coap_encode.c:38
#define coap_lock_callback_release(c, func, failed)
Dummy for no thread-safe code.
#define coap_lock_unlock(c)
Dummy for no thread-safe code.
#define coap_lock_lock(c, failed)
Dummy for no thread-safe code.
#define coap_lock_check_locked(c)
Dummy for no thread-safe code.
#define coap_log_debug(...)
Definition: coap_debug.h:120
#define coap_log_warn(...)
Definition: coap_debug.h:102
@ COAP_LOG_OSCORE
Definition: coap_debug.h:59
COAP_API coap_subscription_t * coap_persist_observe_add(coap_context_t *context, coap_proto_t e_proto, const coap_address_t *e_listen_addr, const coap_addr_tuple_t *s_addr_info, const coap_bin_const_t *raw_packet, const coap_bin_const_t *oscore_info)
Set up an active subscription for an observe that was previously active over a coap-server inadvertan...
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)
Callback handler definition called when a dynamic resource is getting created, as defined in coap_per...
void coap_persist_set_observe_num(coap_resource_t *resource, uint32_t observe_num)
Sets the current observe number value.
int(* coap_resource_deleted_t)(coap_context_t *context, coap_str_const_t *resource_name, void *user_data)
Callback handler definition called when resource is removed, as defined in coap_persist_track_funcs()...
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)
Callback handler definition called when a new observe has been set up, as defined in coap_persist_tra...
#define COAP_OBSERVE_ESTABLISH
The value COAP_OBSERVE_ESTABLISH in a GET/FETCH request option COAP_OPTION_OBSERVE indicates a new ob...
COAP_API void coap_persist_stop(coap_context_t *context)
Stop tracking persist information, leaving the current persist information in the files defined in co...
void coap_persist_track_funcs(coap_context_t *context, coap_observe_added_t observe_added, coap_observe_deleted_t observe_deleted, coap_track_observe_value_t track_observe_value, coap_dyn_resource_added_t dyn_resource_added, coap_resource_deleted_t resource_deleted, uint32_t save_freq, void *user_data)
Set up callbacks to handle persist tracking so on a coap-server inadvertent restart,...
int(* coap_track_observe_value_t)(coap_context_t *context, coap_str_const_t *resource_name, uint32_t observe_num, void *user_data)
Callback handler definition called when an observe unsolicited response is being sent,...
int(* coap_observe_deleted_t)(coap_session_t *session, coap_subscription_t *observe_key, void *user_data)
Callback handler definition called when an observe is being removed, as defined in coap_persist_track...
COAP_API int coap_persist_startup(coap_context_t *context, const char *dyn_resource_save_file, const char *observe_save_file, const char *obs_cnt_save_file, uint32_t save_freq)
Start up persist tracking using the libcoap module.
uint32_t coap_opt_length(const coap_opt_t *opt)
Returns the length of the given option.
Definition: coap_option.c:212
coap_opt_t * coap_check_option(const coap_pdu_t *pdu, coap_option_num_t number, coap_opt_iterator_t *oi)
Retrieves the first option of number number from pdu.
Definition: coap_option.c:199
const uint8_t * coap_opt_value(const coap_opt_t *opt)
Returns a pointer to the value of the given option.
Definition: coap_option.c:249
#define CBOR_BYTE_STRING
Definition: oscore_cbor.h:62
size_t oscore_cbor_get_element_size(const uint8_t **buffer, size_t *buf_len)
Definition: oscore_cbor.c:240
#define CBOR_NULL
Definition: oscore_cbor.h:72
#define CBOR_SIMPLE_VALUE
Definition: oscore_cbor.h:67
uint8_t oscore_cbor_get_next_element(const uint8_t **buffer, size_t *buf_len)
Definition: oscore_cbor.c:227
#define CBOR_ARRAY
Definition: oscore_cbor.h:64
int oscore_new_association(coap_session_t *session, coap_pdu_t *sent_pdu, coap_bin_const_t *token, oscore_recipient_ctx_t *recipient_ctx, coap_bin_const_t *aad, coap_bin_const_t *nonce, coap_bin_const_t *partial_iv, int is_observe)
void oscore_log_hex_value(coap_log_t level, const char *name, coap_bin_const_t *value)
oscore_ctx_t * oscore_find_context(const coap_context_t *c_context, const coap_bin_const_t rcpkey_id, const coap_bin_const_t *ctxkey_id, uint8_t *oscore_r2, oscore_recipient_ctx_t **recipient_ctx)
oscore_find_context - Locate recipient context (and hence OSCORE context)
void coap_delete_pdu(coap_pdu_t *pdu)
Dispose of an CoAP PDU and frees associated storage.
Definition: coap_pdu.c:183
coap_proto_t
CoAP protocol types.
Definition: coap_pdu.h:312
int coap_pdu_parse(coap_proto_t proto, const uint8_t *data, size_t length, coap_pdu_t *pdu)
Parses data into the CoAP PDU structure given in result.
Definition: coap_pdu.c:1455
coap_pdu_t * coap_pdu_init(coap_pdu_type_t type, coap_pdu_code_t code, coap_mid_t mid, size_t size)
Creates a new CoAP PDU with at least enough storage space for the given size maximum message size.
Definition: coap_pdu.c:99
#define COAP_OPTION_OBSERVE
Definition: coap_pdu.h:123
@ COAP_PROTO_UDP
Definition: coap_pdu.h:314
@ COAP_REQUEST_CODE_GET
Definition: coap_pdu.h:329
@ COAP_REQUEST_CODE_FETCH
Definition: coap_pdu.h:333
coap_session_t * coap_endpoint_get_session(coap_endpoint_t *endpoint, const coap_packet_t *packet, coap_tick_t now)
Lookup the server session for the packet received on an endpoint, or create a new one.
void coap_delete_bin_const(coap_bin_const_t *s)
Deletes the given const binary data and releases any memory allocated.
Definition: coap_str.c:120
coap_binary_t * coap_new_binary(size_t size)
Returns a new binary object with at least size bytes storage allocated.
Definition: coap_str.c:77
coap_bin_const_t * coap_new_bin_const(const uint8_t *data, size_t size)
Take the specified byte array (text) and create a coap_bin_const_t * Returns a new const binary objec...
Definition: coap_str.c:110
void coap_delete_binary(coap_binary_t *s)
Deletes the given coap_binary_t object and releases any memory allocated.
Definition: coap_str.c:105
#define coap_binary_equal(binary1, binary2)
Compares the two binary data for equality.
Definition: coap_str.h:211
#define coap_string_equal(string1, string2)
Compares the two strings for equality.
Definition: coap_str.h:197
coap_string_t * coap_new_string(size_t size)
Returns a new string object with at least size+1 bytes storage allocated.
Definition: coap_str.c:21
void coap_delete_string(coap_string_t *s)
Deletes the given string and releases any memory allocated.
Definition: coap_str.c:46
void coap_persist_stop_lkd(coap_context_t *context)
Stop tracking persist information, leaving the current persist information in the files defined in co...
void coap_persist_cleanup(coap_context_t *context)
Close down persist tracking, releasing any memory used.
coap_subscription_t * coap_persist_observe_add_lkd(coap_context_t *context, coap_proto_t e_proto, const coap_address_t *e_listen_addr, const coap_addr_tuple_t *s_addr_info, const coap_bin_const_t *raw_packet, const coap_bin_const_t *oscore_info)
Set up an active subscription for an observe that was previously active over a coap-server inadvertan...
void coap_subscription_init(coap_subscription_t *)
coap_subscription_t * coap_add_observer(coap_resource_t *resource, coap_session_t *session, const coap_bin_const_t *token, const coap_pdu_t *pdu)
Adds the specified peer as observer for resource.
int coap_persist_startup_lkd(coap_context_t *context, const char *dyn_resource_save_file, const char *observe_save_file, const char *obs_cnt_save_file, uint32_t save_freq)
Start up persist tracking using the libcoap module.
int coap_observe_persist_is_supported(void)
Check whether Observe Persist is available.
coap_string_t * coap_get_uri_path(const coap_pdu_t *request)
Extract uri_path string from request PDU.
Definition: coap_uri.c:985
coap_string_t * coap_get_query(const coap_pdu_t *request)
Extract query string from request PDU according to escape rules in 6.5.8.
Definition: coap_uri.c:934
Multi-purpose address abstraction.
Definition: coap_address.h:148
CoAP binary data definition with const data.
Definition: coap_str.h:64
size_t length
length of binary data
Definition: coap_str.h:65
const uint8_t * s
read-only binary data
Definition: coap_str.h:66
CoAP binary data definition.
Definition: coap_str.h:56
size_t length
length of binary data
Definition: coap_str.h:57
uint8_t * s
binary data
Definition: coap_str.h:58
The CoAP stack's global state is stored in a coap_context_t object.
coap_observe_added_t observe_added
Called when there is a new observe subscription request.
coap_dyn_resource_added_t dyn_resource_added
Callback to save dynamic resource when created.
void * observe_user_data
App provided data for use in observe_added or observe_deleted.
coap_track_observe_value_t track_observe_value
Callback to save observe value when updated.
coap_endpoint_t * endpoint
the endpoints used for listening
uint32_t observe_save_freq
How frequently to update observe value.
uint8_t observe_no_clear
Observe 4.04 not to be sent on deleting resource.
coap_observe_deleted_t observe_deleted
Called when there is a observe subscription de-register request.
coap_resource_t * unknown_resource
can be used for handling unknown resources
coap_resource_deleted_t resource_deleted
Invoked when resource is deleted.
Abstraction of virtual endpoint that can be attached to coap_context_t.
struct coap_endpoint_t * next
coap_address_t bind_addr
local interface address
coap_proto_t proto
protocol used on this interface
Iterator to run through PDU options.
Definition: coap_option.h:168
size_t length
length of payload
coap_addr_tuple_t addr_info
local and remote addresses
unsigned char * payload
payload
int ifindex
the interface index
structure for CoAP PDUs
size_t max_size
maximum size for token, options and payload, or zero for variable size pdu
coap_pdu_code_t code
request method (value 1–31) or response code (value 64-255)
coap_bin_const_t actual_token
Actual token in pdu.
size_t used_size
used bytes of storage for token, options and payload
Abstraction of resource that can be attached to coap_context_t.
coap_method_handler_t handler[7]
Used to store handlers for the seven coap methods GET, POST, PUT, DELETE, FETCH, PATCH and IPATCH.
unsigned int observable
can be observed
Abstraction of virtual session that can be attached to coap_context_t (client) or coap_endpoint_t (se...
coap_proto_t proto
protocol used
coap_context_t * context
session's context
CoAP string data definition with const data.
Definition: coap_str.h:46
const uint8_t * s
read-only string data
Definition: coap_str.h:48
size_t length
length of string
Definition: coap_str.h:47
CoAP string data definition.
Definition: coap_str.h:38
uint8_t * s
string data
Definition: coap_str.h:40
Number of notifications that may be sent non-confirmable before a confirmable message is sent to dete...