libcoap 4.3.5-develop-433f483
Loading...
Searching...
No Matches
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-2025 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(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);
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
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) {
121#ifndef INET6_ADDRSTRLEN
122#define INET6_ADDRSTRLEN 40
123#endif
124 unsigned char addr_str[INET6_ADDRSTRLEN + 8];
125
126 if (coap_print_addr(e_listen_addr, addr_str, INET6_ADDRSTRLEN + 8)) {
127 coap_log_warn("coap_persist_observe_add: Endpoint %s not defined\n",
128 addr_str);
129 }
130 }
131 return NULL;
132 }
133
134 /* Build up packet */
135 memcpy(&packet->addr_info, s_addr_info, sizeof(packet->addr_info));
136 packet->ifindex = 0;
137 memcpy(&packet->payload, &raw_packet->s, sizeof(packet->payload));
138 packet->length = raw_packet->length;
139
140 data = raw_packet->s;
141 data_len = raw_packet->length;
142 if (data_len < 4)
143 goto malformed;
144
145 /* Get the session */
146
147 coap_ticks(&now);
148 session = coap_endpoint_get_session(ep, packet, now);
149 if (session == NULL)
150 goto fail;
151 /* Need max space incase PDU is updated with updated token, huge size etc. */
152 pdu = coap_pdu_init(0, 0, 0, 0);
153 if (!pdu)
154 goto fail;
155
156 if (!coap_pdu_parse(session->proto, data, data_len, pdu)) {
157 goto malformed;
158 }
159 pdu->max_size = pdu->used_size;
160
161 if (pdu->code != COAP_REQUEST_CODE_GET &&
163 goto malformed;
164
165 observe = coap_check_option(pdu, COAP_OPTION_OBSERVE, &opt_iter);
166 if (observe == NULL)
167 goto malformed;
168 observe_action = coap_decode_var_bytes(coap_opt_value(observe),
169 coap_opt_length(observe));
170 if (observe_action != COAP_OBSERVE_ESTABLISH)
171 goto malformed;
172
173 /* Get the resource */
174
175 uri_path = coap_get_uri_path(pdu);
176 if (!uri_path)
177 goto malformed;
178
180 (coap_str_const_t *)uri_path);
181 if (r == NULL) {
182 coap_log_warn("coap_persist_observe_add: resource '%s' not defined\n",
183 uri_path->s);
184 goto fail;
185 }
186 if (!r->observable) {
187 coap_log_warn("coap_persist_observe_add: resource '%s' not observable\n",
188 uri_path->s);
189 goto fail;
190 }
191 coap_delete_string(uri_path);
192 uri_path = NULL;
193
194 /* Create / update subscription for observing */
195 /* Now set up the subscription */
196 s = coap_add_observer(r, session, &pdu->actual_token, pdu);
197 if (s == NULL)
198 goto fail;
199
200#if COAP_OSCORE_SUPPORT
201 if (oscore_info) {
202 coap_log_debug("persist: OSCORE association being updated\n");
203 /*
204 * Need to track the association used for tracking this observe, done as
205 * a CBOR array. Written in coap_add_observer().
206 *
207 * If an entry is null, then use nil, else a set of bytes
208 *
209 * Currently tracking 5 items
210 * recipient_id
211 * id_context
212 * aad (from oscore_association_t)
213 * partial_iv (from oscore_association_t)
214 * nonce (from oscore_association_t)
215 */
216 oscore_ctx_t *osc_ctx;
217 const uint8_t *info_buf = oscore_info->s;
218 size_t info_buf_len = oscore_info->length;
219 size_t ret = 0;
220 coap_bin_const_t oscore_key_id;
221 coap_bin_const_t partial_iv;
223 coap_bin_const_t id_context;
224 coap_bin_const_t nonce;
225 int have_aad = 0;
226 int have_partial_iv = 0;
227 int have_id_context = 0;
228 int have_nonce = 0;
229
230 ret = oscore_cbor_get_next_element(&info_buf, &info_buf_len);
231 if (ret != CBOR_ARRAY)
232 goto oscore_fail;
233 if (oscore_cbor_get_element_size(&info_buf, &info_buf_len) != 5)
234 goto oscore_fail;
235
236 /* recipient_id */
237 ret = oscore_cbor_get_next_element(&info_buf, &info_buf_len);
238 if (ret != CBOR_BYTE_STRING)
239 goto oscore_fail;
240 oscore_key_id.length = oscore_cbor_get_element_size(&info_buf,
241 &info_buf_len);
242 oscore_key_id.s = info_buf;
243 info_buf += oscore_key_id.length;
244
245 /* id_context */
246 ret = oscore_cbor_get_next_element(&info_buf, &info_buf_len);
247 if (ret == CBOR_BYTE_STRING) {
248 id_context.length = oscore_cbor_get_element_size(&info_buf,
249 &info_buf_len);
250 id_context.s = info_buf;
251 info_buf += id_context.length;
252 have_id_context = 1;
253 } else if (ret == CBOR_SIMPLE_VALUE &&
255 &info_buf_len) == CBOR_NULL) {
256 } else
257 goto oscore_fail;
258
259 /* aad */
260 ret = oscore_cbor_get_next_element(&info_buf, &info_buf_len);
261 if (ret == CBOR_BYTE_STRING) {
262 aad.length = oscore_cbor_get_element_size(&info_buf, &info_buf_len);
263 aad.s = info_buf;
264 info_buf += aad.length;
265 have_aad = 1;
266 } else if (ret == CBOR_SIMPLE_VALUE &&
268 &info_buf_len) == CBOR_NULL) {
269 } else
270 goto oscore_fail;
271
272 /* partial_iv */
273 ret = oscore_cbor_get_next_element(&info_buf, &info_buf_len);
274 if (ret == CBOR_BYTE_STRING) {
275 partial_iv.length = oscore_cbor_get_element_size(&info_buf,
276 &info_buf_len);
277 partial_iv.s = info_buf;
278 info_buf += partial_iv.length;
279 have_partial_iv = 1;
280 } else if (ret == CBOR_SIMPLE_VALUE &&
282 &info_buf_len) == CBOR_NULL) {
283 } else
284 goto oscore_fail;
285
286 /* nonce */
287 ret = oscore_cbor_get_next_element(&info_buf, &info_buf_len);
288 if (ret == CBOR_BYTE_STRING) {
289 nonce.length = oscore_cbor_get_element_size(&info_buf,
290 &info_buf_len);
291 nonce.s = info_buf;
292 info_buf += nonce.length;
293 have_nonce = 1;
294 } else if (ret == CBOR_SIMPLE_VALUE &&
296 &info_buf_len) == CBOR_NULL) {
297 } else
298 goto oscore_fail;
299
300 osc_ctx = oscore_find_context(session->context, oscore_key_id,
301 have_id_context ? &id_context : NULL, NULL,
302 &session->recipient_ctx);
303 if (osc_ctx) {
304 session->oscore_encryption = 1;
305 oscore_new_association(session, pdu, &pdu->actual_token,
306 session->recipient_ctx,
307 have_aad ? &aad : NULL,
308 have_nonce ? &nonce : NULL,
309 have_partial_iv ? &partial_iv : NULL,
310 1);
311 coap_log_debug("persist: OSCORE association added\n");
313 have_partial_iv ? &partial_iv : NULL);
314 }
315 }
316oscore_fail:
317#else /* ! COAP_OSCORE_SUPPORT */
318 (void)oscore_info;
319#endif /* ! COAP_OSCORE_SUPPORT */
321 return s;
322
323malformed:
324 coap_log_warn("coap_persist_observe_add: discard malformed PDU\n");
325fail:
326 coap_delete_string(uri_path);
328 return NULL;
329}
330
331#if COAP_WITH_OBSERVE_PERSIST
332#include <stdio.h>
333
334/*
335 * read in active observe entry.
336 */
337static int
338coap_op_observe_read(FILE *fp, coap_subscription_t **observe_key,
339 coap_proto_t *e_proto, coap_address_t *e_listen_addr,
340 coap_addr_tuple_t *s_addr_info,
341 coap_bin_const_t **raw_packet, coap_bin_const_t **oscore_info) {
342 ssize_t size;
343 coap_binary_t *scratch = NULL;
344
345 assert(fp && observe_key && e_proto && e_listen_addr && s_addr_info &&
346 raw_packet && oscore_info);
347
348 *raw_packet = NULL;
349 *oscore_info = NULL;
350
351 if (fread(observe_key, sizeof(*observe_key), 1, fp) == 1) {
352 /* New record 'key proto listen addr_info len raw_packet len oscore' */
353 if (fread(e_proto, sizeof(*e_proto), 1, fp) != 1)
354 goto fail;
355 if (fread(e_listen_addr, sizeof(*e_listen_addr), 1, fp) != 1)
356 goto fail;
357 if (fread(s_addr_info, sizeof(*s_addr_info), 1, fp) != 1)
358 goto fail;
359 if (fread(&size, sizeof(size), 1, fp) != 1)
360 goto fail;
361 if (size < 0 || size > 0x10000)
362 goto fail;
363 scratch = coap_new_binary(size);
364 if ((scratch) == NULL)
365 goto fail;
366 if (fread(scratch->s, scratch->length, 1, fp) != 1)
367 goto fail;
368 *raw_packet = (coap_bin_const_t *)scratch;
369 scratch = NULL;
370 if (fread(&size, sizeof(size), 1, fp) != 1)
371 goto fail;
372 /* If size == -1, then no oscore information */
373 if (size == -1)
374 return 1;
375 else if (size < 0 || size > 0x10000)
376 goto fail;
377 else {
378 scratch = coap_new_binary(size);
379 if (scratch == NULL)
380 goto fail;
381 if (fread(scratch->s, scratch->length, 1, fp) != 1)
382 goto fail;
383 *oscore_info = (coap_bin_const_t *)scratch;
384 }
385 return 1;
386 }
387fail:
388 coap_delete_bin_const(*raw_packet);
389 coap_delete_binary(scratch);
390
391 *observe_key = NULL;
392 memset(e_proto, 0, sizeof(*e_proto));
393 memset(e_listen_addr, 0, sizeof(*e_listen_addr));
394 memset(s_addr_info, 0, sizeof(*s_addr_info));
395 *raw_packet = NULL;
396 return 0;
397}
398
399/*
400 * write out active observe entry.
401 */
402static int
403coap_op_observe_write(FILE *fp, coap_subscription_t *observe_key,
404 coap_proto_t e_proto, coap_address_t e_listen_addr,
405 coap_addr_tuple_t s_addr_info,
406 coap_bin_const_t *raw_packet, coap_bin_const_t *oscore_info) {
407 if (fwrite(&observe_key, sizeof(observe_key), 1, fp) != 1)
408 goto fail;
409 if (fwrite(&e_proto, sizeof(e_proto), 1, fp) != 1)
410 goto fail;
411 if (fwrite(&e_listen_addr, sizeof(e_listen_addr),
412 1, fp) != 1)
413 goto fail;
414 if (fwrite(&s_addr_info, sizeof(s_addr_info), 1, fp) != 1)
415 goto fail;
416 if (fwrite(&raw_packet->length, sizeof(raw_packet->length), 1, fp) != 1)
417 goto fail;
418 if (fwrite(raw_packet->s, raw_packet->length, 1, fp) != 1)
419 goto fail;
420 if (oscore_info) {
421 if (fwrite(&oscore_info->length, sizeof(oscore_info->length), 1, fp) != 1)
422 goto fail;
423 if (fwrite(oscore_info->s, oscore_info->length, 1, fp) != 1)
424 goto fail;
425 } else {
426 ssize_t not_defined = -1;
427
428 if (fwrite(&not_defined, sizeof(not_defined), 1, fp) != 1)
429 goto fail;
430 }
431 return 1;
432fail:
433 return 0;
434}
435
436/*
437 * This should be called before coap_persist_track_funcs() to prevent
438 * coap_op_observe_added() getting unnecessarily called.
439 * It should be called after init_resources() and coap_op_resource_load_disk()
440 * so that all the resources are in place.
441 */
442static void
443coap_op_observe_load_disk(coap_context_t *ctx) {
444 FILE *fp_orig = fopen((const char *)ctx->observe_save_file->s, "r");
445 FILE *fp_new = NULL;
446 coap_subscription_t *observe_key = NULL;
447 coap_proto_t e_proto;
448 coap_address_t e_listen_addr;
449 coap_addr_tuple_t s_addr_info;
450 coap_bin_const_t *raw_packet = NULL;
451 coap_bin_const_t *oscore_info = NULL;
452 char *new = NULL;
453
454 if (fp_orig == NULL)
455 goto fail;
456
457 new = coap_malloc_type(COAP_STRING, ctx->observe_save_file->length + 5);
458 if (!new)
459 goto fail;
460
461 strcpy(new, (const char *)ctx->observe_save_file->s);
462 strcat(new, ".tmp");
463 fp_new = fopen(new, "w+");
464 if (fp_new == NULL)
465 goto fail;
466
467 /* Go through and load oscore entry, updating key on the way */
468 while (1) {
469 if (!coap_op_observe_read(fp_orig, &observe_key, &e_proto, &e_listen_addr,
470 &s_addr_info, &raw_packet, &oscore_info))
471 break;
472 coap_log_debug("persist: New session/observe being created\n");
473 observe_key = coap_persist_observe_add_lkd(ctx, e_proto,
474 &e_listen_addr,
475 &s_addr_info,
476 raw_packet,
477 oscore_info);
478 if (observe_key) {
479 if (!coap_op_observe_write(fp_new, observe_key, e_proto, e_listen_addr,
480 s_addr_info, raw_packet, oscore_info))
481 goto fail;
482 }
483 coap_delete_bin_const(raw_packet);
484 raw_packet = NULL;
485 coap_delete_bin_const(oscore_info);
486 oscore_info = NULL;
487 }
488 coap_delete_bin_const(raw_packet);
489 raw_packet = NULL;
490 coap_delete_bin_const(oscore_info);
491 oscore_info = NULL;
492
493 if (fflush(fp_new) == EOF)
494 goto fail;
495 fclose(fp_new);
496 fclose(fp_orig);
497 /* Either old or new is in place */
498 if (rename(new, (const char *)ctx->observe_save_file->s) == -1) {
499 coap_log_warn("rename %s -> %s: failed: %s (%d)\n",
500 new, (const char *)ctx->observe_save_file->s,
501 coap_socket_strerror(), errno);
502 }
504 return;
505
506fail:
507 coap_delete_bin_const(raw_packet);
508 coap_delete_bin_const(oscore_info);
509 if (fp_new)
510 fclose(fp_new);
511 if (fp_orig)
512 fclose(fp_orig);
513 if (new) {
514 (void)remove(new);
515 }
517 return;
518}
519
520/*
521 * client has registered a new observe subscription request.
522 */
523static int
524coap_op_observe_added(coap_session_t *session,
525 coap_subscription_t *a_observe_key,
526 coap_proto_t a_e_proto, coap_address_t *a_e_listen_addr,
527 coap_addr_tuple_t *a_s_addr_info,
528 coap_bin_const_t *a_raw_packet,
529 coap_bin_const_t *a_oscore_info, void *user_data) {
530 FILE *fp_orig = fopen((const char *)session->context->observe_save_file->s,
531 "r");
532 FILE *fp_new = NULL;
533 coap_subscription_t *observe_key = NULL;
534 coap_proto_t e_proto;
535 coap_address_t e_listen_addr;
536 coap_addr_tuple_t s_addr_info;
537 coap_bin_const_t *raw_packet = NULL;
538 coap_bin_const_t *oscore_info = NULL;
539 char *new = NULL;
540
541 (void)user_data;
542
544 session->context->observe_save_file->length + 5);
545 if (!new)
546 goto fail;
547
548 strcpy(new, (const char *)session->context->observe_save_file->s);
549 strcat(new, ".tmp");
550 fp_new = fopen(new, "w+");
551 if (fp_new == NULL)
552 goto fail;
553
554 /* Go through and delete observe entry if it exists */
555 while (fp_orig) {
556 if (!coap_op_observe_read(fp_orig, &observe_key, &e_proto, &e_listen_addr,
557 &s_addr_info, &raw_packet, &oscore_info))
558 break;
559 if (observe_key != a_observe_key) {
560 if (!coap_op_observe_write(fp_new, observe_key, e_proto, e_listen_addr,
561 s_addr_info, raw_packet, oscore_info))
562 goto fail;
563 }
564 coap_delete_bin_const(raw_packet);
565 raw_packet = NULL;
566 coap_delete_bin_const(oscore_info);
567 oscore_info = NULL;
568 }
569 coap_delete_bin_const(raw_packet);
570 raw_packet = NULL;
571 coap_delete_bin_const(oscore_info);
572 oscore_info = NULL;
573
574 /* Add in new entry to the end */
575 if (!coap_op_observe_write(fp_new, a_observe_key, a_e_proto, *a_e_listen_addr,
576 *a_s_addr_info, a_raw_packet, a_oscore_info))
577 goto fail;
578
579 if (fflush(fp_new) == EOF)
580 goto fail;
581 fclose(fp_new);
582 if (fp_orig)
583 fclose(fp_orig);
584 /* Either old or new is in place */
585 (void)rename(new, (const char *)session->context->observe_save_file->s);
587 return 1;
588
589fail:
590 coap_delete_bin_const(raw_packet);
591 coap_delete_bin_const(oscore_info);
592 if (fp_new)
593 fclose(fp_new);
594 if (fp_orig)
595 fclose(fp_orig);
596 if (new) {
597 (void)remove(new);
598 }
600 return 0;
601}
602
603/*
604 * client has de-registered a observe subscription request.
605 */
606static int
607coap_op_observe_deleted(coap_session_t *session,
608 coap_subscription_t *d_observe_key,
609 void *user_data) {
610 FILE *fp_orig = fopen((const char *)session->context->observe_save_file->s,
611 "r");
612 FILE *fp_new = NULL;
613 coap_subscription_t *observe_key = NULL;
614 coap_proto_t e_proto;
615 coap_address_t e_listen_addr;
616 coap_addr_tuple_t s_addr_info;
617 coap_bin_const_t *raw_packet = NULL;
618 coap_bin_const_t *oscore_info = NULL;
619 char *new = NULL;
620
621 (void)user_data;
622
623 if (fp_orig == NULL)
624 goto fail;
626 session->context->observe_save_file->length + 5);
627 if (!new)
628 goto fail;
629
630 strcpy(new, (const char *)session->context->observe_save_file->s);
631 strcat(new, ".tmp");
632 fp_new = fopen(new, "w+");
633 if (fp_new == NULL)
634 goto fail;
635
636 /* Go through and locate observe entry to delete and not copy it across */
637 while (1) {
638 if (!coap_op_observe_read(fp_orig, &observe_key, &e_proto, &e_listen_addr,
639 &s_addr_info, &raw_packet, &oscore_info))
640 break;
641 if (observe_key != d_observe_key) {
642 if (!coap_op_observe_write(fp_new, observe_key, e_proto, e_listen_addr,
643 s_addr_info, (coap_bin_const_t *)raw_packet,
644 (coap_bin_const_t *)oscore_info))
645 goto fail;
646 }
647 coap_delete_bin_const(raw_packet);
648 raw_packet = NULL;
649 coap_delete_bin_const(oscore_info);
650 oscore_info = NULL;
651 }
652 coap_delete_bin_const(raw_packet);
653 raw_packet = NULL;
654 coap_delete_bin_const(oscore_info);
655 oscore_info = NULL;
656
657 if (fflush(fp_new) == EOF)
658 goto fail;
659 fclose(fp_new);
660 fclose(fp_orig);
661 /* Either old or new is in place */
662 (void)rename(new, (const char *)session->context->observe_save_file->s);
664 return 1;
665
666fail:
667 coap_delete_bin_const(raw_packet);
668 coap_delete_bin_const(oscore_info);
669 if (fp_new)
670 fclose(fp_new);
671 if (fp_orig)
672 fclose(fp_orig);
673 if (new) {
674 (void)remove(new);
675 }
677 return 0;
678}
679
680/*
681 * This should be called before coap_persist_track_funcs() to prevent
682 * coap_op_obs_cnt_track_observe() getting unnecessarily called.
683 * Should be called after coap_op_dyn_resource_load_disk() to make sure that
684 * all the resources are in the right place.
685 */
686static void
687coap_op_obs_cnt_load_disk(coap_context_t *context) {
688 FILE *fp = fopen((const char *)context->obs_cnt_save_file->s, "r");
689 char buf[1500];
690
691 if (fp == NULL)
692 return;
693
694 while (fgets(buf, sizeof(buf), fp) != NULL) {
695 char *cp = strchr(buf, ' ');
696 coap_str_const_t resource_key;
697 uint32_t observe_num;
699
700 if (!cp)
701 break;
702
703 *cp = '\000';
704 cp++;
705 observe_num = atoi(cp);
706 /*
707 * Need to assume 0 .. (context->observe_save_freq-1) have in addition
708 * been sent so need to round up to latest possible send value
709 */
710 observe_num = ((observe_num + context->observe_save_freq) /
711 context->observe_save_freq) *
712 context->observe_save_freq - 1;
713 resource_key.s = (uint8_t *)buf;
714 resource_key.length = strlen(buf);
715 r = coap_get_resource_from_uri_path_lkd(context, &resource_key);
716 if (r) {
717 coap_log_debug("persist: Initial observe number being updated '%s' %u\n",
718 buf, observe_num);
719 coap_persist_set_observe_num(r, observe_num);
720 }
721 }
722 fclose(fp);
723}
724
725/*
726 * Called when the observe value of a resource has been changed, but limited
727 * to be called every context->context->observe_save_freq to reduce update
728 * overheads.
729 */
730static int
731coap_op_obs_cnt_track_observe(coap_context_t *context,
732 coap_str_const_t *resource_name,
733 uint32_t n_observe_num,
734 void *user_data) {
735 FILE *fp_orig = fopen((const char *)context->obs_cnt_save_file->s, "r");
736 FILE *fp_new = NULL;
737 char buf[1500];
738 char *new = NULL;
739
740 (void)user_data;
741
742 new = coap_malloc_type(COAP_STRING, context->obs_cnt_save_file->length + 5);
743 if (!new)
744 goto fail;
745
746 strcpy(new, (const char *)context->obs_cnt_save_file->s);
747 strcat(new, ".tmp");
748 fp_new = fopen(new, "w+");
749 if (fp_new == NULL)
750 goto fail;
751
752 /* Go through and locate resource entry to update */
753 while (fp_orig && fgets(buf, sizeof(buf), fp_orig) != NULL) {
754 char *cp = strchr(buf, ' ');
755 uint32_t observe_num;
756 coap_bin_const_t resource_key;
757
758 if (!cp)
759 break;
760
761 *cp = '\000';
762 cp++;
763 observe_num = atoi(cp);
764 resource_key.s = (uint8_t *)buf;
765 resource_key.length = strlen(buf);
766 if (!coap_binary_equal(resource_name, &resource_key)) {
767 if (fprintf(fp_new, "%s %u\n", resource_key.s, observe_num) < 0)
768 goto fail;
769 }
770 }
771 if (fprintf(fp_new, "%s %u\n", resource_name->s, n_observe_num) < 0)
772 goto fail;
773 if (fflush(fp_new) == EOF)
774 goto fail;
775 fclose(fp_new);
776 if (fp_orig)
777 fclose(fp_orig);
778 /* Either old or new is in place */
779 (void)rename(new, (const char *)context->obs_cnt_save_file->s);
781 return 1;
782
783fail:
784 if (fp_new)
785 fclose(fp_new);
786 if (fp_orig)
787 fclose(fp_orig);
788 if (new) {
789 (void)remove(new);
790 }
792 return 0;
793}
794
795/*
796 * Called when a resource has been deleted.
797 */
798static int
799coap_op_obs_cnt_deleted(coap_context_t *context,
800 coap_str_const_t *resource_name) {
801 FILE *fp_orig = fopen((const char *)context->obs_cnt_save_file->s, "r");
802 FILE *fp_new = NULL;
803 char buf[1500];
804 char *new = NULL;
805
806 if (fp_orig == NULL)
807 goto fail;
808 new = coap_malloc_type(COAP_STRING, context->obs_cnt_save_file->length + 5);
809 if (!new)
810 goto fail;
811
812 strcpy(new, (const char *)context->obs_cnt_save_file->s);
813 strcat(new, ".tmp");
814 fp_new = fopen(new, "w+");
815 if (fp_new == NULL)
816 goto fail;
817
818 /* Go through and locate resource entry to delete */
819 while (fgets(buf, sizeof(buf), fp_orig) != NULL) {
820 char *cp = strchr(buf, ' ');
821 uint32_t observe_num;
822 coap_bin_const_t resource_key;
823
824 if (!cp)
825 break;
826
827 *cp = '\000';
828 cp++;
829 observe_num = atoi(cp);
830 resource_key.s = (uint8_t *)buf;
831 resource_key.length = strlen(buf);
832 if (!coap_binary_equal(resource_name, &resource_key)) {
833 if (fprintf(fp_new, "%s %u\n", resource_key.s, observe_num) < 0)
834 goto fail;
835 }
836 }
837 if (fflush(fp_new) == EOF)
838 goto fail;
839 fclose(fp_new);
840 fclose(fp_orig);
841 /* Either old or new is in place */
842 (void)rename(new, (const char *)context->obs_cnt_save_file->s);
844 return 1;
845
846fail:
847 if (fp_new)
848 fclose(fp_new);
849 if (fp_orig)
850 fclose(fp_orig);
851 if (new) {
852 (void)remove(new);
853 }
855 return 0;
856}
857
858/*
859 * read in dynamic resource entry, allocating name & raw_packet
860 * which need to be freed off by caller.
861 */
862static int
863coap_op_dyn_resource_read(FILE *fp, coap_proto_t *e_proto,
864 coap_string_t **name,
865 coap_binary_t **raw_packet) {
866 ssize_t size;
867
868 *name = NULL;
869 *raw_packet = NULL;
870
871 if (fread(e_proto, sizeof(*e_proto), 1, fp) == 1) {
872 /* New record 'proto len resource_name len raw_packet' */
873 if (fread(&size, sizeof(size), 1, fp) != 1)
874 goto fail;
875 if (size < 0 || size > 0x10000)
876 goto fail;
877 *name = coap_new_string(size);
878 if (!(*name))
879 goto fail;
880 if (fread((*name)->s, size, 1, fp) != 1)
881 goto fail;
882 if (fread(&size, sizeof(size), 1, fp) != 1)
883 goto fail;
884 if (size < 0 || size > 0x10000)
885 goto fail;
886 *raw_packet = coap_new_binary(size);
887 if (!(*raw_packet))
888 goto fail;
889 if (fread((*raw_packet)->s, size, 1, fp) != 1)
890 goto fail;
891 return 1;
892 }
893fail:
894 return 0;
895}
896
897/*
898 * write out dynamic resource entry.
899 */
900static int
901coap_op_dyn_resource_write(FILE *fp, coap_proto_t e_proto,
902 coap_str_const_t *name,
903 coap_bin_const_t *raw_packet) {
904 if (fwrite(&e_proto, sizeof(e_proto), 1, fp) != 1)
905 goto fail;
906 if (fwrite(&name->length, sizeof(name->length), 1, fp) != 1)
907 goto fail;
908 if (fwrite(name->s, name->length, 1, fp) != 1)
909 goto fail;
910 if (fwrite(&raw_packet->length, sizeof(raw_packet->length), 1, fp) != 1)
911 goto fail;
912 if (fwrite(raw_packet->s, raw_packet->length, 1, fp) != 1)
913 goto fail;
914 return 1;
915fail:
916 return 0;
917}
918
919/*
920 * This should be called before coap_persist_track_funcs() to prevent
921 * coap_op_dyn_resource_added() getting unnecessarily called.
922 *
923 * Each record 'proto len resource_name len raw_packet'
924 */
925static void
926coap_op_dyn_resource_load_disk(coap_context_t *ctx) {
927 FILE *fp_orig = NULL;
928 coap_proto_t e_proto;
929 coap_string_t *name = NULL;
930 coap_binary_t *raw_packet = NULL;
932 coap_session_t *session = NULL;
933 coap_pdu_t *request = NULL;
934 coap_pdu_t *response = NULL;
935 coap_string_t *query = NULL;
936
937 if (!ctx->unknown_resource && !ctx->dyn_create_handler)
938 return;
939
940 fp_orig = fopen((const char *)ctx->dyn_resource_save_file->s, "r");
941 if (fp_orig == NULL)
942 return;
944 sizeof(coap_session_t));
945 if (!session)
946 goto fail;
947 memset(session, 0, sizeof(coap_session_t));
948 session->context = ctx;
949
950 /* Go through and create each dynamic resource if it does not exist*/
951 while (1) {
952 if (!coap_op_dyn_resource_read(fp_orig, &e_proto, &name, &raw_packet))
953 break;
955 if (!r) {
956 /* Create the new resource using the application logic */
957
958 coap_log_debug("persist: dynamic resource '%s' being re-created\n", name->s);
959 /*
960 * Need max space incase PDU is updated with updated token,
961 * huge size etc.
962 * */
963 request = coap_pdu_init(0, 0, 0, 0);
964 if (!request)
965 goto fail;
966
967 session->proto = e_proto;
968 if (!coap_pdu_parse(session->proto, raw_packet->s,
969 raw_packet->length, request)) {
970 goto fail;
971 }
972 r = ctx->unknown_resource;
973 if ((ctx->dyn_create_handler != NULL) &&
974 (request->code == COAP_REQUEST_CODE_PUT || request->code == COAP_REQUEST_CODE_POST)) {
975 /* Above test must be the same as in handle_request() */
976 if (ctx->dynamic_cur < ctx->dynamic_max || ctx->dynamic_max == 0) {
977 ctx->unknown_pdu = request;
978 ctx->unknown_session = session;
979 coap_lock_callback_ret(r, ctx->dyn_create_handler(session, request));
980 ctx->unknown_pdu = NULL;
981 ctx->unknown_session = NULL;
982 }
983 }
984 if (!r || !r->handler[request->code-1])
985 goto next;
986
987 response = coap_pdu_init(0, 0, 0, 0);
988 if (!response)
989 goto fail;
990 query = coap_get_query(request);
991 /* Call the application handler to set up this dynamic resource */
992 coap_lock_callback_release(r->handler[request->code-1](r,
993 session, request,
994 query, response),
995 /* context is being freed off */
996 goto fail);
997 coap_delete_string(query);
998 query = NULL;
999 coap_delete_pdu_lkd(response);
1000 response = NULL;
1001next:
1002 coap_delete_pdu_lkd(request);
1003 request = NULL;
1004 }
1005 coap_delete_string(name);
1006 coap_delete_binary(raw_packet);
1007 }
1008fail:
1009 coap_delete_string(name);
1010 coap_delete_binary(raw_packet);
1011 coap_delete_string(query);
1012 coap_delete_pdu_lkd(request);
1013 coap_delete_pdu_lkd(response);
1014 fclose(fp_orig);
1015 coap_free_type(COAP_SESSION, session);
1016}
1017
1018/*
1019 * Server has set up a new dynamic resource against a request for an unknown
1020 * resource.
1021 */
1022static int
1023coap_op_dyn_resource_added(coap_session_t *session,
1024 coap_str_const_t *resource_name,
1025 coap_bin_const_t *packet,
1026 void *user_data) {
1027 FILE *fp_orig;
1028 FILE *fp_new = NULL;
1029 char *new = NULL;
1030 coap_context_t *context = session->context;
1031 coap_string_t *name = NULL;
1032 coap_binary_t *raw_packet = NULL;
1033 coap_proto_t e_proto;
1034
1035 (void)user_data;
1036
1037 fp_orig = fopen((const char *)context->dyn_resource_save_file->s, "a");
1038 if (fp_orig == NULL)
1039 return 0;
1040
1042 context->dyn_resource_save_file->length + 5);
1043 if (!new)
1044 goto fail;
1045
1046 strcpy(new, (const char *)context->dyn_resource_save_file->s);
1047 strcat(new, ".tmp");
1048 fp_new = fopen(new, "w+");
1049 if (fp_new == NULL)
1050 goto fail;
1051
1052 /* Go through and locate duplicate resource to delete */
1053 while (1) {
1054 if (!coap_op_dyn_resource_read(fp_orig, &e_proto, &name, &raw_packet))
1055 break;
1056 if (!coap_string_equal(resource_name, name)) {
1057 /* Copy across non-matching entry */
1058 if (!coap_op_dyn_resource_write(fp_new, e_proto, (coap_str_const_t *)name,
1059 (coap_bin_const_t *)raw_packet))
1060 break;
1061 }
1062 coap_delete_string(name);
1063 name = NULL;
1064 coap_delete_binary(raw_packet);
1065 raw_packet = NULL;
1066 }
1067 coap_delete_string(name);
1068 coap_delete_binary(raw_packet);
1069 /* Add new entry to the end */
1070 if (!coap_op_dyn_resource_write(fp_new, session->proto,
1071 resource_name, packet))
1072 goto fail;
1073
1074 if (fflush(fp_new) == EOF)
1075 goto fail;
1076 fclose(fp_new);
1077 fclose(fp_orig);
1078 /* Either old or new is in place */
1079 (void)rename(new, (const char *)context->dyn_resource_save_file->s);
1081 return 1;
1082
1083fail:
1084 if (fp_new)
1085 fclose(fp_new);
1086 if (fp_orig)
1087 fclose(fp_orig);
1088 if (new) {
1089 (void)remove(new);
1090 }
1092 return 0;
1093}
1094
1095/*
1096 * Server has deleted a resource
1097 */
1098static int
1099coap_op_resource_deleted(coap_context_t *context,
1100 coap_str_const_t *resource_name,
1101 void *user_data) {
1102 FILE *fp_orig = NULL;
1103 FILE *fp_new = NULL;
1104 char *new = NULL;
1105 coap_proto_t e_proto;
1106 coap_string_t *name = NULL;
1107 coap_binary_t *raw_packet = NULL;
1108 (void)user_data;
1109
1110 coap_op_obs_cnt_deleted(context, resource_name);
1111
1112 fp_orig = fopen((const char *)context->dyn_resource_save_file->s, "r");
1113 if (fp_orig == NULL)
1114 return 1;
1115
1117 context->dyn_resource_save_file->length + 5);
1118 if (!new)
1119 goto fail;
1120
1121 strcpy(new, (const char *)context->dyn_resource_save_file->s);
1122 strcat(new, ".tmp");
1123 fp_new = fopen(new, "w+");
1124 if (fp_new == NULL)
1125 goto fail;
1126
1127 /* Go through and locate resource to delete and not copy it across */
1128 while (1) {
1129 if (!coap_op_dyn_resource_read(fp_orig, &e_proto, &name, &raw_packet))
1130 break;
1131 if (!coap_string_equal(resource_name, name)) {
1132 /* Copy across non-matching entry */
1133 if (!coap_op_dyn_resource_write(fp_new, e_proto, (coap_str_const_t *)name,
1134 (coap_bin_const_t *)raw_packet))
1135 break;
1136 }
1137 coap_delete_string(name);
1138 name = NULL;
1139 coap_delete_binary(raw_packet);
1140 raw_packet = NULL;
1141 }
1142 coap_delete_string(name);
1143 coap_delete_binary(raw_packet);
1144
1145 if (fflush(fp_new) == EOF)
1146 goto fail;
1147 fclose(fp_new);
1148 fclose(fp_orig);
1149 /* Either old or new is in place */
1150 (void)rename(new, (const char *)context->dyn_resource_save_file->s);
1152 return 1;
1153
1154fail:
1155 if (fp_new)
1156 fclose(fp_new);
1157 if (fp_orig)
1158 fclose(fp_orig);
1159 if (new) {
1160 (void)remove(new);
1161 }
1163 return 0;
1164}
1165
1166COAP_API int
1168 const char *dyn_resource_save_file,
1169 const char *observe_save_file,
1170 const char *obs_cnt_save_file,
1171 uint32_t save_freq) {
1172 int ret;
1173
1174 coap_lock_lock(return 0);
1175 ret = coap_persist_startup_lkd(context,
1176 dyn_resource_save_file,
1177 observe_save_file,
1178 obs_cnt_save_file,
1179 save_freq);
1181 return ret;
1182}
1183
1184int
1186 const char *dyn_resource_save_file,
1187 const char *observe_save_file,
1188 const char *obs_cnt_save_file,
1189 uint32_t save_freq) {
1191 if (dyn_resource_save_file) {
1192 context->dyn_resource_save_file =
1193 coap_new_bin_const((const uint8_t *)dyn_resource_save_file,
1194 strlen(dyn_resource_save_file));
1195 if (!context->dyn_resource_save_file)
1196 return 0;
1197 coap_op_dyn_resource_load_disk(context);
1198 context->dyn_resource_added = coap_op_dyn_resource_added;
1199 context->resource_deleted = coap_op_resource_deleted;
1200 }
1201 if (obs_cnt_save_file) {
1202 context->obs_cnt_save_file =
1203 coap_new_bin_const((const uint8_t *)obs_cnt_save_file,
1204 strlen(obs_cnt_save_file));
1205 if (!context->obs_cnt_save_file)
1206 return 0;
1207 context->observe_save_freq = save_freq ? save_freq : 1;
1208 coap_op_obs_cnt_load_disk(context);
1209 context->track_observe_value = coap_op_obs_cnt_track_observe;
1210 context->resource_deleted = coap_op_resource_deleted;
1211 }
1212 if (observe_save_file) {
1213 context->observe_save_file =
1214 coap_new_bin_const((const uint8_t *)observe_save_file,
1215 strlen(observe_save_file));
1216 if (!context->observe_save_file)
1217 return 0;
1218 coap_op_observe_load_disk(context);
1219 context->observe_added = coap_op_observe_added;
1220 context->observe_deleted = coap_op_observe_deleted;
1221 }
1222 return 1;
1223}
1224
1225void
1227 coap_delete_bin_const(context->dyn_resource_save_file);
1228 coap_delete_bin_const(context->obs_cnt_save_file);
1229 coap_delete_bin_const(context->observe_save_file);
1230 context->dyn_resource_save_file = NULL;
1231 context->obs_cnt_save_file = NULL;
1232 context->observe_save_file = NULL;
1233
1234 /* Close down any tracking */
1235 coap_persist_track_funcs(context, NULL, NULL, NULL, NULL,
1236 NULL, 0, NULL);
1237}
1238
1239COAP_API void
1241 if (!context)
1242 return;
1243 coap_lock_lock(return);
1244 coap_persist_stop_lkd(context);
1246}
1247
1248void
1250 if (context == NULL)
1251 return;
1253 context->observe_no_clear = 1;
1254 coap_persist_cleanup(context);
1255}
1256#else /* ! COAP_WITH_OBSERVE_PERSIST */
1257COAP_API int
1259 const char *dyn_resource_save_file,
1260 const char *observe_save_file,
1261 const char *obs_cnt_save_file,
1262 uint32_t save_freq) {
1263 (void)context;
1264 (void)dyn_resource_save_file;
1265 (void)observe_save_file;
1266 (void)obs_cnt_save_file;
1267 (void)save_freq;
1268 return 0;
1269}
1270
1271COAP_API void
1273 context->observe_no_clear = 1;
1274 /* Close down any tracking */
1275 coap_persist_track_funcs(context, NULL, NULL, NULL, NULL,
1276 NULL, 0, NULL);
1277}
1278
1279#endif /* ! COAP_WITH_OBSERVE_PERSIST */
1280
1281#endif /* COAP_SERVER_SUPPORT */
#define INET6_ADDRSTRLEN
Definition coap_debug.c:234
const char * coap_socket_strerror(void)
Definition coap_io.c:2359
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_ret(r, func)
Dummy for no thread-safe code.
#define coap_lock_unlock()
Dummy for no thread-safe code.
#define coap_lock_check_locked()
Dummy for no thread-safe code.
#define coap_lock_callback_release(func, failed)
Dummy for no thread-safe code.
#define coap_lock_lock(failed)
Dummy for no thread-safe code.
#define coap_log_debug(...)
Definition coap_debug.h:120
coap_log_t coap_get_log_level(void)
Get the current logging level.
Definition coap_debug.c:103
size_t coap_print_addr(const coap_address_t *addr, unsigned char *buf, size_t len)
Print the address into the defined buffer.
Definition coap_debug.c:241
#define coap_log_warn(...)
Definition coap_debug.h:102
@ COAP_LOG_OSCORE
Definition coap_debug.h:59
@ COAP_LOG_WARN
Definition coap_debug.h:55
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.
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.
const uint8_t * coap_opt_value(const coap_opt_t *opt)
Returns a pointer to the value of the given option.
#define CBOR_BYTE_STRING
Definition oscore_cbor.h:62
size_t oscore_cbor_get_element_size(const uint8_t **buffer, size_t *buf_len)
#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)
#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_lkd(coap_pdu_t *pdu)
Dispose of an CoAP PDU and free off associated storage.
Definition coap_pdu.c:194
coap_proto_t
CoAP protocol types.
Definition coap_pdu.h:313
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:1483
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:102
#define COAP_OPTION_OBSERVE
Definition coap_pdu.h:123
@ COAP_PROTO_UDP
Definition coap_pdu.h:315
@ COAP_REQUEST_CODE_PUT
Definition coap_pdu.h:332
@ COAP_REQUEST_CODE_POST
Definition coap_pdu.h:331
@ COAP_REQUEST_CODE_GET
Definition coap_pdu.h:330
@ COAP_REQUEST_CODE_FETCH
Definition coap_pdu.h:334
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:990
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:939
Multi-purpose address abstraction.
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_resource_dynamic_create_t dyn_create_handler
Dynamc resource create handler.
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.
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...