libcoap 4.3.2rc2
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 || 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 *raw_packet = NULL;
314 *oscore_info = NULL;
315
316 if (fread(observe_key, sizeof(*observe_key), 1, fp) == 1) {
317 /* New record 'key proto listen addr_info len raw_packet len oscore' */
318 if (fread(e_proto, sizeof(*e_proto), 1, fp) != 1)
319 goto fail;
320 if (fread(e_listen_addr, sizeof(*e_listen_addr), 1, fp) != 1)
321 goto fail;
322 if (fread(s_addr_info, sizeof(*s_addr_info), 1, fp) != 1)
323 goto fail;
324 if (fread(&size, sizeof(size), 1, fp) != 1)
325 goto fail;
326 if (size < 0 || size > 0x10000)
327 goto fail;
328 scratch = coap_new_binary(size);
329 if ((scratch) == NULL)
330 goto fail;
331 if (fread(scratch->s, scratch->length, 1, fp) != 1)
332 goto fail;
333 *raw_packet = (coap_bin_const_t *)scratch;
334 if (fread(&size, sizeof(size), 1, fp) != 1)
335 goto fail;
336 if (size == -1)
337 return 1;
338 else if (size < 0 || size > 0x10000)
339 goto fail;
340 else {
341 scratch = coap_new_binary(size);
342 if (scratch == NULL)
343 goto fail;
344 if (fread(scratch->s, scratch->length, 1, fp) != 1)
345 goto fail;
346 *oscore_info = (coap_bin_const_t *)scratch;
347 }
348 return 1;
349 }
350fail:
351 coap_delete_binary(scratch);
352 *raw_packet = NULL;
353 return 0;
354}
355
356/*
357 * write out active observe entry.
358 */
359static int
360coap_op_observe_write(FILE *fp, coap_subscription_t *observe_key,
361 coap_proto_t e_proto, coap_address_t e_listen_addr,
362 coap_addr_tuple_t s_addr_info,
363 coap_bin_const_t *raw_packet, coap_bin_const_t *oscore_info) {
364 if (fwrite(&observe_key, sizeof(observe_key), 1, fp) != 1)
365 goto fail;
366 if (fwrite(&e_proto, sizeof(e_proto), 1, fp) != 1)
367 goto fail;
368 if (fwrite(&e_listen_addr, sizeof(e_listen_addr),
369 1, fp) != 1)
370 goto fail;
371 if (fwrite(&s_addr_info, sizeof(s_addr_info), 1, fp) != 1)
372 goto fail;
373 if (fwrite(&raw_packet->length, sizeof(raw_packet->length), 1, fp) != 1)
374 goto fail;
375 if (fwrite(raw_packet->s, raw_packet->length, 1, fp) != 1)
376 goto fail;
377 if (oscore_info) {
378 if (fwrite(&oscore_info->length, sizeof(oscore_info->length), 1, fp) != 1)
379 goto fail;
380 if (fwrite(oscore_info->s, oscore_info->length, 1, fp) != 1)
381 goto fail;
382 } else {
383 ssize_t not_defined = -1;
384
385 if (fwrite(&not_defined, sizeof(not_defined), 1, fp) != 1)
386 goto fail;
387 }
388 return 1;
389fail:
390 return 0;
391}
392
393/*
394 * This should be called before coap_persist_track_funcs() to prevent
395 * coap_op_observe_added() getting unnecessarily called.
396 * It should be called after init_resources() and coap_op_resource_load_disk()
397 * so that all the resources are in place.
398 */
399static void
400coap_op_observe_load_disk(coap_context_t *ctx) {
401 FILE *fp_orig = fopen((const char *)ctx->observe_save_file->s, "r");
402 FILE *fp_new = NULL;
403 coap_subscription_t *observe_key = NULL;
404 coap_proto_t e_proto;
405 coap_address_t e_listen_addr;
406 coap_addr_tuple_t s_addr_info;
407 coap_bin_const_t *raw_packet = NULL;
408 coap_bin_const_t *oscore_info = NULL;
409 char *new = NULL;
410
411 if (fp_orig == NULL)
412 goto fail;
413 new = coap_malloc_type(COAP_STRING, ctx->observe_save_file->length + 5);
414 if (!new)
415 goto fail;
416
417 strcpy(new, (const char *)ctx->observe_save_file->s);
418 strcat(new, ".tmp");
419 fp_new = fopen(new, "w+");
420 if (fp_new == NULL)
421 goto fail;
422
423 /* Go through and load oscore entry, updating key on the way */
424 while (1) {
425 if (!coap_op_observe_read(fp_orig, &observe_key, &e_proto, &e_listen_addr,
426 &s_addr_info, &raw_packet, &oscore_info))
427 break;
428 coap_log_debug("persist: New session/observe being created\n");
429 observe_key = coap_persist_observe_add(ctx, e_proto,
430 &e_listen_addr,
431 &s_addr_info,
432 raw_packet,
433 oscore_info);
434 if (observe_key) {
435 if (!coap_op_observe_write(fp_new, observe_key, e_proto, e_listen_addr,
436 s_addr_info, raw_packet, oscore_info))
437 goto fail;
438 coap_delete_bin_const(raw_packet);
439 raw_packet = NULL;
440 coap_delete_bin_const(oscore_info);
441 oscore_info = NULL;
442 }
443 }
444 coap_delete_bin_const(raw_packet);
445 raw_packet = NULL;
446 coap_delete_bin_const(oscore_info);
447 oscore_info = NULL;
448
449 if (fflush(fp_new) == EOF)
450 goto fail;
451 fclose(fp_new);
452 fclose(fp_orig);
453 /* Either old or new is in place */
454 (void)rename(new, (const char *)ctx->observe_save_file->s);
456 return;
457
458fail:
459 coap_delete_bin_const(raw_packet);
460 coap_delete_bin_const(oscore_info);
461 if (fp_new)
462 fclose(fp_new);
463 if (fp_orig)
464 fclose(fp_orig);
465 if (new) {
466 (void)remove(new);
467 }
469 return;
470}
471
472/*
473 * client has registered a new observe subscription request.
474 */
475static int
476coap_op_observe_added(coap_session_t *session,
477 coap_subscription_t *a_observe_key,
478 coap_proto_t a_e_proto, coap_address_t *a_e_listen_addr,
479 coap_addr_tuple_t *a_s_addr_info,
480 coap_bin_const_t *a_raw_packet,
481 coap_bin_const_t *a_oscore_info, void *user_data) {
482 FILE *fp_orig = fopen((const char *)session->context->observe_save_file->s,
483 "r");
484 FILE *fp_new = NULL;
485 coap_subscription_t *observe_key = NULL;
486 coap_proto_t e_proto;
487 coap_address_t e_listen_addr;
488 coap_addr_tuple_t s_addr_info;
489 coap_bin_const_t *raw_packet = NULL;
490 coap_bin_const_t *oscore_info = NULL;
491 char *new = NULL;
492
493 (void)user_data;
494
496 session->context->observe_save_file->length + 5);
497 if (!new)
498 goto fail;
499
500 strcpy(new, (const char *)session->context->observe_save_file->s);
501 strcat(new, ".tmp");
502 fp_new = fopen(new, "w+");
503 if (fp_new == NULL)
504 goto fail;
505
506 /* Go through and delete observe entry if it exists */
507 while (fp_orig) {
508 if (!coap_op_observe_read(fp_orig, &observe_key, &e_proto, &e_listen_addr,
509 &s_addr_info, &raw_packet, &oscore_info))
510 break;
511 if (observe_key != a_observe_key) {
512 if (!coap_op_observe_write(fp_new, observe_key, e_proto, e_listen_addr,
513 s_addr_info, raw_packet, oscore_info))
514 goto fail;
515 }
516 coap_delete_bin_const(raw_packet);
517 raw_packet = NULL;
518 coap_delete_bin_const(oscore_info);
519 oscore_info = NULL;
520 }
521 coap_delete_bin_const(raw_packet);
522 raw_packet = NULL;
523 coap_delete_bin_const(oscore_info);
524 oscore_info = NULL;
525
526 /* Add in new entry to the end */
527 if (!coap_op_observe_write(fp_new, a_observe_key, a_e_proto, *a_e_listen_addr,
528 *a_s_addr_info, a_raw_packet, a_oscore_info))
529 goto fail;
530
531 if (fflush(fp_new) == EOF)
532 goto fail;
533 fclose(fp_new);
534 if (fp_orig)
535 fclose(fp_orig);
536 /* Either old or new is in place */
537 (void)rename(new, (const char *)session->context->observe_save_file->s);
539 return 1;
540
541fail:
542 coap_delete_bin_const(raw_packet);
543 coap_delete_bin_const(oscore_info);
544 if (fp_new)
545 fclose(fp_new);
546 if (fp_orig)
547 fclose(fp_orig);
548 if (new) {
549 (void)remove(new);
550 }
552 return 0;
553}
554
555/*
556 * client has de-registered a observe subscription request.
557 */
558static int
559coap_op_observe_deleted(coap_session_t *session,
560 coap_subscription_t *d_observe_key,
561 void *user_data) {
562 FILE *fp_orig = fopen((const char *)session->context->observe_save_file->s,
563 "r");
564 FILE *fp_new = NULL;
565 coap_subscription_t *observe_key = NULL;
566 coap_proto_t e_proto;
567 coap_address_t e_listen_addr;
568 coap_addr_tuple_t s_addr_info;
569 coap_bin_const_t *raw_packet = NULL;
570 coap_bin_const_t *oscore_info = NULL;
571 char *new = NULL;
572
573 (void)user_data;
574
575 if (fp_orig == NULL)
576 goto fail;
578 session->context->observe_save_file->length + 5);
579 if (!new)
580 goto fail;
581
582 strcpy(new, (const char *)session->context->observe_save_file->s);
583 strcat(new, ".tmp");
584 fp_new = fopen(new, "w+");
585 if (fp_new == NULL)
586 goto fail;
587
588 /* Go through and locate observe entry to delete and not copy it across */
589 while (1) {
590 if (!coap_op_observe_read(fp_orig, &observe_key, &e_proto, &e_listen_addr,
591 &s_addr_info, &raw_packet, &oscore_info))
592 break;
593 if (observe_key != d_observe_key) {
594 if (!coap_op_observe_write(fp_new, observe_key, e_proto, e_listen_addr,
595 s_addr_info, (coap_bin_const_t *)raw_packet,
596 (coap_bin_const_t *)oscore_info))
597 goto fail;
598 }
599 coap_delete_bin_const(raw_packet);
600 raw_packet = NULL;
601 coap_delete_bin_const(oscore_info);
602 oscore_info = NULL;
603 }
604 coap_delete_bin_const(raw_packet);
605 raw_packet = NULL;
606 coap_delete_bin_const(oscore_info);
607 oscore_info = NULL;
608
609 if (fflush(fp_new) == EOF)
610 goto fail;
611 fclose(fp_new);
612 fclose(fp_orig);
613 /* Either old or new is in place */
614 (void)rename(new, (const char *)session->context->observe_save_file->s);
616 return 1;
617
618fail:
619 coap_delete_bin_const(raw_packet);
620 coap_delete_bin_const(oscore_info);
621 if (fp_new)
622 fclose(fp_new);
623 if (fp_orig)
624 fclose(fp_orig);
625 if (new) {
626 (void)remove(new);
627 }
629 return 0;
630}
631
632/*
633 * This should be called before coap_persist_track_funcs() to prevent
634 * coap_op_obs_cnt_track_observe() getting unnecessarily called.
635 * Should be called after coap_op_dyn_resource_load_disk() to make sure that
636 * all the resources are in the right place.
637 */
638static void
639coap_op_obs_cnt_load_disk(coap_context_t *context) {
640 FILE *fp = fopen((const char *)context->obs_cnt_save_file->s, "r");
641 char buf[1500];
642
643 if (fp == NULL)
644 return;
645
646 while (fgets(buf, sizeof(buf), fp) != NULL) {
647 char *cp = strchr(buf, ' ');
648 coap_str_const_t resource_key;
649 uint32_t observe_num;
651
652 if (!cp)
653 break;
654
655 *cp = '\000';
656 cp++;
657 observe_num = atoi(cp);
658 /*
659 * Need to assume 0 .. (context->observe_save_freq-1) have in addition
660 * been sent so need to round up to latest possible send value
661 */
662 observe_num = ((observe_num + context->observe_save_freq) /
663 context->observe_save_freq) *
664 context->observe_save_freq - 1;
665 resource_key.s = (uint8_t *)buf;
666 resource_key.length = strlen(buf);
667 r = coap_get_resource_from_uri_path(context, &resource_key);
668 if (r) {
669 coap_log_debug("persist: Initial observe number being updated\n");
670 coap_persist_set_observe_num(r, observe_num);
671 }
672 }
673 fclose(fp);
674}
675
676/*
677 * Called when the observe value of a resource has been changed, but limited
678 * to be called every context->context->observe_save_freq to reduce update
679 * overheads.
680 */
681static int
682coap_op_obs_cnt_track_observe(coap_context_t *context,
683 coap_str_const_t *resource_name,
684 uint32_t n_observe_num,
685 void *user_data) {
686 FILE *fp_orig = fopen((const char *)context->obs_cnt_save_file->s, "r");
687 FILE *fp_new = NULL;
688 char buf[1500];
689 char *new = NULL;
690
691 (void)user_data;
692
693 new = coap_malloc_type(COAP_STRING, context->obs_cnt_save_file->length + 5);
694 if (!new)
695 goto fail;
696
697 strcpy(new, (const char *)context->obs_cnt_save_file->s);
698 strcat(new, ".tmp");
699 fp_new = fopen(new, "w+");
700 if (fp_new == NULL)
701 goto fail;
702
703 /* Go through and locate resource entry to update */
704 while (fp_orig && fgets(buf, sizeof(buf), fp_orig) != NULL) {
705 char *cp = strchr(buf, ' ');
706 uint32_t observe_num;
707 coap_bin_const_t resource_key;
708
709 if (!cp)
710 break;
711
712 *cp = '\000';
713 cp++;
714 observe_num = atoi(cp);
715 resource_key.s = (uint8_t *)buf;
716 resource_key.length = strlen(buf);
717 if (!coap_binary_equal(resource_name, &resource_key)) {
718 if (fprintf(fp_new, "%s %u\n", resource_key.s, observe_num) < 0)
719 goto fail;
720 }
721 }
722 if (fprintf(fp_new, "%s %u\n", resource_name->s, n_observe_num) < 0)
723 goto fail;
724 if (fflush(fp_new) == EOF)
725 goto fail;
726 fclose(fp_new);
727 if (fp_orig)
728 fclose(fp_orig);
729 /* Either old or new is in place */
730 (void)rename(new, (const char *)context->obs_cnt_save_file->s);
732 return 1;
733
734fail:
735 if (fp_new)
736 fclose(fp_new);
737 if (fp_orig)
738 fclose(fp_orig);
739 if (new) {
740 (void)remove(new);
741 }
743 return 0;
744}
745
746/*
747 * Called when a resource has been deleted.
748 */
749static int
750coap_op_obs_cnt_deleted(coap_context_t *context,
751 coap_str_const_t *resource_name) {
752 FILE *fp_orig = fopen((const char *)context->obs_cnt_save_file->s, "r");
753 FILE *fp_new = NULL;
754 char buf[1500];
755 char *new = NULL;
756
757 if (fp_orig == NULL)
758 goto fail;
759 new = coap_malloc_type(COAP_STRING, context->obs_cnt_save_file->length + 5);
760 if (!new)
761 goto fail;
762
763 strcpy(new, (const char *)context->obs_cnt_save_file->s);
764 strcat(new, ".tmp");
765 fp_new = fopen(new, "w+");
766 if (fp_new == NULL)
767 goto fail;
768
769 /* Go through and locate resource entry to delete */
770 while (fgets(buf, sizeof(buf), fp_orig) != NULL) {
771 char *cp = strchr(buf, ' ');
772 uint32_t observe_num;
773 coap_bin_const_t resource_key;
774
775 if (!cp)
776 break;
777
778 *cp = '\000';
779 cp++;
780 observe_num = atoi(cp);
781 resource_key.s = (uint8_t *)buf;
782 resource_key.length = strlen(buf);
783 if (!coap_binary_equal(resource_name, &resource_key)) {
784 if (fprintf(fp_new, "%s %u\n", resource_key.s, observe_num) < 0)
785 goto fail;
786 }
787 }
788 if (fflush(fp_new) == EOF)
789 goto fail;
790 fclose(fp_new);
791 fclose(fp_orig);
792 /* Either old or new is in place */
793 (void)rename(new, (const char *)context->obs_cnt_save_file->s);
795 return 1;
796
797fail:
798 if (fp_new)
799 fclose(fp_new);
800 if (fp_orig)
801 fclose(fp_orig);
802 if (new) {
803 (void)remove(new);
804 }
806 return 0;
807}
808
809/*
810 * read in dynamic resource entry, allocating name & raw_packet
811 * which need to be freed off by caller.
812 */
813static int
814coap_op_dyn_resource_read(FILE *fp, coap_proto_t *e_proto,
815 coap_string_t **name,
816 coap_binary_t **raw_packet) {
817 ssize_t size;
818
819 *name = NULL;
820 *raw_packet = NULL;
821
822 if (fread(e_proto, sizeof(*e_proto), 1, fp) == 1) {
823 /* New record 'proto len resource_name len raw_packet' */
824 if (fread(&size, sizeof(size), 1, fp) != 1)
825 goto fail;
826 if (size < 0 || size > 0x10000)
827 goto fail;
828 *name = coap_new_string(size);
829 if (!(*name))
830 goto fail;
831 if (fread((*name)->s, size, 1, fp) != 1)
832 goto fail;
833 if (fread(&size, sizeof(size), 1, fp) != 1)
834 goto fail;
835 if (size < 0 || size > 0x10000)
836 goto fail;
837 *raw_packet = coap_new_binary(size);
838 if (!(*raw_packet))
839 goto fail;
840 if (fread((*raw_packet)->s, size, 1, fp) != 1)
841 goto fail;
842 return 1;
843 }
844fail:
845 return 0;
846}
847
848/*
849 * write out dynamic resource entry.
850 */
851static int
852coap_op_dyn_resource_write(FILE *fp, coap_proto_t e_proto,
853 coap_str_const_t *name,
854 coap_bin_const_t *raw_packet) {
855 if (fwrite(&e_proto, sizeof(e_proto), 1, fp) != 1)
856 goto fail;
857 if (fwrite(&name->length, sizeof(name->length), 1, fp) != 1)
858 goto fail;
859 if (fwrite(name->s, name->length, 1, fp) != 1)
860 goto fail;
861 if (fwrite(&raw_packet->length, sizeof(raw_packet->length), 1, fp) != 1)
862 goto fail;
863 if (fwrite(raw_packet->s, raw_packet->length, 1, fp) != 1)
864 goto fail;
865 return 1;
866fail:
867 return 0;
868}
869
870/*
871 * This should be called before coap_persist_track_funcs() to prevent
872 * coap_op_dyn_resource_added() getting unnecessarily called.
873 *
874 * Each record 'proto len resource_name len raw_packet'
875 */
876static void
877coap_op_dyn_resource_load_disk(coap_context_t *ctx) {
878 FILE *fp_orig = NULL;
879 coap_proto_t e_proto;
880 coap_string_t *name = NULL;
881 coap_binary_t *raw_packet = NULL;
883 coap_session_t *session = NULL;
884 coap_pdu_t *request = NULL;
885 coap_pdu_t *response = NULL;
886 coap_string_t *query = NULL;
887
888 if (!ctx->unknown_resource)
889 return;
890
891 fp_orig = fopen((const char *)ctx->dyn_resource_save_file->s, "r");
892 if (fp_orig == NULL)
893 return;
895 sizeof(coap_session_t));
896 if (!session)
897 goto fail;
898 memset(session, 0, sizeof(coap_session_t));
899 session->context = ctx;
900
901 /* Go through and create each dynamic resource if it does not exist*/
902 while (1) {
903 if (!coap_op_dyn_resource_read(fp_orig, &e_proto, &name, &raw_packet))
904 break;
906 if (!r) {
907 /* Create the new resource using the application logic */
908
909 coap_log_debug("persist: dynamic resource being re-created\n");
910 /*
911 * Need max space incase PDU is updated with updated token,
912 * huge size etc.
913 * */
914 request = coap_pdu_init(0, 0, 0, 0);
915 if (!request)
916 goto fail;
917
918 session->proto = e_proto;
919 if (!coap_pdu_parse(session->proto, raw_packet->s,
920 raw_packet->length, request)) {
921 goto fail;
922 }
923 if (!ctx->unknown_resource->handler[request->code-1])
924 goto fail;
925 response = coap_pdu_init(0, 0, 0, 0);
926 if (!response)
927 goto fail;
928 query = coap_get_query(request);
929 /* Call the application handler to set up this dynamic resource */
930 ctx->unknown_resource->handler[request->code-1](ctx->unknown_resource,
931 session, request,
932 query, response);
933 coap_delete_string(query);
934 query = NULL;
935 coap_delete_pdu(request);
936 request = NULL;
937 coap_delete_pdu(response);
938 response = NULL;
939 }
940 coap_delete_string(name);
941 coap_delete_binary(raw_packet);
942 }
943fail:
944 coap_delete_string(name);
945 coap_delete_binary(raw_packet);
946 coap_delete_string(query);
947 coap_delete_pdu(request);
948 coap_delete_pdu(response);
949 fclose(fp_orig);
951}
952
953/*
954 * Server has set up a new dynamic resource agains a request for an unknown
955 * resource.
956 */
957static int
958coap_op_dyn_resource_added(coap_session_t *session,
959 coap_str_const_t *resource_name,
960 coap_bin_const_t *packet,
961 void *user_data) {
962 FILE *fp_orig;
963 FILE *fp_new = NULL;
964 char *new = NULL;
965 coap_context_t *context = session->context;
966 coap_string_t *name = NULL;
967 coap_binary_t *raw_packet = NULL;
968 coap_proto_t e_proto;
969
970 (void)user_data;
971
972 fp_orig = fopen((const char *)context->dyn_resource_save_file->s, "a");
973 if (fp_orig == NULL)
974 return 0;
975
977 context->dyn_resource_save_file->length + 5);
978 if (!new)
979 goto fail;
980
981 strcpy(new, (const char *)context->dyn_resource_save_file->s);
982 strcat(new, ".tmp");
983 fp_new = fopen(new, "w+");
984 if (fp_new == NULL)
985 goto fail;
986
987 /* Go through and locate duplicate resource to delete */
988 while (1) {
989 if (!coap_op_dyn_resource_read(fp_orig, &e_proto, &name, &raw_packet))
990 break;
991 if (!coap_string_equal(resource_name, name)) {
992 /* Copy across non-matching entry */
993 if (!coap_op_dyn_resource_write(fp_new, e_proto, (coap_str_const_t *)name,
994 (coap_bin_const_t *)raw_packet))
995 break;
996 }
997 coap_delete_string(name);
998 name = NULL;
999 coap_delete_binary(raw_packet);
1000 raw_packet = NULL;
1001 }
1002 coap_delete_string(name);
1003 coap_delete_binary(raw_packet);
1004 /* Add new entry to the end */
1005 if (!coap_op_dyn_resource_write(fp_new, session->proto,
1006 resource_name, packet))
1007 goto fail;
1008
1009 if (fflush(fp_new) == EOF)
1010 goto fail;
1011 fclose(fp_new);
1012 fclose(fp_orig);
1013 /* Either old or new is in place */
1014 (void)rename(new, (const char *)context->dyn_resource_save_file->s);
1016 return 1;
1017
1018fail:
1019 if (fp_new)
1020 fclose(fp_new);
1021 if (fp_orig)
1022 fclose(fp_orig);
1023 if (new) {
1024 (void)remove(new);
1025 }
1027 return 0;
1028}
1029
1030/*
1031 * Server has deleted a resource
1032 */
1033static int
1034coap_op_resource_deleted(coap_context_t *context,
1035 coap_str_const_t *resource_name,
1036 void *user_data) {
1037 FILE *fp_orig = NULL;
1038 FILE *fp_new = NULL;
1039 char *new = NULL;
1040 coap_proto_t e_proto;
1041 coap_string_t *name = NULL;
1042 coap_binary_t *raw_packet = NULL;
1043 (void)user_data;
1044
1045 coap_op_obs_cnt_deleted(context, resource_name);
1046
1047 fp_orig = fopen((const char *)context->dyn_resource_save_file->s, "r");
1048 if (fp_orig == NULL)
1049 return 1;
1050
1052 context->dyn_resource_save_file->length + 5);
1053 if (!new)
1054 goto fail;
1055
1056 strcpy(new, (const char *)context->dyn_resource_save_file->s);
1057 strcat(new, ".tmp");
1058 fp_new = fopen(new, "w+");
1059 if (fp_new == NULL)
1060 goto fail;
1061
1062 /* Go through and locate resource to delete and not copy it across */
1063 while (1) {
1064 if (!coap_op_dyn_resource_read(fp_orig, &e_proto, &name, &raw_packet))
1065 break;
1066 if (!coap_string_equal(resource_name, name)) {
1067 /* Copy across non-matching entry */
1068 if (!coap_op_dyn_resource_write(fp_new, e_proto, (coap_str_const_t *)name,
1069 (coap_bin_const_t *)raw_packet))
1070 break;
1071 }
1072 coap_delete_string(name);
1073 name = NULL;
1074 coap_delete_binary(raw_packet);
1075 raw_packet = NULL;
1076 }
1077 coap_delete_string(name);
1078 coap_delete_binary(raw_packet);
1079
1080 if (fflush(fp_new) == EOF)
1081 goto fail;
1082 fclose(fp_new);
1083 fclose(fp_orig);
1084 /* Either old or new is in place */
1085 (void)rename(new, (const char *)context->dyn_resource_save_file->s);
1087 return 1;
1088
1089fail:
1090 if (fp_new)
1091 fclose(fp_new);
1092 if (fp_orig)
1093 fclose(fp_orig);
1094 if (new) {
1095 (void)remove(new);
1096 }
1098 return 0;
1099}
1100
1101int
1103 const char *dyn_resource_save_file,
1104 const char *observe_save_file,
1105 const char *obs_cnt_save_file,
1106 uint32_t save_freq) {
1107 if (dyn_resource_save_file) {
1108 context->dyn_resource_save_file =
1109 coap_new_bin_const((const uint8_t *)dyn_resource_save_file,
1110 strlen(dyn_resource_save_file));
1111 if (!context->dyn_resource_save_file)
1112 return 0;
1113 coap_op_dyn_resource_load_disk(context);
1114 context->dyn_resource_added = coap_op_dyn_resource_added;
1115 context->resource_deleted = coap_op_resource_deleted;
1116 }
1117 if (obs_cnt_save_file) {
1118 context->obs_cnt_save_file =
1119 coap_new_bin_const((const uint8_t *)obs_cnt_save_file,
1120 strlen(obs_cnt_save_file));
1121 if (!context->obs_cnt_save_file)
1122 return 0;
1123 context->observe_save_freq = save_freq ? save_freq : 1;
1124 coap_op_obs_cnt_load_disk(context);
1125 context->track_observe_value = coap_op_obs_cnt_track_observe;
1126 context->resource_deleted = coap_op_resource_deleted;
1127 }
1128 if (observe_save_file) {
1129 context->observe_save_file =
1130 coap_new_bin_const((const uint8_t *)observe_save_file,
1131 strlen(observe_save_file));
1132 if (!context->observe_save_file)
1133 return 0;
1134 coap_op_observe_load_disk(context);
1135 context->observe_added = coap_op_observe_added;
1136 context->observe_deleted = coap_op_observe_deleted;
1137 }
1138 return 1;
1139}
1140
1141void
1143 coap_delete_bin_const(context->dyn_resource_save_file);
1144 coap_delete_bin_const(context->obs_cnt_save_file);
1145 coap_delete_bin_const(context->observe_save_file);
1146 context->dyn_resource_save_file = NULL;
1147 context->obs_cnt_save_file = NULL;
1148 context->observe_save_file = NULL;
1149
1150 /* Close down any tracking */
1151 coap_persist_track_funcs(context, NULL, NULL, NULL, NULL,
1152 NULL, 0, NULL);
1153}
1154
1155void
1157 if (context == NULL)
1158 return;
1159 context->observe_no_clear = 1;
1160 coap_persist_cleanup(context);
1161}
1162#else /* ! COAP_WITH_OBSERVE_PERSIST */
1163int
1165 const char *dyn_resource_save_file,
1166 const char *observe_save_file,
1167 const char *obs_cnt_save_file,
1168 uint32_t save_freq) {
1169 (void)context;
1170 (void)dyn_resource_save_file;
1171 (void)observe_save_file;
1172 (void)obs_cnt_save_file;
1173 (void)save_freq;
1174 return 0;
1175}
1176
1177void
1179 context->observe_no_clear = 1;
1180 /* Close down any tracking */
1181 coap_persist_track_funcs(context, NULL, NULL, NULL, NULL,
1182 NULL, 0, NULL);
1183}
1184
1185#endif /* ! COAP_WITH_OBSERVE_PERSIST */
1186
1187#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:237
#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:224
#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...