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