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