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