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