Coverage Report

Created: 2026-06-10 06:32

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