1c87c5fbaSopenharmony_ci/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2c87c5fbaSopenharmony_ci
3c87c5fbaSopenharmony_ci/* coap -- simple implementation of the Constrained Application Protocol (CoAP)
4c87c5fbaSopenharmony_ci *         as defined in RFC 7252
5c87c5fbaSopenharmony_ci *
6c87c5fbaSopenharmony_ci * Copyright (C) 2010--2023 Olaf Bergmann <bergmann@tzi.org> and others
7c87c5fbaSopenharmony_ci *
8c87c5fbaSopenharmony_ci * SPDX-License-Identifier: BSD-2-Clause
9c87c5fbaSopenharmony_ci *
10c87c5fbaSopenharmony_ci * This file is part of the CoAP library libcoap. Please see README for terms
11c87c5fbaSopenharmony_ci * of use.
12c87c5fbaSopenharmony_ci */
13c87c5fbaSopenharmony_ci
14c87c5fbaSopenharmony_ci#include <string.h>
15c87c5fbaSopenharmony_ci#include <stdlib.h>
16c87c5fbaSopenharmony_ci#include <stdio.h>
17c87c5fbaSopenharmony_ci#include <ctype.h>
18c87c5fbaSopenharmony_ci#include <inttypes.h>
19c87c5fbaSopenharmony_ci#include <sys/types.h>
20c87c5fbaSopenharmony_ci#include <sys/stat.h>
21c87c5fbaSopenharmony_ci#include <errno.h>
22c87c5fbaSopenharmony_ci#include <signal.h>
23c87c5fbaSopenharmony_ci#ifdef _WIN32
24c87c5fbaSopenharmony_ci#define strcasecmp _stricmp
25c87c5fbaSopenharmony_ci#define strncasecmp _strnicmp
26c87c5fbaSopenharmony_ci#include "getopt.c"
27c87c5fbaSopenharmony_ci#if !defined(S_ISDIR)
28c87c5fbaSopenharmony_ci#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
29c87c5fbaSopenharmony_ci#endif
30c87c5fbaSopenharmony_ci#ifndef R_OK
31c87c5fbaSopenharmony_ci#define R_OK 4
32c87c5fbaSopenharmony_ci#endif
33c87c5fbaSopenharmony_cichar *strndup(const char *s1, size_t n);
34c87c5fbaSopenharmony_cichar *
35c87c5fbaSopenharmony_cistrndup(const char *s1, size_t n) {
36c87c5fbaSopenharmony_ci  char *copy = (char *)malloc(n + 1);
37c87c5fbaSopenharmony_ci  if (copy) {
38c87c5fbaSopenharmony_ci    memcpy(copy, s1, n);
39c87c5fbaSopenharmony_ci    copy[n] = 0;
40c87c5fbaSopenharmony_ci  }
41c87c5fbaSopenharmony_ci  return copy;
42c87c5fbaSopenharmony_ci}
43c87c5fbaSopenharmony_ci#include <io.h>
44c87c5fbaSopenharmony_ci#define access _access
45c87c5fbaSopenharmony_ci#define fileno _fileno
46c87c5fbaSopenharmony_ci#else
47c87c5fbaSopenharmony_ci#include <unistd.h>
48c87c5fbaSopenharmony_ci#include <sys/select.h>
49c87c5fbaSopenharmony_ci#include <sys/socket.h>
50c87c5fbaSopenharmony_ci#include <netinet/in.h>
51c87c5fbaSopenharmony_ci#include <arpa/inet.h>
52c87c5fbaSopenharmony_ci#include <netdb.h>
53c87c5fbaSopenharmony_ci#include <dirent.h>
54c87c5fbaSopenharmony_ci#include <syslog.h>
55c87c5fbaSopenharmony_ci#endif
56c87c5fbaSopenharmony_ci
57c87c5fbaSopenharmony_ci/*
58c87c5fbaSopenharmony_ci * SERVER_CAN_PROXY=0 can be set by build system if
59c87c5fbaSopenharmony_ci * "./configure --disable-client-mode" is used.
60c87c5fbaSopenharmony_ci */
61c87c5fbaSopenharmony_ci#ifndef SERVER_CAN_PROXY
62c87c5fbaSopenharmony_ci#define SERVER_CAN_PROXY 1
63c87c5fbaSopenharmony_ci#endif
64c87c5fbaSopenharmony_ci
65c87c5fbaSopenharmony_ci/* Need to refresh time once per sec */
66c87c5fbaSopenharmony_ci#define COAP_RESOURCE_CHECK_TIME 1
67c87c5fbaSopenharmony_ci
68c87c5fbaSopenharmony_ci#include <coap3/coap.h>
69c87c5fbaSopenharmony_ci
70c87c5fbaSopenharmony_ci#ifndef min
71c87c5fbaSopenharmony_ci#define min(a,b) ((a) < (b) ? (a) : (b))
72c87c5fbaSopenharmony_ci#endif
73c87c5fbaSopenharmony_ci
74c87c5fbaSopenharmony_cistatic coap_oscore_conf_t *oscore_conf;
75c87c5fbaSopenharmony_cistatic int doing_oscore = 0;
76c87c5fbaSopenharmony_ci
77c87c5fbaSopenharmony_ci/* set to 1 to request clean server shutdown */
78c87c5fbaSopenharmony_cistatic int quit = 0;
79c87c5fbaSopenharmony_ci
80c87c5fbaSopenharmony_ci/* set to 1 if persist information is to be kept on server shutdown */
81c87c5fbaSopenharmony_cistatic int keep_persist = 0;
82c87c5fbaSopenharmony_ci
83c87c5fbaSopenharmony_ci/* changeable clock base (see handle_put_time()) */
84c87c5fbaSopenharmony_cistatic time_t clock_offset;
85c87c5fbaSopenharmony_cistatic time_t my_clock_base = 0;
86c87c5fbaSopenharmony_ci
87c87c5fbaSopenharmony_cicoap_resource_t *time_resource = NULL;
88c87c5fbaSopenharmony_ci
89c87c5fbaSopenharmony_cistatic int resource_flags = COAP_RESOURCE_FLAGS_NOTIFY_CON;
90c87c5fbaSopenharmony_cistatic int track_observes = 0;
91c87c5fbaSopenharmony_ci
92c87c5fbaSopenharmony_ci/*
93c87c5fbaSopenharmony_ci * For PKI, if one or more of cert_file, key_file and ca_file is in PKCS11 URI
94c87c5fbaSopenharmony_ci * format, then the remainder of cert_file, key_file and ca_file are treated
95c87c5fbaSopenharmony_ci * as being in DER format to provide consistency across the underlying (D)TLS
96c87c5fbaSopenharmony_ci * libraries.
97c87c5fbaSopenharmony_ci */
98c87c5fbaSopenharmony_cistatic char *cert_file = NULL; /* certificate and optional private key in PEM,
99c87c5fbaSopenharmony_ci                                  or PKCS11 URI*/
100c87c5fbaSopenharmony_cistatic char *key_file = NULL; /* private key in PEM, DER or PKCS11 URI */
101c87c5fbaSopenharmony_cistatic char *pkcs11_pin = NULL; /* PKCS11 pin to unlock access to token */
102c87c5fbaSopenharmony_cistatic char *ca_file = NULL;   /* CA for cert_file - for cert checking in PEM,
103c87c5fbaSopenharmony_ci                                  DER or PKCS11 URI */
104c87c5fbaSopenharmony_cistatic char *root_ca_file = NULL; /* List of trusted Root CAs in PEM */
105c87c5fbaSopenharmony_cistatic int use_pem_buf = 0; /* Map these cert/key files into memory to test
106c87c5fbaSopenharmony_ci                               PEM_BUF logic if set */
107c87c5fbaSopenharmony_cistatic int is_rpk_not_cert = 0; /* Cert is RPK if set */
108c87c5fbaSopenharmony_ci/* Used to hold initial PEM_BUF setup */
109c87c5fbaSopenharmony_cistatic uint8_t *cert_mem_base = NULL; /* certificate and private key in PEM_BUF */
110c87c5fbaSopenharmony_cistatic uint8_t *key_mem_base = NULL; /* private key in PEM_BUF */
111c87c5fbaSopenharmony_cistatic uint8_t *ca_mem_base = NULL;   /* CA for cert checking in PEM_BUF */
112c87c5fbaSopenharmony_ci/* Used for verify_pki_sni_callback PEM_BUF temporary holding */
113c87c5fbaSopenharmony_cistatic uint8_t *cert_mem = NULL; /* certificate and private key in PEM_BUF */
114c87c5fbaSopenharmony_cistatic uint8_t *key_mem = NULL; /* private key in PEM_BUF */
115c87c5fbaSopenharmony_cistatic uint8_t *ca_mem = NULL;   /* CA for cert checking in PEM_BUF */
116c87c5fbaSopenharmony_cistatic size_t cert_mem_len = 0;
117c87c5fbaSopenharmony_cistatic size_t key_mem_len = 0;
118c87c5fbaSopenharmony_cistatic size_t ca_mem_len = 0;
119c87c5fbaSopenharmony_cistatic int verify_peer_cert = 1; /* PKI granularity - by default set */
120c87c5fbaSopenharmony_ci#define MAX_KEY   64 /* Maximum length of a pre-shared key in bytes. */
121c87c5fbaSopenharmony_cistatic uint8_t *key = NULL;
122c87c5fbaSopenharmony_cistatic ssize_t key_length = 0;
123c87c5fbaSopenharmony_ciint key_defined = 0;
124c87c5fbaSopenharmony_cistatic const char *hint = "CoAP";
125c87c5fbaSopenharmony_cistatic int support_dynamic = 0;
126c87c5fbaSopenharmony_cistatic uint32_t block_mode = COAP_BLOCK_USE_LIBCOAP;
127c87c5fbaSopenharmony_cistatic int echo_back = 0;
128c87c5fbaSopenharmony_cistatic uint32_t csm_max_message_size = 0;
129c87c5fbaSopenharmony_cistatic size_t extended_token_size = COAP_TOKEN_DEFAULT_MAX;
130c87c5fbaSopenharmony_cistatic coap_proto_t use_unix_proto = COAP_PROTO_NONE;
131c87c5fbaSopenharmony_cistatic int enable_ws = 0;
132c87c5fbaSopenharmony_cistatic int ws_port = 80;
133c87c5fbaSopenharmony_cistatic int wss_port = 443;
134c87c5fbaSopenharmony_ci
135c87c5fbaSopenharmony_cistatic coap_dtls_pki_t *setup_pki(coap_context_t *ctx, coap_dtls_role_t role, char *sni);
136c87c5fbaSopenharmony_ci
137c87c5fbaSopenharmony_citypedef struct psk_sni_def_t {
138c87c5fbaSopenharmony_ci  char *sni_match;
139c87c5fbaSopenharmony_ci  coap_bin_const_t *new_key;
140c87c5fbaSopenharmony_ci  coap_bin_const_t *new_hint;
141c87c5fbaSopenharmony_ci} psk_sni_def_t;
142c87c5fbaSopenharmony_ci
143c87c5fbaSopenharmony_citypedef struct valid_psk_snis_t {
144c87c5fbaSopenharmony_ci  size_t count;
145c87c5fbaSopenharmony_ci  psk_sni_def_t *psk_sni_list;
146c87c5fbaSopenharmony_ci} valid_psk_snis_t;
147c87c5fbaSopenharmony_ci
148c87c5fbaSopenharmony_cistatic valid_psk_snis_t valid_psk_snis = {0, NULL};
149c87c5fbaSopenharmony_ci
150c87c5fbaSopenharmony_citypedef struct id_def_t {
151c87c5fbaSopenharmony_ci  char *hint_match;
152c87c5fbaSopenharmony_ci  coap_bin_const_t *identity_match;
153c87c5fbaSopenharmony_ci  coap_bin_const_t *new_key;
154c87c5fbaSopenharmony_ci} id_def_t;
155c87c5fbaSopenharmony_ci
156c87c5fbaSopenharmony_citypedef struct valid_ids_t {
157c87c5fbaSopenharmony_ci  size_t count;
158c87c5fbaSopenharmony_ci  id_def_t *id_list;
159c87c5fbaSopenharmony_ci} valid_ids_t;
160c87c5fbaSopenharmony_ci
161c87c5fbaSopenharmony_cistatic valid_ids_t valid_ids = {0, NULL};
162c87c5fbaSopenharmony_citypedef struct pki_sni_def_t {
163c87c5fbaSopenharmony_ci  char *sni_match;
164c87c5fbaSopenharmony_ci  char *new_cert;
165c87c5fbaSopenharmony_ci  char *new_ca;
166c87c5fbaSopenharmony_ci} pki_sni_def_t;
167c87c5fbaSopenharmony_ci
168c87c5fbaSopenharmony_citypedef struct valid_pki_snis_t {
169c87c5fbaSopenharmony_ci  size_t count;
170c87c5fbaSopenharmony_ci  pki_sni_def_t *pki_sni_list;
171c87c5fbaSopenharmony_ci} valid_pki_snis_t;
172c87c5fbaSopenharmony_ci
173c87c5fbaSopenharmony_cistatic valid_pki_snis_t valid_pki_snis = {0, NULL};
174c87c5fbaSopenharmony_ci
175c87c5fbaSopenharmony_citypedef struct transient_value_t {
176c87c5fbaSopenharmony_ci  coap_binary_t *value;
177c87c5fbaSopenharmony_ci  size_t ref_cnt;
178c87c5fbaSopenharmony_ci} transient_value_t;
179c87c5fbaSopenharmony_ci
180c87c5fbaSopenharmony_ci/* temporary storage for dynamic resource representations */
181c87c5fbaSopenharmony_cistatic transient_value_t *example_data_value = NULL;
182c87c5fbaSopenharmony_cistatic int example_data_media_type = COAP_MEDIATYPE_TEXT_PLAIN;
183c87c5fbaSopenharmony_ci
184c87c5fbaSopenharmony_ci/* SIGINT handler: set quit to 1 for graceful termination */
185c87c5fbaSopenharmony_cistatic void
186c87c5fbaSopenharmony_cihandle_sigint(int signum COAP_UNUSED) {
187c87c5fbaSopenharmony_ci  quit = 1;
188c87c5fbaSopenharmony_ci}
189c87c5fbaSopenharmony_ci
190c87c5fbaSopenharmony_ci#ifndef _WIN32
191c87c5fbaSopenharmony_ci/*
192c87c5fbaSopenharmony_ci * SIGUSR2 handler: set quit to 1 for graceful termination
193c87c5fbaSopenharmony_ci * Disable sending out 4.04 for any active observations.
194c87c5fbaSopenharmony_ci * Note: coap_*() functions should not be called at sig interrupt.
195c87c5fbaSopenharmony_ci */
196c87c5fbaSopenharmony_cistatic void
197c87c5fbaSopenharmony_cihandle_sigusr2(int signum COAP_UNUSED) {
198c87c5fbaSopenharmony_ci  quit = 1;
199c87c5fbaSopenharmony_ci  keep_persist = 1;
200c87c5fbaSopenharmony_ci}
201c87c5fbaSopenharmony_ci#endif /* ! _WIN32 */
202c87c5fbaSopenharmony_ci
203c87c5fbaSopenharmony_ci/*
204c87c5fbaSopenharmony_ci * This will return a correctly formed transient_value_t *, or NULL.
205c87c5fbaSopenharmony_ci * If an error, the passed in coap_binary_t * will get deleted.
206c87c5fbaSopenharmony_ci * Note: transient_value->value will never be returned as NULL.
207c87c5fbaSopenharmony_ci */
208c87c5fbaSopenharmony_cistatic transient_value_t *
209c87c5fbaSopenharmony_cialloc_resource_data(coap_binary_t *value) {
210c87c5fbaSopenharmony_ci  transient_value_t *transient_value;
211c87c5fbaSopenharmony_ci  if (!value)
212c87c5fbaSopenharmony_ci    return NULL;
213c87c5fbaSopenharmony_ci  transient_value = coap_malloc(sizeof(transient_value_t));
214c87c5fbaSopenharmony_ci  if (!transient_value) {
215c87c5fbaSopenharmony_ci    coap_delete_binary(value);
216c87c5fbaSopenharmony_ci    return NULL;
217c87c5fbaSopenharmony_ci  }
218c87c5fbaSopenharmony_ci  transient_value->ref_cnt = 1;
219c87c5fbaSopenharmony_ci  transient_value->value = value;
220c87c5fbaSopenharmony_ci  return transient_value;
221c87c5fbaSopenharmony_ci}
222c87c5fbaSopenharmony_ci
223c87c5fbaSopenharmony_ci/*
224c87c5fbaSopenharmony_ci * Need to handle race conditions of data being updated (by PUT) and
225c87c5fbaSopenharmony_ci * being read by a blocked response to GET.
226c87c5fbaSopenharmony_ci */
227c87c5fbaSopenharmony_cistatic void
228c87c5fbaSopenharmony_cirelease_resource_data(coap_session_t *session COAP_UNUSED,
229c87c5fbaSopenharmony_ci                      void *app_ptr) {
230c87c5fbaSopenharmony_ci  transient_value_t *transient_value = (transient_value_t *)app_ptr;
231c87c5fbaSopenharmony_ci
232c87c5fbaSopenharmony_ci  if (!transient_value)
233c87c5fbaSopenharmony_ci    return;
234c87c5fbaSopenharmony_ci
235c87c5fbaSopenharmony_ci  if (--transient_value->ref_cnt > 0)
236c87c5fbaSopenharmony_ci    return;
237c87c5fbaSopenharmony_ci  coap_delete_binary(transient_value->value);
238c87c5fbaSopenharmony_ci  coap_free(transient_value);
239c87c5fbaSopenharmony_ci}
240c87c5fbaSopenharmony_ci
241c87c5fbaSopenharmony_ci/*
242c87c5fbaSopenharmony_ci * Bump the reference count and return reference to data
243c87c5fbaSopenharmony_ci */
244c87c5fbaSopenharmony_cistatic coap_binary_t
245c87c5fbaSopenharmony_cireference_resource_data(transient_value_t *entry) {
246c87c5fbaSopenharmony_ci  coap_binary_t body;
247c87c5fbaSopenharmony_ci  if (entry) {
248c87c5fbaSopenharmony_ci    /* Bump reference so not removed elsewhere */
249c87c5fbaSopenharmony_ci    entry->ref_cnt++;
250c87c5fbaSopenharmony_ci    assert(entry->value);
251c87c5fbaSopenharmony_ci    body.length = entry->value->length;
252c87c5fbaSopenharmony_ci    body.s = entry->value->s;
253c87c5fbaSopenharmony_ci  } else {
254c87c5fbaSopenharmony_ci    body.length = 0;
255c87c5fbaSopenharmony_ci    body.s = NULL;
256c87c5fbaSopenharmony_ci  }
257c87c5fbaSopenharmony_ci  return body;
258c87c5fbaSopenharmony_ci}
259c87c5fbaSopenharmony_ci
260c87c5fbaSopenharmony_ci#define INDEX "This is a test server made with libcoap (see https://libcoap.net)\n" \
261c87c5fbaSopenharmony_ci  "Copyright (C) 2010--2023 Olaf Bergmann <bergmann@tzi.org> and others\n\n"
262c87c5fbaSopenharmony_ci
263c87c5fbaSopenharmony_cistatic void
264c87c5fbaSopenharmony_cihnd_get_index(coap_resource_t *resource,
265c87c5fbaSopenharmony_ci              coap_session_t *session,
266c87c5fbaSopenharmony_ci              const coap_pdu_t *request,
267c87c5fbaSopenharmony_ci              const coap_string_t *query COAP_UNUSED,
268c87c5fbaSopenharmony_ci              coap_pdu_t *response) {
269c87c5fbaSopenharmony_ci
270c87c5fbaSopenharmony_ci  coap_pdu_set_code(response, COAP_RESPONSE_CODE_CONTENT);
271c87c5fbaSopenharmony_ci  coap_add_data_large_response(resource, session, request, response,
272c87c5fbaSopenharmony_ci                               query, COAP_MEDIATYPE_TEXT_PLAIN,
273c87c5fbaSopenharmony_ci                               0x2ffff, 0, strlen(INDEX),
274c87c5fbaSopenharmony_ci                               (const uint8_t *)INDEX, NULL, NULL);
275c87c5fbaSopenharmony_ci}
276c87c5fbaSopenharmony_ci
277c87c5fbaSopenharmony_cistatic void
278c87c5fbaSopenharmony_cihnd_get_fetch_time(coap_resource_t *resource,
279c87c5fbaSopenharmony_ci                   coap_session_t *session,
280c87c5fbaSopenharmony_ci                   const coap_pdu_t *request,
281c87c5fbaSopenharmony_ci                   const coap_string_t *query,
282c87c5fbaSopenharmony_ci                   coap_pdu_t *response) {
283c87c5fbaSopenharmony_ci  unsigned char buf[40];
284c87c5fbaSopenharmony_ci  size_t len;
285c87c5fbaSopenharmony_ci  time_t now;
286c87c5fbaSopenharmony_ci  coap_tick_t t;
287c87c5fbaSopenharmony_ci  (void)request;
288c87c5fbaSopenharmony_ci  coap_pdu_code_t code = coap_pdu_get_code(request);
289c87c5fbaSopenharmony_ci  size_t size;
290c87c5fbaSopenharmony_ci  const uint8_t *data;
291c87c5fbaSopenharmony_ci  coap_str_const_t *ticks = coap_make_str_const("ticks");
292c87c5fbaSopenharmony_ci
293c87c5fbaSopenharmony_ci  if (my_clock_base) {
294c87c5fbaSopenharmony_ci
295c87c5fbaSopenharmony_ci    /* calculate current time */
296c87c5fbaSopenharmony_ci    coap_ticks(&t);
297c87c5fbaSopenharmony_ci    now = my_clock_base + (t / COAP_TICKS_PER_SECOND);
298c87c5fbaSopenharmony_ci
299c87c5fbaSopenharmony_ci    /* coap_get_data() sets size to 0 on error */
300c87c5fbaSopenharmony_ci    (void)coap_get_data(request, &size, &data);
301c87c5fbaSopenharmony_ci
302c87c5fbaSopenharmony_ci    if (code == COAP_REQUEST_CODE_GET && query != NULL &&
303c87c5fbaSopenharmony_ci        coap_string_equal(query, ticks)) {
304c87c5fbaSopenharmony_ci      /* parameter is in query, output ticks */
305c87c5fbaSopenharmony_ci      len = snprintf((char *)buf, sizeof(buf), "%" PRIi64, (int64_t)now);
306c87c5fbaSopenharmony_ci    } else if (code == COAP_REQUEST_CODE_FETCH && size == ticks->length &&
307c87c5fbaSopenharmony_ci               memcmp(data, ticks->s, ticks->length) == 0) {
308c87c5fbaSopenharmony_ci      /* parameter is in data, output ticks */
309c87c5fbaSopenharmony_ci      len = snprintf((char *)buf, sizeof(buf), "%" PRIi64, (int64_t)now);
310c87c5fbaSopenharmony_ci    } else {      /* output human-readable time */
311c87c5fbaSopenharmony_ci      struct tm *tmp;
312c87c5fbaSopenharmony_ci      tmp = gmtime(&now);
313c87c5fbaSopenharmony_ci      if (!tmp) {
314c87c5fbaSopenharmony_ci        /* If 'now' is not valid */
315c87c5fbaSopenharmony_ci        coap_pdu_set_code(response, COAP_RESPONSE_CODE_NOT_FOUND);
316c87c5fbaSopenharmony_ci        return;
317c87c5fbaSopenharmony_ci      } else {
318c87c5fbaSopenharmony_ci        len = strftime((char *)buf, sizeof(buf), "%b %d %H:%M:%S", tmp);
319c87c5fbaSopenharmony_ci      }
320c87c5fbaSopenharmony_ci    }
321c87c5fbaSopenharmony_ci    coap_pdu_set_code(response, COAP_RESPONSE_CODE_CONTENT);
322c87c5fbaSopenharmony_ci    coap_add_data_large_response(resource, session, request, response,
323c87c5fbaSopenharmony_ci                                 query, COAP_MEDIATYPE_TEXT_PLAIN, 1, 0,
324c87c5fbaSopenharmony_ci                                 len,
325c87c5fbaSopenharmony_ci                                 buf, NULL, NULL);
326c87c5fbaSopenharmony_ci  } else {
327c87c5fbaSopenharmony_ci    /* if my_clock_base was deleted, we pretend to have no such resource */
328c87c5fbaSopenharmony_ci    coap_pdu_set_code(response, COAP_RESPONSE_CODE_NOT_FOUND);
329c87c5fbaSopenharmony_ci  }
330c87c5fbaSopenharmony_ci}
331c87c5fbaSopenharmony_ci
332c87c5fbaSopenharmony_cistatic void
333c87c5fbaSopenharmony_cihnd_put_time(coap_resource_t *resource,
334c87c5fbaSopenharmony_ci             coap_session_t *session COAP_UNUSED,
335c87c5fbaSopenharmony_ci             const coap_pdu_t *request,
336c87c5fbaSopenharmony_ci             const coap_string_t *query COAP_UNUSED,
337c87c5fbaSopenharmony_ci             coap_pdu_t *response) {
338c87c5fbaSopenharmony_ci  coap_tick_t t;
339c87c5fbaSopenharmony_ci  size_t size;
340c87c5fbaSopenharmony_ci  const uint8_t *data;
341c87c5fbaSopenharmony_ci
342c87c5fbaSopenharmony_ci  /* FIXME: re-set my_clock_base to clock_offset if my_clock_base == 0
343c87c5fbaSopenharmony_ci   * and request is empty. When not empty, set to value in request payload
344c87c5fbaSopenharmony_ci   * (insist on query ?ticks). Return Created or Ok.
345c87c5fbaSopenharmony_ci   */
346c87c5fbaSopenharmony_ci
347c87c5fbaSopenharmony_ci  /* if my_clock_base was deleted, we pretend to have no such resource */
348c87c5fbaSopenharmony_ci  coap_pdu_set_code(response, my_clock_base ? COAP_RESPONSE_CODE_CHANGED :
349c87c5fbaSopenharmony_ci                    COAP_RESPONSE_CODE_CREATED);
350c87c5fbaSopenharmony_ci
351c87c5fbaSopenharmony_ci  coap_resource_notify_observers(resource, NULL);
352c87c5fbaSopenharmony_ci
353c87c5fbaSopenharmony_ci  /* coap_get_data() sets size to 0 on error */
354c87c5fbaSopenharmony_ci  (void)coap_get_data(request, &size, &data);
355c87c5fbaSopenharmony_ci
356c87c5fbaSopenharmony_ci  if (size == 0) {      /* re-init */
357c87c5fbaSopenharmony_ci    my_clock_base = clock_offset;
358c87c5fbaSopenharmony_ci  } else {
359c87c5fbaSopenharmony_ci    my_clock_base = 0;
360c87c5fbaSopenharmony_ci    coap_ticks(&t);
361c87c5fbaSopenharmony_ci    while (size--)
362c87c5fbaSopenharmony_ci      my_clock_base = my_clock_base * 10 + *data++;
363c87c5fbaSopenharmony_ci    my_clock_base -= t / COAP_TICKS_PER_SECOND;
364c87c5fbaSopenharmony_ci
365c87c5fbaSopenharmony_ci    /* Sanity check input value */
366c87c5fbaSopenharmony_ci    if (!gmtime(&my_clock_base)) {
367c87c5fbaSopenharmony_ci      unsigned char buf[3];
368c87c5fbaSopenharmony_ci      coap_pdu_set_code(response, COAP_RESPONSE_CODE_BAD_REQUEST);
369c87c5fbaSopenharmony_ci      coap_add_option(response,
370c87c5fbaSopenharmony_ci                      COAP_OPTION_CONTENT_FORMAT,
371c87c5fbaSopenharmony_ci                      coap_encode_var_safe(buf, sizeof(buf),
372c87c5fbaSopenharmony_ci                                           COAP_MEDIATYPE_TEXT_PLAIN), buf);
373c87c5fbaSopenharmony_ci      coap_add_data(response, 22, (const uint8_t *)"Invalid set time value");
374c87c5fbaSopenharmony_ci      /* re-init as value is bad */
375c87c5fbaSopenharmony_ci      my_clock_base = clock_offset;
376c87c5fbaSopenharmony_ci    }
377c87c5fbaSopenharmony_ci  }
378c87c5fbaSopenharmony_ci}
379c87c5fbaSopenharmony_ci
380c87c5fbaSopenharmony_cistatic void
381c87c5fbaSopenharmony_cihnd_delete_time(coap_resource_t *resource COAP_UNUSED,
382c87c5fbaSopenharmony_ci                coap_session_t *session COAP_UNUSED,
383c87c5fbaSopenharmony_ci                const coap_pdu_t *request COAP_UNUSED,
384c87c5fbaSopenharmony_ci                const coap_string_t *query COAP_UNUSED,
385c87c5fbaSopenharmony_ci                coap_pdu_t *response COAP_UNUSED) {
386c87c5fbaSopenharmony_ci  my_clock_base = 0;    /* mark clock as "deleted" */
387c87c5fbaSopenharmony_ci
388c87c5fbaSopenharmony_ci  /* type = request->hdr->type == COAP_MESSAGE_CON  */
389c87c5fbaSopenharmony_ci  /*   ? COAP_MESSAGE_ACK : COAP_MESSAGE_NON; */
390c87c5fbaSopenharmony_ci}
391c87c5fbaSopenharmony_ci
392c87c5fbaSopenharmony_ci/*
393c87c5fbaSopenharmony_ci * This logic is used to test out that the client correctly handles a
394c87c5fbaSopenharmony_ci * "separate" response (empty ACK followed by data response at a later stage).
395c87c5fbaSopenharmony_ci */
396c87c5fbaSopenharmony_cistatic void
397c87c5fbaSopenharmony_cihnd_get_async(coap_resource_t *resource,
398c87c5fbaSopenharmony_ci              coap_session_t *session,
399c87c5fbaSopenharmony_ci              const coap_pdu_t *request,
400c87c5fbaSopenharmony_ci              const coap_string_t *query,
401c87c5fbaSopenharmony_ci              coap_pdu_t *response) {
402c87c5fbaSopenharmony_ci  unsigned long delay = 4; /* Less than COAP_DEFAULT_LEISURE */
403c87c5fbaSopenharmony_ci  size_t size;
404c87c5fbaSopenharmony_ci  coap_async_t *async;
405c87c5fbaSopenharmony_ci  coap_bin_const_t token = coap_pdu_get_token(request);
406c87c5fbaSopenharmony_ci
407c87c5fbaSopenharmony_ci  /*
408c87c5fbaSopenharmony_ci   * See if this is the initial, or delayed request
409c87c5fbaSopenharmony_ci   */
410c87c5fbaSopenharmony_ci
411c87c5fbaSopenharmony_ci  async = coap_find_async(session, token);
412c87c5fbaSopenharmony_ci  if (!async) {
413c87c5fbaSopenharmony_ci    /* Set up an async request to trigger delay in the future */
414c87c5fbaSopenharmony_ci    if (query) {
415c87c5fbaSopenharmony_ci      /* Expect the query to just be the number of seconds to delay */
416c87c5fbaSopenharmony_ci      const uint8_t *p = query->s;
417c87c5fbaSopenharmony_ci
418c87c5fbaSopenharmony_ci      if (isdigit(*p)) {
419c87c5fbaSopenharmony_ci        delay = 0;
420c87c5fbaSopenharmony_ci        for (size = query->length; size; --size, ++p) {
421c87c5fbaSopenharmony_ci          if (!isdigit(*p))
422c87c5fbaSopenharmony_ci            break;
423c87c5fbaSopenharmony_ci          delay = delay * 10 + (*p - '0');
424c87c5fbaSopenharmony_ci        }
425c87c5fbaSopenharmony_ci      } else {
426c87c5fbaSopenharmony_ci        coap_log_debug("async: query is just a number of seconds to alter delay\n");
427c87c5fbaSopenharmony_ci      }
428c87c5fbaSopenharmony_ci      if (delay == 0) {
429c87c5fbaSopenharmony_ci        coap_log_info("async: delay of 0 not supported\n");
430c87c5fbaSopenharmony_ci        coap_pdu_set_code(response, COAP_RESPONSE_CODE_BAD_REQUEST);
431c87c5fbaSopenharmony_ci        return;
432c87c5fbaSopenharmony_ci      }
433c87c5fbaSopenharmony_ci    }
434c87c5fbaSopenharmony_ci    async = coap_register_async(session,
435c87c5fbaSopenharmony_ci                                request,
436c87c5fbaSopenharmony_ci                                COAP_TICKS_PER_SECOND * delay);
437c87c5fbaSopenharmony_ci    if (async == NULL) {
438c87c5fbaSopenharmony_ci      coap_pdu_set_code(response, COAP_RESPONSE_CODE_SERVICE_UNAVAILABLE);
439c87c5fbaSopenharmony_ci      return;
440c87c5fbaSopenharmony_ci    }
441c87c5fbaSopenharmony_ci    /*
442c87c5fbaSopenharmony_ci     * Not setting response code will cause empty ACK to be sent
443c87c5fbaSopenharmony_ci     * if Confirmable
444c87c5fbaSopenharmony_ci     */
445c87c5fbaSopenharmony_ci    return;
446c87c5fbaSopenharmony_ci  }
447c87c5fbaSopenharmony_ci  /* no request (observe) or async set up, so this is the delayed request */
448c87c5fbaSopenharmony_ci
449c87c5fbaSopenharmony_ci  /* Send back the appropriate data */
450c87c5fbaSopenharmony_ci  coap_add_data_large_response(resource, session, request, response,
451c87c5fbaSopenharmony_ci                               query, COAP_MEDIATYPE_TEXT_PLAIN, -1, 0, 4,
452c87c5fbaSopenharmony_ci                               (const uint8_t *)"done", NULL, NULL);
453c87c5fbaSopenharmony_ci  coap_pdu_set_code(response, COAP_RESPONSE_CODE_CONTENT);
454c87c5fbaSopenharmony_ci
455c87c5fbaSopenharmony_ci  /* async is automatically removed by libcoap on return from this handler */
456c87c5fbaSopenharmony_ci}
457c87c5fbaSopenharmony_ci
458c87c5fbaSopenharmony_ci/*
459c87c5fbaSopenharmony_ci * Large Data GET handler
460c87c5fbaSopenharmony_ci */
461c87c5fbaSopenharmony_ci
462c87c5fbaSopenharmony_ci#ifndef INITIAL_EXAMPLE_SIZE
463c87c5fbaSopenharmony_ci#define INITIAL_EXAMPLE_SIZE 1500
464c87c5fbaSopenharmony_ci#endif
465c87c5fbaSopenharmony_cistatic void
466c87c5fbaSopenharmony_cihnd_get_example_data(coap_resource_t *resource,
467c87c5fbaSopenharmony_ci                     coap_session_t *session,
468c87c5fbaSopenharmony_ci                     const coap_pdu_t *request,
469c87c5fbaSopenharmony_ci                     const coap_string_t *query,
470c87c5fbaSopenharmony_ci                     coap_pdu_t *response) {
471c87c5fbaSopenharmony_ci  coap_binary_t body;
472c87c5fbaSopenharmony_ci  if (!example_data_value) {
473c87c5fbaSopenharmony_ci    /* Initialise for the first time */
474c87c5fbaSopenharmony_ci    int i;
475c87c5fbaSopenharmony_ci    coap_binary_t *value = coap_new_binary(INITIAL_EXAMPLE_SIZE);
476c87c5fbaSopenharmony_ci    if (value) {
477c87c5fbaSopenharmony_ci      for (i = 0; i < INITIAL_EXAMPLE_SIZE; i++) {
478c87c5fbaSopenharmony_ci        if ((i % 10) == 0) {
479c87c5fbaSopenharmony_ci          value->s[i] = 'a' + (i/10) % 26;
480c87c5fbaSopenharmony_ci        } else {
481c87c5fbaSopenharmony_ci          value->s[i] = '0' + i%10;
482c87c5fbaSopenharmony_ci        }
483c87c5fbaSopenharmony_ci      }
484c87c5fbaSopenharmony_ci    }
485c87c5fbaSopenharmony_ci    example_data_value = alloc_resource_data(value);
486c87c5fbaSopenharmony_ci  }
487c87c5fbaSopenharmony_ci  coap_pdu_set_code(response, COAP_RESPONSE_CODE_CONTENT);
488c87c5fbaSopenharmony_ci  body = reference_resource_data(example_data_value);
489c87c5fbaSopenharmony_ci  coap_add_data_large_response(resource, session, request, response,
490c87c5fbaSopenharmony_ci                               query, example_data_media_type, -1, 0,
491c87c5fbaSopenharmony_ci                               body.length,
492c87c5fbaSopenharmony_ci                               body.s,
493c87c5fbaSopenharmony_ci                               release_resource_data, example_data_value);
494c87c5fbaSopenharmony_ci}
495c87c5fbaSopenharmony_ci
496c87c5fbaSopenharmony_cistatic void
497c87c5fbaSopenharmony_cicache_free_app_data(void *data) {
498c87c5fbaSopenharmony_ci  coap_binary_t *bdata = (coap_binary_t *)data;
499c87c5fbaSopenharmony_ci  coap_delete_binary(bdata);
500c87c5fbaSopenharmony_ci}
501c87c5fbaSopenharmony_ci
502c87c5fbaSopenharmony_ci/*
503c87c5fbaSopenharmony_ci * Large Data PUT handler
504c87c5fbaSopenharmony_ci */
505c87c5fbaSopenharmony_ci
506c87c5fbaSopenharmony_cistatic void
507c87c5fbaSopenharmony_cihnd_put_example_data(coap_resource_t *resource,
508c87c5fbaSopenharmony_ci                     coap_session_t *session,
509c87c5fbaSopenharmony_ci                     const coap_pdu_t *request,
510c87c5fbaSopenharmony_ci                     const coap_string_t *query COAP_UNUSED,
511c87c5fbaSopenharmony_ci                     coap_pdu_t *response) {
512c87c5fbaSopenharmony_ci  size_t size;
513c87c5fbaSopenharmony_ci  const uint8_t *data;
514c87c5fbaSopenharmony_ci  coap_opt_iterator_t opt_iter;
515c87c5fbaSopenharmony_ci  coap_opt_t *option;
516c87c5fbaSopenharmony_ci  size_t offset;
517c87c5fbaSopenharmony_ci  size_t total;
518c87c5fbaSopenharmony_ci  coap_binary_t *data_so_far;
519c87c5fbaSopenharmony_ci
520c87c5fbaSopenharmony_ci  if (coap_get_data_large(request, &size, &data, &offset, &total) &&
521c87c5fbaSopenharmony_ci      size != total) {
522c87c5fbaSopenharmony_ci    /*
523c87c5fbaSopenharmony_ci     * A part of the data has been received (COAP_BLOCK_SINGLE_BODY not set).
524c87c5fbaSopenharmony_ci     * However, total unfortunately is only an indication, so it is not safe to
525c87c5fbaSopenharmony_ci     * allocate a block based on total.  As per
526c87c5fbaSopenharmony_ci     * https://rfc-editor.org/rfc/rfc7959#section-4
527c87c5fbaSopenharmony_ci     *   o  In a request carrying a Block1 Option, to indicate the current
528c87c5fbaSopenharmony_ci     *         estimate the client has of the total size of the resource
529c87c5fbaSopenharmony_ci     *         representation, measured in bytes ("size indication").
530c87c5fbaSopenharmony_ci     *
531c87c5fbaSopenharmony_ci     * coap_cache_ignore_options() must have previously been called with at
532c87c5fbaSopenharmony_ci     * least COAP_OPTION_BLOCK1 set as the option value will change per block.
533c87c5fbaSopenharmony_ci     */
534c87c5fbaSopenharmony_ci    coap_cache_entry_t *cache_entry = coap_cache_get_by_pdu(session,
535c87c5fbaSopenharmony_ci                                                            request,
536c87c5fbaSopenharmony_ci                                                            COAP_CACHE_IS_SESSION_BASED);
537c87c5fbaSopenharmony_ci
538c87c5fbaSopenharmony_ci    if (offset == 0) {
539c87c5fbaSopenharmony_ci      if (!cache_entry) {
540c87c5fbaSopenharmony_ci        /*
541c87c5fbaSopenharmony_ci         * Set idle_timeout parameter to COAP_MAX_TRANSMIT_WAIT if you want
542c87c5fbaSopenharmony_ci         * early removal on transmission failure. 0 means only delete when
543c87c5fbaSopenharmony_ci         * the session is deleted as session_based is set here.
544c87c5fbaSopenharmony_ci         */
545c87c5fbaSopenharmony_ci        cache_entry = coap_new_cache_entry(session, request,
546c87c5fbaSopenharmony_ci                                           COAP_CACHE_NOT_RECORD_PDU,
547c87c5fbaSopenharmony_ci                                           COAP_CACHE_IS_SESSION_BASED, 0);
548c87c5fbaSopenharmony_ci      } else {
549c87c5fbaSopenharmony_ci        data_so_far = coap_cache_get_app_data(cache_entry);
550c87c5fbaSopenharmony_ci        if (data_so_far) {
551c87c5fbaSopenharmony_ci          coap_delete_binary(data_so_far);
552c87c5fbaSopenharmony_ci          data_so_far = NULL;
553c87c5fbaSopenharmony_ci        }
554c87c5fbaSopenharmony_ci        coap_cache_set_app_data(cache_entry, NULL, NULL);
555c87c5fbaSopenharmony_ci      }
556c87c5fbaSopenharmony_ci    }
557c87c5fbaSopenharmony_ci    if (!cache_entry) {
558c87c5fbaSopenharmony_ci      if (offset == 0) {
559c87c5fbaSopenharmony_ci        coap_log_warn("Unable to create a new cache entry\n");
560c87c5fbaSopenharmony_ci      } else {
561c87c5fbaSopenharmony_ci        coap_log_warn("No cache entry available for the non-first BLOCK\n");
562c87c5fbaSopenharmony_ci      }
563c87c5fbaSopenharmony_ci      coap_pdu_set_code(response, COAP_RESPONSE_CODE_INTERNAL_ERROR);
564c87c5fbaSopenharmony_ci      return;
565c87c5fbaSopenharmony_ci    }
566c87c5fbaSopenharmony_ci
567c87c5fbaSopenharmony_ci    if (size) {
568c87c5fbaSopenharmony_ci      /* Add in the new data to cache entry */
569c87c5fbaSopenharmony_ci      data_so_far = coap_cache_get_app_data(cache_entry);
570c87c5fbaSopenharmony_ci      data_so_far = coap_block_build_body(data_so_far, size, data,
571c87c5fbaSopenharmony_ci                                          offset, total);
572c87c5fbaSopenharmony_ci      /* Yes, data_so_far can be NULL if error */
573c87c5fbaSopenharmony_ci      coap_cache_set_app_data(cache_entry, data_so_far, cache_free_app_data);
574c87c5fbaSopenharmony_ci    }
575c87c5fbaSopenharmony_ci    if (offset + size == total) {
576c87c5fbaSopenharmony_ci      /* All the data is now in */
577c87c5fbaSopenharmony_ci      data_so_far = coap_cache_get_app_data(cache_entry);
578c87c5fbaSopenharmony_ci      coap_cache_set_app_data(cache_entry, NULL, NULL);
579c87c5fbaSopenharmony_ci    } else {
580c87c5fbaSopenharmony_ci      /* Give us the next block response */
581c87c5fbaSopenharmony_ci      coap_pdu_set_code(response, COAP_RESPONSE_CODE_CONTINUE);
582c87c5fbaSopenharmony_ci      return;
583c87c5fbaSopenharmony_ci    }
584c87c5fbaSopenharmony_ci  } else {
585c87c5fbaSopenharmony_ci    /* single body of data received */
586c87c5fbaSopenharmony_ci    data_so_far = coap_new_binary(size);
587c87c5fbaSopenharmony_ci    if (data_so_far) {
588c87c5fbaSopenharmony_ci      memcpy(data_so_far->s, data, size);
589c87c5fbaSopenharmony_ci    }
590c87c5fbaSopenharmony_ci  }
591c87c5fbaSopenharmony_ci
592c87c5fbaSopenharmony_ci  if (example_data_value) {
593c87c5fbaSopenharmony_ci    /* pre-existed response */
594c87c5fbaSopenharmony_ci    coap_pdu_set_code(response, COAP_RESPONSE_CODE_CHANGED);
595c87c5fbaSopenharmony_ci    /* Need to de-reference as value may be in use elsewhere */
596c87c5fbaSopenharmony_ci    release_resource_data(session, example_data_value);
597c87c5fbaSopenharmony_ci  } else
598c87c5fbaSopenharmony_ci    /* just generated response */
599c87c5fbaSopenharmony_ci    coap_pdu_set_code(response, COAP_RESPONSE_CODE_CREATED);
600c87c5fbaSopenharmony_ci
601c87c5fbaSopenharmony_ci  example_data_value = alloc_resource_data(data_so_far);
602c87c5fbaSopenharmony_ci  if (!example_data_value) {
603c87c5fbaSopenharmony_ci    coap_pdu_set_code(response, COAP_RESPONSE_CODE_INTERNAL_ERROR);
604c87c5fbaSopenharmony_ci    return;
605c87c5fbaSopenharmony_ci  }
606c87c5fbaSopenharmony_ci  if ((option = coap_check_option(request, COAP_OPTION_CONTENT_FORMAT,
607c87c5fbaSopenharmony_ci                                  &opt_iter)) != NULL) {
608c87c5fbaSopenharmony_ci    example_data_media_type =
609c87c5fbaSopenharmony_ci        coap_decode_var_bytes(coap_opt_value(option),
610c87c5fbaSopenharmony_ci                              coap_opt_length(option));
611c87c5fbaSopenharmony_ci  } else {
612c87c5fbaSopenharmony_ci    example_data_media_type = COAP_MEDIATYPE_TEXT_PLAIN;
613c87c5fbaSopenharmony_ci  }
614c87c5fbaSopenharmony_ci
615c87c5fbaSopenharmony_ci  coap_resource_notify_observers(resource, NULL);
616c87c5fbaSopenharmony_ci  if (echo_back) {
617c87c5fbaSopenharmony_ci    coap_binary_t body;
618c87c5fbaSopenharmony_ci
619c87c5fbaSopenharmony_ci    body = reference_resource_data(example_data_value);
620c87c5fbaSopenharmony_ci    coap_add_data_large_response(resource, session, request, response,
621c87c5fbaSopenharmony_ci                                 query, example_data_media_type, -1, 0,
622c87c5fbaSopenharmony_ci                                 body.length,
623c87c5fbaSopenharmony_ci                                 body.s,
624c87c5fbaSopenharmony_ci                                 release_resource_data, example_data_value);
625c87c5fbaSopenharmony_ci  }
626c87c5fbaSopenharmony_ci}
627c87c5fbaSopenharmony_ci
628c87c5fbaSopenharmony_ci#if SERVER_CAN_PROXY
629c87c5fbaSopenharmony_ci
630c87c5fbaSopenharmony_ci#define MAX_USER 128 /* Maximum length of a user name (i.e., PSK
631c87c5fbaSopenharmony_ci                      * identity) in bytes. */
632c87c5fbaSopenharmony_cistatic unsigned char *user = NULL;
633c87c5fbaSopenharmony_cistatic ssize_t user_length = -1;
634c87c5fbaSopenharmony_ci
635c87c5fbaSopenharmony_cistatic coap_uri_t proxy = { {0, NULL}, 0, {0, NULL}, {0, NULL}, 0 };
636c87c5fbaSopenharmony_cistatic size_t proxy_host_name_count = 0;
637c87c5fbaSopenharmony_cistatic const char **proxy_host_name_list = NULL;
638c87c5fbaSopenharmony_ci
639c87c5fbaSopenharmony_citypedef struct proxy_list_t {
640c87c5fbaSopenharmony_ci  coap_session_t *ongoing;  /* Ongoing session */
641c87c5fbaSopenharmony_ci  coap_session_t *incoming; /* Incoming session */
642c87c5fbaSopenharmony_ci  coap_binary_t *token;     /* Incoming token */
643c87c5fbaSopenharmony_ci  coap_string_t *query;     /* Incoming query */
644c87c5fbaSopenharmony_ci  coap_pdu_code_t req_code; /* Incoming request code */
645c87c5fbaSopenharmony_ci  coap_pdu_type_t req_type; /* Incoming request type */
646c87c5fbaSopenharmony_ci} proxy_list_t;
647c87c5fbaSopenharmony_ci
648c87c5fbaSopenharmony_cistatic proxy_list_t *proxy_list = NULL;
649c87c5fbaSopenharmony_cistatic size_t proxy_list_count = 0;
650c87c5fbaSopenharmony_cistatic coap_resource_t *proxy_resource = NULL;
651c87c5fbaSopenharmony_ci
652c87c5fbaSopenharmony_cistatic int
653c87c5fbaSopenharmony_ciget_uri_proxy_scheme_info(const coap_pdu_t *request,
654c87c5fbaSopenharmony_ci                          coap_opt_t *opt,
655c87c5fbaSopenharmony_ci                          coap_uri_t *uri,
656c87c5fbaSopenharmony_ci                          coap_string_t **uri_path,
657c87c5fbaSopenharmony_ci                          coap_string_t **uri_query) {
658c87c5fbaSopenharmony_ci
659c87c5fbaSopenharmony_ci  const char *opt_val = (const char *)coap_opt_value(opt);
660c87c5fbaSopenharmony_ci  int opt_len = coap_opt_length(opt);
661c87c5fbaSopenharmony_ci  coap_opt_iterator_t opt_iter;
662c87c5fbaSopenharmony_ci
663c87c5fbaSopenharmony_ci  if (opt_len == 9 &&
664c87c5fbaSopenharmony_ci      strncasecmp(opt_val, "coaps+tcp", 9) == 0) {
665c87c5fbaSopenharmony_ci    uri->scheme = COAP_URI_SCHEME_COAPS_TCP;
666c87c5fbaSopenharmony_ci    uri->port = COAPS_DEFAULT_PORT;
667c87c5fbaSopenharmony_ci  } else if (opt_len == 8 &&
668c87c5fbaSopenharmony_ci             strncasecmp(opt_val, "coap+tcp", 8) == 0) {
669c87c5fbaSopenharmony_ci    uri->scheme = COAP_URI_SCHEME_COAP_TCP;
670c87c5fbaSopenharmony_ci    uri->port = COAP_DEFAULT_PORT;
671c87c5fbaSopenharmony_ci  } else if (opt_len == 5 &&
672c87c5fbaSopenharmony_ci             strncasecmp(opt_val, "coaps", 5) == 0) {
673c87c5fbaSopenharmony_ci    uri->scheme = COAP_URI_SCHEME_COAPS;
674c87c5fbaSopenharmony_ci    uri->port = COAPS_DEFAULT_PORT;
675c87c5fbaSopenharmony_ci  } else if (opt_len == 4 &&
676c87c5fbaSopenharmony_ci             strncasecmp(opt_val, "coap", 4) == 0) {
677c87c5fbaSopenharmony_ci    uri->scheme = COAP_URI_SCHEME_COAP;
678c87c5fbaSopenharmony_ci    uri->port = COAP_DEFAULT_PORT;
679c87c5fbaSopenharmony_ci  } else {
680c87c5fbaSopenharmony_ci    coap_log_warn("Unsupported Proxy Scheme '%*.*s'\n",
681c87c5fbaSopenharmony_ci                  opt_len, opt_len, opt_val);
682c87c5fbaSopenharmony_ci    return 0;
683c87c5fbaSopenharmony_ci  }
684c87c5fbaSopenharmony_ci
685c87c5fbaSopenharmony_ci  opt = coap_check_option(request, COAP_OPTION_URI_HOST, &opt_iter);
686c87c5fbaSopenharmony_ci  if (opt) {
687c87c5fbaSopenharmony_ci    uri->host.length = coap_opt_length(opt);
688c87c5fbaSopenharmony_ci    uri->host.s = coap_opt_value(opt);
689c87c5fbaSopenharmony_ci  } else {
690c87c5fbaSopenharmony_ci    coap_log_warn("Proxy Scheme requires Uri-Host\n");
691c87c5fbaSopenharmony_ci    return 0;
692c87c5fbaSopenharmony_ci  }
693c87c5fbaSopenharmony_ci  opt = coap_check_option(request, COAP_OPTION_URI_PORT, &opt_iter);
694c87c5fbaSopenharmony_ci  if (opt) {
695c87c5fbaSopenharmony_ci    uri->port =
696c87c5fbaSopenharmony_ci        coap_decode_var_bytes(coap_opt_value(opt),
697c87c5fbaSopenharmony_ci                              coap_opt_length(opt));
698c87c5fbaSopenharmony_ci  }
699c87c5fbaSopenharmony_ci  *uri_path = coap_get_uri_path(request);
700c87c5fbaSopenharmony_ci  if (*uri_path) {
701c87c5fbaSopenharmony_ci    uri->path.s = (*uri_path)->s;
702c87c5fbaSopenharmony_ci    uri->path.length = (*uri_path)->length;
703c87c5fbaSopenharmony_ci  }
704c87c5fbaSopenharmony_ci  *uri_query = coap_get_query(request);
705c87c5fbaSopenharmony_ci  if (*uri_query) {
706c87c5fbaSopenharmony_ci    uri->query.s = (*uri_query)->s;
707c87c5fbaSopenharmony_ci    uri->query.length = (*uri_query)->length;
708c87c5fbaSopenharmony_ci  }
709c87c5fbaSopenharmony_ci  return 1;
710c87c5fbaSopenharmony_ci}
711c87c5fbaSopenharmony_ci
712c87c5fbaSopenharmony_cistatic int
713c87c5fbaSopenharmony_civerify_proxy_scheme_supported(coap_uri_scheme_t scheme) {
714c87c5fbaSopenharmony_ci
715c87c5fbaSopenharmony_ci  /* Sanity check that the connection can be forwarded on */
716c87c5fbaSopenharmony_ci  switch (scheme) {
717c87c5fbaSopenharmony_ci  case COAP_URI_SCHEME_HTTP:
718c87c5fbaSopenharmony_ci  case COAP_URI_SCHEME_HTTPS:
719c87c5fbaSopenharmony_ci    coap_log_warn("Proxy URI http or https not supported\n");
720c87c5fbaSopenharmony_ci    return 0;
721c87c5fbaSopenharmony_ci  case COAP_URI_SCHEME_COAP:
722c87c5fbaSopenharmony_ci    break;
723c87c5fbaSopenharmony_ci  case COAP_URI_SCHEME_COAPS:
724c87c5fbaSopenharmony_ci    if (!coap_dtls_is_supported()) {
725c87c5fbaSopenharmony_ci      coap_log_warn("coaps URI scheme not supported for proxy\n");
726c87c5fbaSopenharmony_ci      return 0;
727c87c5fbaSopenharmony_ci    }
728c87c5fbaSopenharmony_ci    break;
729c87c5fbaSopenharmony_ci  case COAP_URI_SCHEME_COAP_TCP:
730c87c5fbaSopenharmony_ci    if (!coap_tcp_is_supported()) {
731c87c5fbaSopenharmony_ci      coap_log_warn("coap+tcp URI scheme not supported for proxy\n");
732c87c5fbaSopenharmony_ci      return 0;
733c87c5fbaSopenharmony_ci    }
734c87c5fbaSopenharmony_ci    break;
735c87c5fbaSopenharmony_ci  case COAP_URI_SCHEME_COAPS_TCP:
736c87c5fbaSopenharmony_ci    if (!coap_tls_is_supported()) {
737c87c5fbaSopenharmony_ci      coap_log_warn("coaps+tcp URI scheme not supported for proxy\n");
738c87c5fbaSopenharmony_ci      return 0;
739c87c5fbaSopenharmony_ci    }
740c87c5fbaSopenharmony_ci    break;
741c87c5fbaSopenharmony_ci  case COAP_URI_SCHEME_COAP_WS:
742c87c5fbaSopenharmony_ci    if (!coap_ws_is_supported()) {
743c87c5fbaSopenharmony_ci      coap_log_warn("coap+ws URI scheme not supported for proxy\n");
744c87c5fbaSopenharmony_ci      return 0;
745c87c5fbaSopenharmony_ci    }
746c87c5fbaSopenharmony_ci    break;
747c87c5fbaSopenharmony_ci  case COAP_URI_SCHEME_COAPS_WS:
748c87c5fbaSopenharmony_ci    if (!coap_wss_is_supported()) {
749c87c5fbaSopenharmony_ci      coap_log_warn("coaps+ws URI scheme not supported for proxy\n");
750c87c5fbaSopenharmony_ci      return 0;
751c87c5fbaSopenharmony_ci    }
752c87c5fbaSopenharmony_ci    break;
753c87c5fbaSopenharmony_ci  case COAP_URI_SCHEME_LAST:
754c87c5fbaSopenharmony_ci  default:
755c87c5fbaSopenharmony_ci    coap_log_warn("%d URI scheme not supported\n", scheme);
756c87c5fbaSopenharmony_ci    break;
757c87c5fbaSopenharmony_ci  }
758c87c5fbaSopenharmony_ci  return 1;
759c87c5fbaSopenharmony_ci}
760c87c5fbaSopenharmony_ci
761c87c5fbaSopenharmony_cistatic coap_dtls_cpsk_t *
762c87c5fbaSopenharmony_cisetup_cpsk(char *client_sni) {
763c87c5fbaSopenharmony_ci  static coap_dtls_cpsk_t dtls_cpsk;
764c87c5fbaSopenharmony_ci
765c87c5fbaSopenharmony_ci  memset(&dtls_cpsk, 0, sizeof(dtls_cpsk));
766c87c5fbaSopenharmony_ci  dtls_cpsk.version = COAP_DTLS_CPSK_SETUP_VERSION;
767c87c5fbaSopenharmony_ci  dtls_cpsk.client_sni = client_sni;
768c87c5fbaSopenharmony_ci  dtls_cpsk.psk_info.identity.s = user;
769c87c5fbaSopenharmony_ci  dtls_cpsk.psk_info.identity.length = user_length;
770c87c5fbaSopenharmony_ci  dtls_cpsk.psk_info.key.s = key;
771c87c5fbaSopenharmony_ci  dtls_cpsk.psk_info.key.length = key_length;
772c87c5fbaSopenharmony_ci  return &dtls_cpsk;
773c87c5fbaSopenharmony_ci}
774c87c5fbaSopenharmony_ci
775c87c5fbaSopenharmony_cistatic proxy_list_t *
776c87c5fbaSopenharmony_ciget_proxy_session(coap_session_t *session, coap_pdu_t *response,
777c87c5fbaSopenharmony_ci                  const coap_bin_const_t *token, const coap_string_t *query,
778c87c5fbaSopenharmony_ci                  coap_pdu_code_t req_code, coap_pdu_type_t req_type) {
779c87c5fbaSopenharmony_ci
780c87c5fbaSopenharmony_ci  size_t i;
781c87c5fbaSopenharmony_ci  proxy_list_t *new_proxy_list;
782c87c5fbaSopenharmony_ci
783c87c5fbaSopenharmony_ci  /* Locate existing forwarding relationship */
784c87c5fbaSopenharmony_ci  for (i = 0; i < proxy_list_count; i++) {
785c87c5fbaSopenharmony_ci    if (proxy_list[i].incoming == session) {
786c87c5fbaSopenharmony_ci      return &proxy_list[i];
787c87c5fbaSopenharmony_ci    }
788c87c5fbaSopenharmony_ci  }
789c87c5fbaSopenharmony_ci
790c87c5fbaSopenharmony_ci  /* Need to create a new forwarding mapping */
791c87c5fbaSopenharmony_ci  new_proxy_list = realloc(proxy_list, (i+1)*sizeof(proxy_list[0]));
792c87c5fbaSopenharmony_ci
793c87c5fbaSopenharmony_ci  if (new_proxy_list == NULL) {
794c87c5fbaSopenharmony_ci    coap_pdu_set_code(response, COAP_RESPONSE_CODE_INTERNAL_ERROR);
795c87c5fbaSopenharmony_ci    return NULL;
796c87c5fbaSopenharmony_ci  }
797c87c5fbaSopenharmony_ci  proxy_list = new_proxy_list;
798c87c5fbaSopenharmony_ci  proxy_list[i].incoming = session;
799c87c5fbaSopenharmony_ci  if (token) {
800c87c5fbaSopenharmony_ci    proxy_list[i].token = coap_new_binary(token->length);
801c87c5fbaSopenharmony_ci    if (!proxy_list[i].token) {
802c87c5fbaSopenharmony_ci      coap_pdu_set_code(response, COAP_RESPONSE_CODE_INTERNAL_ERROR);
803c87c5fbaSopenharmony_ci      return NULL;
804c87c5fbaSopenharmony_ci    }
805c87c5fbaSopenharmony_ci    memcpy(proxy_list[i].token->s, token->s, token->length);
806c87c5fbaSopenharmony_ci  } else
807c87c5fbaSopenharmony_ci    proxy_list[i].token = NULL;
808c87c5fbaSopenharmony_ci
809c87c5fbaSopenharmony_ci  if (query) {
810c87c5fbaSopenharmony_ci    proxy_list[i].query = coap_new_string(query->length);
811c87c5fbaSopenharmony_ci    if (!proxy_list[i].query) {
812c87c5fbaSopenharmony_ci      coap_pdu_set_code(response, COAP_RESPONSE_CODE_INTERNAL_ERROR);
813c87c5fbaSopenharmony_ci      return NULL;
814c87c5fbaSopenharmony_ci    }
815c87c5fbaSopenharmony_ci    memcpy(proxy_list[i].query->s, query->s, query->length);
816c87c5fbaSopenharmony_ci  } else
817c87c5fbaSopenharmony_ci    proxy_list[i].query = NULL;
818c87c5fbaSopenharmony_ci
819c87c5fbaSopenharmony_ci  proxy_list[i].ongoing = NULL;
820c87c5fbaSopenharmony_ci  proxy_list[i].req_code = req_code;
821c87c5fbaSopenharmony_ci  proxy_list[i].req_type = req_type;
822c87c5fbaSopenharmony_ci  proxy_list_count++;
823c87c5fbaSopenharmony_ci  return &proxy_list[i];
824c87c5fbaSopenharmony_ci}
825c87c5fbaSopenharmony_ci
826c87c5fbaSopenharmony_cistatic void
827c87c5fbaSopenharmony_ciremove_proxy_association(coap_session_t *session, int send_failure) {
828c87c5fbaSopenharmony_ci
829c87c5fbaSopenharmony_ci  size_t i;
830c87c5fbaSopenharmony_ci
831c87c5fbaSopenharmony_ci  for (i = 0; i < proxy_list_count; i++) {
832c87c5fbaSopenharmony_ci    if (proxy_list[i].incoming == session) {
833c87c5fbaSopenharmony_ci      coap_session_release(proxy_list[i].ongoing);
834c87c5fbaSopenharmony_ci      break;
835c87c5fbaSopenharmony_ci    }
836c87c5fbaSopenharmony_ci    if (proxy_list[i].ongoing == session && send_failure) {
837c87c5fbaSopenharmony_ci      coap_pdu_t *response;
838c87c5fbaSopenharmony_ci
839c87c5fbaSopenharmony_ci      coap_session_release(proxy_list[i].ongoing);
840c87c5fbaSopenharmony_ci
841c87c5fbaSopenharmony_ci      /* Need to send back a gateway failure */
842c87c5fbaSopenharmony_ci      response = coap_pdu_init(proxy_list[i].req_type,
843c87c5fbaSopenharmony_ci                               COAP_RESPONSE_CODE_BAD_GATEWAY,
844c87c5fbaSopenharmony_ci                               coap_new_message_id(proxy_list[i].incoming),
845c87c5fbaSopenharmony_ci                               coap_session_max_pdu_size(proxy_list[i].incoming));
846c87c5fbaSopenharmony_ci      if (!response) {
847c87c5fbaSopenharmony_ci        coap_log_info("PDU creation issue\n");
848c87c5fbaSopenharmony_ci        return;
849c87c5fbaSopenharmony_ci      }
850c87c5fbaSopenharmony_ci
851c87c5fbaSopenharmony_ci      if (proxy_list[i].token &&
852c87c5fbaSopenharmony_ci          !coap_add_token(response, proxy_list[i].token->length,
853c87c5fbaSopenharmony_ci                          proxy_list[i].token->s)) {
854c87c5fbaSopenharmony_ci        coap_log_debug("Cannot add token to incoming proxy response PDU\n");
855c87c5fbaSopenharmony_ci      }
856c87c5fbaSopenharmony_ci
857c87c5fbaSopenharmony_ci      if (coap_send(proxy_list[i].incoming, response) ==
858c87c5fbaSopenharmony_ci          COAP_INVALID_MID) {
859c87c5fbaSopenharmony_ci        coap_log_info("Failed to send PDU with 5.02 gateway issue\n");
860c87c5fbaSopenharmony_ci      }
861c87c5fbaSopenharmony_ci      break;
862c87c5fbaSopenharmony_ci    }
863c87c5fbaSopenharmony_ci  }
864c87c5fbaSopenharmony_ci  if (i != proxy_list_count) {
865c87c5fbaSopenharmony_ci    coap_delete_binary(proxy_list[i].token);
866c87c5fbaSopenharmony_ci    coap_delete_string(proxy_list[i].query);
867c87c5fbaSopenharmony_ci    if (proxy_list_count-i > 1) {
868c87c5fbaSopenharmony_ci      memmove(&proxy_list[i],
869c87c5fbaSopenharmony_ci              &proxy_list[i+1],
870c87c5fbaSopenharmony_ci              (proxy_list_count-i-1) * sizeof(proxy_list[0]));
871c87c5fbaSopenharmony_ci    }
872c87c5fbaSopenharmony_ci    proxy_list_count--;
873c87c5fbaSopenharmony_ci  }
874c87c5fbaSopenharmony_ci}
875c87c5fbaSopenharmony_ci
876c87c5fbaSopenharmony_ci
877c87c5fbaSopenharmony_cistatic coap_session_t *
878c87c5fbaSopenharmony_ciget_ongoing_proxy_session(coap_session_t *session,
879c87c5fbaSopenharmony_ci                          coap_pdu_t *response, const coap_bin_const_t *token,
880c87c5fbaSopenharmony_ci                          const coap_string_t *query, coap_pdu_code_t req_code,
881c87c5fbaSopenharmony_ci                          coap_pdu_type_t req_type, const coap_uri_t *uri) {
882c87c5fbaSopenharmony_ci
883c87c5fbaSopenharmony_ci  coap_address_t dst;
884c87c5fbaSopenharmony_ci  coap_uri_scheme_t scheme;
885c87c5fbaSopenharmony_ci  coap_proto_t proto;
886c87c5fbaSopenharmony_ci  static char client_sni[256];
887c87c5fbaSopenharmony_ci  coap_str_const_t server;
888c87c5fbaSopenharmony_ci  uint16_t port;
889c87c5fbaSopenharmony_ci  coap_addr_info_t *info_list = NULL;
890c87c5fbaSopenharmony_ci  proxy_list_t *new_proxy_list;
891c87c5fbaSopenharmony_ci  coap_context_t *context = coap_session_get_context(session);
892c87c5fbaSopenharmony_ci
893c87c5fbaSopenharmony_ci  new_proxy_list = get_proxy_session(session, response, token, query, req_code,
894c87c5fbaSopenharmony_ci                                     req_type);
895c87c5fbaSopenharmony_ci  if (!new_proxy_list)
896c87c5fbaSopenharmony_ci    return NULL;
897c87c5fbaSopenharmony_ci
898c87c5fbaSopenharmony_ci  if (new_proxy_list->ongoing)
899c87c5fbaSopenharmony_ci    return new_proxy_list->ongoing;
900c87c5fbaSopenharmony_ci
901c87c5fbaSopenharmony_ci  if (proxy.host.length) {
902c87c5fbaSopenharmony_ci    server = proxy.host;
903c87c5fbaSopenharmony_ci    port = proxy.port;
904c87c5fbaSopenharmony_ci    scheme = proxy.scheme;
905c87c5fbaSopenharmony_ci  } else {
906c87c5fbaSopenharmony_ci    server = uri->host;
907c87c5fbaSopenharmony_ci    port = uri->port;
908c87c5fbaSopenharmony_ci    scheme = uri->scheme;
909c87c5fbaSopenharmony_ci  }
910c87c5fbaSopenharmony_ci
911c87c5fbaSopenharmony_ci  /* resolve destination address where data should be sent */
912c87c5fbaSopenharmony_ci  info_list = coap_resolve_address_info(&server, port, port, port, port,
913c87c5fbaSopenharmony_ci                                        0,
914c87c5fbaSopenharmony_ci                                        1 << scheme,
915c87c5fbaSopenharmony_ci                                        COAP_RESOLVE_TYPE_REMOTE);
916c87c5fbaSopenharmony_ci
917c87c5fbaSopenharmony_ci  if (info_list == NULL) {
918c87c5fbaSopenharmony_ci    coap_pdu_set_code(response, COAP_RESPONSE_CODE_BAD_GATEWAY);
919c87c5fbaSopenharmony_ci    remove_proxy_association(session, 0);
920c87c5fbaSopenharmony_ci    return NULL;
921c87c5fbaSopenharmony_ci  }
922c87c5fbaSopenharmony_ci  proto = info_list->proto;
923c87c5fbaSopenharmony_ci  memcpy(&dst, &info_list->addr, sizeof(dst));
924c87c5fbaSopenharmony_ci  coap_free_address_info(info_list);
925c87c5fbaSopenharmony_ci
926c87c5fbaSopenharmony_ci  switch (scheme) {
927c87c5fbaSopenharmony_ci  case COAP_URI_SCHEME_COAP:
928c87c5fbaSopenharmony_ci  case COAP_URI_SCHEME_COAP_TCP:
929c87c5fbaSopenharmony_ci  case COAP_URI_SCHEME_COAP_WS:
930c87c5fbaSopenharmony_ci    new_proxy_list->ongoing =
931c87c5fbaSopenharmony_ci        coap_new_client_session(context, NULL, &dst, proto);
932c87c5fbaSopenharmony_ci    break;
933c87c5fbaSopenharmony_ci  case COAP_URI_SCHEME_COAPS:
934c87c5fbaSopenharmony_ci  case COAP_URI_SCHEME_COAPS_TCP:
935c87c5fbaSopenharmony_ci  case COAP_URI_SCHEME_COAPS_WS:
936c87c5fbaSopenharmony_ci    memset(client_sni, 0, sizeof(client_sni));
937c87c5fbaSopenharmony_ci    if ((server.length == 3 && memcmp(server.s, "::1", 3) != 0) ||
938c87c5fbaSopenharmony_ci        (server.length == 9 && memcmp(server.s, "127.0.0.1", 9) != 0))
939c87c5fbaSopenharmony_ci      memcpy(client_sni, server.s, min(server.length, sizeof(client_sni)-1));
940c87c5fbaSopenharmony_ci    else
941c87c5fbaSopenharmony_ci      memcpy(client_sni, "localhost", 9);
942c87c5fbaSopenharmony_ci
943c87c5fbaSopenharmony_ci    if (!key_defined) {
944c87c5fbaSopenharmony_ci      /* Use our defined PKI certs (or NULL)  */
945c87c5fbaSopenharmony_ci      coap_dtls_pki_t *dtls_pki = setup_pki(context, COAP_DTLS_ROLE_CLIENT,
946c87c5fbaSopenharmony_ci                                            client_sni);
947c87c5fbaSopenharmony_ci      new_proxy_list->ongoing =
948c87c5fbaSopenharmony_ci          coap_new_client_session_pki(context, NULL, &dst, proto, dtls_pki);
949c87c5fbaSopenharmony_ci    } else {
950c87c5fbaSopenharmony_ci      /* Use our defined PSK */
951c87c5fbaSopenharmony_ci      coap_dtls_cpsk_t *dtls_cpsk = setup_cpsk(client_sni);
952c87c5fbaSopenharmony_ci
953c87c5fbaSopenharmony_ci      new_proxy_list->ongoing =
954c87c5fbaSopenharmony_ci          coap_new_client_session_psk2(context, NULL, &dst, proto, dtls_cpsk);
955c87c5fbaSopenharmony_ci    }
956c87c5fbaSopenharmony_ci    break;
957c87c5fbaSopenharmony_ci  case COAP_URI_SCHEME_HTTP:
958c87c5fbaSopenharmony_ci  case COAP_URI_SCHEME_HTTPS:
959c87c5fbaSopenharmony_ci  case COAP_URI_SCHEME_LAST:
960c87c5fbaSopenharmony_ci  default:
961c87c5fbaSopenharmony_ci    assert(0);
962c87c5fbaSopenharmony_ci    break;
963c87c5fbaSopenharmony_ci  }
964c87c5fbaSopenharmony_ci  if (new_proxy_list->ongoing == NULL) {
965c87c5fbaSopenharmony_ci    coap_pdu_set_code(response, COAP_RESPONSE_CODE_PROXYING_NOT_SUPPORTED);
966c87c5fbaSopenharmony_ci    remove_proxy_association(session, 0);
967c87c5fbaSopenharmony_ci    return NULL;
968c87c5fbaSopenharmony_ci  }
969c87c5fbaSopenharmony_ci  return new_proxy_list->ongoing;
970c87c5fbaSopenharmony_ci}
971c87c5fbaSopenharmony_ci
972c87c5fbaSopenharmony_cistatic void
973c87c5fbaSopenharmony_cirelease_proxy_body_data(coap_session_t *session COAP_UNUSED,
974c87c5fbaSopenharmony_ci                        void *app_ptr) {
975c87c5fbaSopenharmony_ci  coap_delete_binary(app_ptr);
976c87c5fbaSopenharmony_ci}
977c87c5fbaSopenharmony_ci
978c87c5fbaSopenharmony_cistatic void
979c87c5fbaSopenharmony_cihnd_proxy_uri(coap_resource_t *resource COAP_UNUSED,
980c87c5fbaSopenharmony_ci              coap_session_t *session,
981c87c5fbaSopenharmony_ci              const coap_pdu_t *request,
982c87c5fbaSopenharmony_ci              const coap_string_t *query,
983c87c5fbaSopenharmony_ci              coap_pdu_t *response) {
984c87c5fbaSopenharmony_ci  coap_opt_iterator_t opt_iter;
985c87c5fbaSopenharmony_ci  coap_opt_t *opt;
986c87c5fbaSopenharmony_ci  coap_opt_t *proxy_uri;
987c87c5fbaSopenharmony_ci  int proxy_scheme_option = 0;
988c87c5fbaSopenharmony_ci  coap_uri_t uri;
989c87c5fbaSopenharmony_ci  coap_string_t *uri_path = NULL;
990c87c5fbaSopenharmony_ci  coap_string_t *uri_query = NULL;
991c87c5fbaSopenharmony_ci  coap_session_t *ongoing = NULL;
992c87c5fbaSopenharmony_ci  size_t size;
993c87c5fbaSopenharmony_ci  size_t offset;
994c87c5fbaSopenharmony_ci  size_t total;
995c87c5fbaSopenharmony_ci  coap_binary_t *body_data = NULL;
996c87c5fbaSopenharmony_ci  const uint8_t *data;
997c87c5fbaSopenharmony_ci  coap_pdu_t *pdu;
998c87c5fbaSopenharmony_ci  coap_optlist_t *optlist = NULL;
999c87c5fbaSopenharmony_ci  coap_opt_t *option;
1000c87c5fbaSopenharmony_ci#define BUFSIZE 100
1001c87c5fbaSopenharmony_ci  unsigned char buf[BUFSIZE];
1002c87c5fbaSopenharmony_ci  coap_bin_const_t token = coap_pdu_get_token(request);
1003c87c5fbaSopenharmony_ci
1004c87c5fbaSopenharmony_ci  memset(&uri, 0, sizeof(uri));
1005c87c5fbaSopenharmony_ci  /*
1006c87c5fbaSopenharmony_ci   * See if Proxy-Scheme
1007c87c5fbaSopenharmony_ci   */
1008c87c5fbaSopenharmony_ci  opt = coap_check_option(request, COAP_OPTION_PROXY_SCHEME, &opt_iter);
1009c87c5fbaSopenharmony_ci  if (opt) {
1010c87c5fbaSopenharmony_ci    if (!get_uri_proxy_scheme_info(request, opt, &uri, &uri_path,
1011c87c5fbaSopenharmony_ci                                   &uri_query)) {
1012c87c5fbaSopenharmony_ci      coap_pdu_set_code(response,
1013c87c5fbaSopenharmony_ci                        COAP_RESPONSE_CODE_PROXYING_NOT_SUPPORTED);
1014c87c5fbaSopenharmony_ci      goto cleanup;
1015c87c5fbaSopenharmony_ci    }
1016c87c5fbaSopenharmony_ci    proxy_scheme_option = 1;
1017c87c5fbaSopenharmony_ci  }
1018c87c5fbaSopenharmony_ci  /*
1019c87c5fbaSopenharmony_ci   * See if Proxy-Uri
1020c87c5fbaSopenharmony_ci   */
1021c87c5fbaSopenharmony_ci  proxy_uri = coap_check_option(request, COAP_OPTION_PROXY_URI, &opt_iter);
1022c87c5fbaSopenharmony_ci  if (proxy_uri) {
1023c87c5fbaSopenharmony_ci    coap_log_info("Proxy URI '%.*s'\n",
1024c87c5fbaSopenharmony_ci                  coap_opt_length(proxy_uri),
1025c87c5fbaSopenharmony_ci                  (const char *)coap_opt_value(proxy_uri));
1026c87c5fbaSopenharmony_ci    if (coap_split_proxy_uri(coap_opt_value(proxy_uri),
1027c87c5fbaSopenharmony_ci                             coap_opt_length(proxy_uri),
1028c87c5fbaSopenharmony_ci                             &uri) < 0) {
1029c87c5fbaSopenharmony_ci      /* Need to return a 5.05 RFC7252 Section 5.7.2 */
1030c87c5fbaSopenharmony_ci      coap_log_warn("Proxy URI not decodable\n");
1031c87c5fbaSopenharmony_ci      coap_pdu_set_code(response,
1032c87c5fbaSopenharmony_ci                        COAP_RESPONSE_CODE_PROXYING_NOT_SUPPORTED);
1033c87c5fbaSopenharmony_ci      goto cleanup;
1034c87c5fbaSopenharmony_ci    }
1035c87c5fbaSopenharmony_ci  }
1036c87c5fbaSopenharmony_ci
1037c87c5fbaSopenharmony_ci  if (!(proxy_scheme_option || proxy_uri)) {
1038c87c5fbaSopenharmony_ci    coap_pdu_set_code(response, COAP_RESPONSE_CODE_NOT_FOUND);
1039c87c5fbaSopenharmony_ci    goto cleanup;
1040c87c5fbaSopenharmony_ci  }
1041c87c5fbaSopenharmony_ci
1042c87c5fbaSopenharmony_ci  if (uri.host.length == 0) {
1043c87c5fbaSopenharmony_ci    /* Ongoing connection not well formed */
1044c87c5fbaSopenharmony_ci    coap_pdu_set_code(response, COAP_RESPONSE_CODE_PROXYING_NOT_SUPPORTED);
1045c87c5fbaSopenharmony_ci    goto cleanup;
1046c87c5fbaSopenharmony_ci  }
1047c87c5fbaSopenharmony_ci
1048c87c5fbaSopenharmony_ci  if (!verify_proxy_scheme_supported(uri.scheme)) {
1049c87c5fbaSopenharmony_ci    coap_pdu_set_code(response, COAP_RESPONSE_CODE_PROXYING_NOT_SUPPORTED);
1050c87c5fbaSopenharmony_ci    goto cleanup;
1051c87c5fbaSopenharmony_ci  }
1052c87c5fbaSopenharmony_ci
1053c87c5fbaSopenharmony_ci  /* Handle the CoAP forwarding mapping */
1054c87c5fbaSopenharmony_ci  if (uri.scheme == COAP_URI_SCHEME_COAP ||
1055c87c5fbaSopenharmony_ci      uri.scheme == COAP_URI_SCHEME_COAPS ||
1056c87c5fbaSopenharmony_ci      uri.scheme == COAP_URI_SCHEME_COAP_TCP ||
1057c87c5fbaSopenharmony_ci      uri.scheme == COAP_URI_SCHEME_COAPS_TCP) {
1058c87c5fbaSopenharmony_ci    coap_pdu_code_t req_code = coap_pdu_get_code(request);
1059c87c5fbaSopenharmony_ci    coap_pdu_type_t req_type = coap_pdu_get_type(request);
1060c87c5fbaSopenharmony_ci
1061c87c5fbaSopenharmony_ci    if (!get_proxy_session(session, response, &token, query, req_code, req_type))
1062c87c5fbaSopenharmony_ci      goto cleanup;
1063c87c5fbaSopenharmony_ci
1064c87c5fbaSopenharmony_ci    if (coap_get_data_large(request, &size, &data, &offset, &total)) {
1065c87c5fbaSopenharmony_ci      /* COAP_BLOCK_SINGLE_BODY is set, so single body should be given */
1066c87c5fbaSopenharmony_ci      assert(size == total);
1067c87c5fbaSopenharmony_ci      body_data = coap_new_binary(total);
1068c87c5fbaSopenharmony_ci      if (!body_data) {
1069c87c5fbaSopenharmony_ci        coap_log_debug("body build memory error\n");
1070c87c5fbaSopenharmony_ci        goto cleanup;
1071c87c5fbaSopenharmony_ci      }
1072c87c5fbaSopenharmony_ci      memcpy(body_data->s, data, size);
1073c87c5fbaSopenharmony_ci      data = body_data->s;
1074c87c5fbaSopenharmony_ci    }
1075c87c5fbaSopenharmony_ci
1076c87c5fbaSopenharmony_ci    /* Send data on (opening session if appropriate) */
1077c87c5fbaSopenharmony_ci
1078c87c5fbaSopenharmony_ci    ongoing = get_ongoing_proxy_session(session, response, &token,
1079c87c5fbaSopenharmony_ci                                        query, req_code, req_type, &uri);
1080c87c5fbaSopenharmony_ci    if (!ongoing)
1081c87c5fbaSopenharmony_ci      goto cleanup;
1082c87c5fbaSopenharmony_ci    /*
1083c87c5fbaSopenharmony_ci     * Build up the ongoing PDU that we are going to send
1084c87c5fbaSopenharmony_ci     */
1085c87c5fbaSopenharmony_ci    pdu = coap_pdu_init(req_type, req_code,
1086c87c5fbaSopenharmony_ci                        coap_new_message_id(ongoing),
1087c87c5fbaSopenharmony_ci                        coap_session_max_pdu_size(ongoing));
1088c87c5fbaSopenharmony_ci    if (!pdu) {
1089c87c5fbaSopenharmony_ci      coap_pdu_set_code(response, COAP_RESPONSE_CODE_INTERNAL_ERROR);
1090c87c5fbaSopenharmony_ci      goto cleanup;
1091c87c5fbaSopenharmony_ci    }
1092c87c5fbaSopenharmony_ci
1093c87c5fbaSopenharmony_ci    if (!coap_add_token(pdu, token.length, token.s)) {
1094c87c5fbaSopenharmony_ci      coap_log_debug("cannot add token to proxy request\n");
1095c87c5fbaSopenharmony_ci      coap_pdu_set_code(response, COAP_RESPONSE_CODE_INTERNAL_ERROR);
1096c87c5fbaSopenharmony_ci      coap_delete_pdu(pdu);
1097c87c5fbaSopenharmony_ci      goto cleanup;
1098c87c5fbaSopenharmony_ci    }
1099c87c5fbaSopenharmony_ci
1100c87c5fbaSopenharmony_ci    if (proxy.host.length == 0) {
1101c87c5fbaSopenharmony_ci      /* Use  Uri-Path and Uri-Query - direct session */
1102c87c5fbaSopenharmony_ci      proxy_uri = NULL;
1103c87c5fbaSopenharmony_ci      proxy_scheme_option = 0;
1104c87c5fbaSopenharmony_ci      const coap_address_t *dst = coap_session_get_addr_remote(ongoing);
1105c87c5fbaSopenharmony_ci
1106c87c5fbaSopenharmony_ci      if (coap_uri_into_options(&uri, dst, &optlist, 1,
1107c87c5fbaSopenharmony_ci                                buf, sizeof(buf)) < 0) {
1108c87c5fbaSopenharmony_ci        coap_log_err("Failed to create options for URI\n");
1109c87c5fbaSopenharmony_ci        goto cleanup;
1110c87c5fbaSopenharmony_ci      }
1111c87c5fbaSopenharmony_ci    }
1112c87c5fbaSopenharmony_ci
1113c87c5fbaSopenharmony_ci    /* Copy the remaining options across */
1114c87c5fbaSopenharmony_ci    coap_option_iterator_init(request, &opt_iter, COAP_OPT_ALL);
1115c87c5fbaSopenharmony_ci    while ((option = coap_option_next(&opt_iter))) {
1116c87c5fbaSopenharmony_ci      switch (opt_iter.number) {
1117c87c5fbaSopenharmony_ci      case COAP_OPTION_PROXY_URI:
1118c87c5fbaSopenharmony_ci        if (proxy_uri) {
1119c87c5fbaSopenharmony_ci          /* Need to add back in */
1120c87c5fbaSopenharmony_ci          goto add_in;
1121c87c5fbaSopenharmony_ci        }
1122c87c5fbaSopenharmony_ci        break;
1123c87c5fbaSopenharmony_ci      case COAP_OPTION_PROXY_SCHEME:
1124c87c5fbaSopenharmony_ci      case COAP_OPTION_URI_PATH:
1125c87c5fbaSopenharmony_ci      case COAP_OPTION_URI_PORT:
1126c87c5fbaSopenharmony_ci      case COAP_OPTION_URI_QUERY:
1127c87c5fbaSopenharmony_ci        if (proxy_scheme_option) {
1128c87c5fbaSopenharmony_ci          /* Need to add back in */
1129c87c5fbaSopenharmony_ci          goto add_in;
1130c87c5fbaSopenharmony_ci        }
1131c87c5fbaSopenharmony_ci        break;
1132c87c5fbaSopenharmony_ci      case COAP_OPTION_BLOCK1:
1133c87c5fbaSopenharmony_ci      case COAP_OPTION_BLOCK2:
1134c87c5fbaSopenharmony_ci      case COAP_OPTION_Q_BLOCK1:
1135c87c5fbaSopenharmony_ci      case COAP_OPTION_Q_BLOCK2:
1136c87c5fbaSopenharmony_ci        /* These are not passed on */
1137c87c5fbaSopenharmony_ci        break;
1138c87c5fbaSopenharmony_ci      default:
1139c87c5fbaSopenharmony_ciadd_in:
1140c87c5fbaSopenharmony_ci        coap_insert_optlist(&optlist,
1141c87c5fbaSopenharmony_ci                            coap_new_optlist(opt_iter.number,
1142c87c5fbaSopenharmony_ci                                             coap_opt_length(option),
1143c87c5fbaSopenharmony_ci                                             coap_opt_value(option)));
1144c87c5fbaSopenharmony_ci        break;
1145c87c5fbaSopenharmony_ci      }
1146c87c5fbaSopenharmony_ci    }
1147c87c5fbaSopenharmony_ci
1148c87c5fbaSopenharmony_ci    /* Update pdu with options */
1149c87c5fbaSopenharmony_ci    coap_add_optlist_pdu(pdu, &optlist);
1150c87c5fbaSopenharmony_ci    coap_delete_optlist(optlist);
1151c87c5fbaSopenharmony_ci
1152c87c5fbaSopenharmony_ci    if (size) {
1153c87c5fbaSopenharmony_ci      if (!coap_add_data_large_request(ongoing, pdu, size, data,
1154c87c5fbaSopenharmony_ci                                       release_proxy_body_data, body_data)) {
1155c87c5fbaSopenharmony_ci        coap_log_debug("cannot add data to proxy request\n");
1156c87c5fbaSopenharmony_ci      } else {
1157c87c5fbaSopenharmony_ci        body_data = NULL;
1158c87c5fbaSopenharmony_ci      }
1159c87c5fbaSopenharmony_ci    }
1160c87c5fbaSopenharmony_ci
1161c87c5fbaSopenharmony_ci    if (coap_get_log_level() < COAP_LOG_DEBUG)
1162c87c5fbaSopenharmony_ci      coap_show_pdu(COAP_LOG_INFO, pdu);
1163c87c5fbaSopenharmony_ci
1164c87c5fbaSopenharmony_ci    coap_send(ongoing, pdu);
1165c87c5fbaSopenharmony_ci    /*
1166c87c5fbaSopenharmony_ci     * Do not update with response code (hence empty ACK) as will be sending
1167c87c5fbaSopenharmony_ci     * separate response when response comes back from upstream server
1168c87c5fbaSopenharmony_ci     */
1169c87c5fbaSopenharmony_ci    goto cleanup;
1170c87c5fbaSopenharmony_ci  } else {
1171c87c5fbaSopenharmony_ci    /* TODO http & https */
1172c87c5fbaSopenharmony_ci    coap_log_err("Proxy-Uri scheme %d unknown\n", uri.scheme);
1173c87c5fbaSopenharmony_ci  }
1174c87c5fbaSopenharmony_cicleanup:
1175c87c5fbaSopenharmony_ci  coap_delete_string(uri_path);
1176c87c5fbaSopenharmony_ci  coap_delete_string(uri_query);
1177c87c5fbaSopenharmony_ci  coap_delete_binary(body_data);
1178c87c5fbaSopenharmony_ci}
1179c87c5fbaSopenharmony_ci
1180c87c5fbaSopenharmony_ci#endif /* SERVER_CAN_PROXY */
1181c87c5fbaSopenharmony_ci
1182c87c5fbaSopenharmony_citypedef struct dynamic_resource_t {
1183c87c5fbaSopenharmony_ci  coap_string_t *uri_path;
1184c87c5fbaSopenharmony_ci  transient_value_t *value;
1185c87c5fbaSopenharmony_ci  coap_resource_t *resource;
1186c87c5fbaSopenharmony_ci  int created;
1187c87c5fbaSopenharmony_ci  uint16_t media_type;
1188c87c5fbaSopenharmony_ci} dynamic_resource_t;
1189c87c5fbaSopenharmony_ci
1190c87c5fbaSopenharmony_cistatic int dynamic_count = 0;
1191c87c5fbaSopenharmony_cistatic dynamic_resource_t *dynamic_entry = NULL;
1192c87c5fbaSopenharmony_ci
1193c87c5fbaSopenharmony_ci/*
1194c87c5fbaSopenharmony_ci * Regular DELETE handler - used by resources created by the
1195c87c5fbaSopenharmony_ci * Unknown Resource PUT handler
1196c87c5fbaSopenharmony_ci */
1197c87c5fbaSopenharmony_ci
1198c87c5fbaSopenharmony_cistatic void
1199c87c5fbaSopenharmony_cihnd_delete(coap_resource_t *resource,
1200c87c5fbaSopenharmony_ci           coap_session_t *session COAP_UNUSED,
1201c87c5fbaSopenharmony_ci           const coap_pdu_t *request,
1202c87c5fbaSopenharmony_ci           const coap_string_t *query COAP_UNUSED,
1203c87c5fbaSopenharmony_ci           coap_pdu_t *response) {
1204c87c5fbaSopenharmony_ci  int i;
1205c87c5fbaSopenharmony_ci  coap_string_t *uri_path;
1206c87c5fbaSopenharmony_ci
1207c87c5fbaSopenharmony_ci  /* get the uri_path */
1208c87c5fbaSopenharmony_ci  uri_path = coap_get_uri_path(request);
1209c87c5fbaSopenharmony_ci  if (!uri_path) {
1210c87c5fbaSopenharmony_ci    coap_pdu_set_code(response, COAP_RESPONSE_CODE_NOT_FOUND);
1211c87c5fbaSopenharmony_ci    return;
1212c87c5fbaSopenharmony_ci  }
1213c87c5fbaSopenharmony_ci
1214c87c5fbaSopenharmony_ci  for (i = 0; i < dynamic_count; i++) {
1215c87c5fbaSopenharmony_ci    if (coap_string_equal(uri_path, dynamic_entry[i].uri_path)) {
1216c87c5fbaSopenharmony_ci      /* Dynamic entry no longer required - delete it */
1217c87c5fbaSopenharmony_ci      release_resource_data(session, dynamic_entry[i].value);
1218c87c5fbaSopenharmony_ci      coap_delete_string(dynamic_entry[i].uri_path);
1219c87c5fbaSopenharmony_ci      if (dynamic_count-i > 1) {
1220c87c5fbaSopenharmony_ci        memmove(&dynamic_entry[i],
1221c87c5fbaSopenharmony_ci                &dynamic_entry[i+1],
1222c87c5fbaSopenharmony_ci                (dynamic_count-i-1) * sizeof(dynamic_entry[0]));
1223c87c5fbaSopenharmony_ci      }
1224c87c5fbaSopenharmony_ci      dynamic_count--;
1225c87c5fbaSopenharmony_ci      break;
1226c87c5fbaSopenharmony_ci    }
1227c87c5fbaSopenharmony_ci  }
1228c87c5fbaSopenharmony_ci
1229c87c5fbaSopenharmony_ci  /* Dynamic resource no longer required - delete it */
1230c87c5fbaSopenharmony_ci  coap_delete_resource(NULL, resource);
1231c87c5fbaSopenharmony_ci  coap_delete_string(uri_path);
1232c87c5fbaSopenharmony_ci  coap_pdu_set_code(response, COAP_RESPONSE_CODE_DELETED);
1233c87c5fbaSopenharmony_ci}
1234c87c5fbaSopenharmony_ci
1235c87c5fbaSopenharmony_ci/*
1236c87c5fbaSopenharmony_ci * Regular GET handler - used by resources created by the
1237c87c5fbaSopenharmony_ci * Unknown Resource PUT handler
1238c87c5fbaSopenharmony_ci */
1239c87c5fbaSopenharmony_ci
1240c87c5fbaSopenharmony_cistatic void
1241c87c5fbaSopenharmony_cihnd_get(coap_resource_t *resource,
1242c87c5fbaSopenharmony_ci        coap_session_t *session,
1243c87c5fbaSopenharmony_ci        const coap_pdu_t *request,
1244c87c5fbaSopenharmony_ci        const coap_string_t *query,
1245c87c5fbaSopenharmony_ci        coap_pdu_t *response) {
1246c87c5fbaSopenharmony_ci  coap_str_const_t *uri_path;
1247c87c5fbaSopenharmony_ci  int i;
1248c87c5fbaSopenharmony_ci  dynamic_resource_t *resource_entry = NULL;
1249c87c5fbaSopenharmony_ci  coap_binary_t body;
1250c87c5fbaSopenharmony_ci  /*
1251c87c5fbaSopenharmony_ci   * request will be NULL if an Observe triggered request, so the uri_path,
1252c87c5fbaSopenharmony_ci   * if needed, must be abstracted from the resource.
1253c87c5fbaSopenharmony_ci   * The uri_path string is a const pointer
1254c87c5fbaSopenharmony_ci   */
1255c87c5fbaSopenharmony_ci
1256c87c5fbaSopenharmony_ci  uri_path = coap_resource_get_uri_path(resource);
1257c87c5fbaSopenharmony_ci  if (!uri_path) {
1258c87c5fbaSopenharmony_ci    coap_pdu_set_code(response, COAP_RESPONSE_CODE_NOT_FOUND);
1259c87c5fbaSopenharmony_ci    return;
1260c87c5fbaSopenharmony_ci  }
1261c87c5fbaSopenharmony_ci
1262c87c5fbaSopenharmony_ci  for (i = 0; i < dynamic_count; i++) {
1263c87c5fbaSopenharmony_ci    if (coap_string_equal(uri_path, dynamic_entry[i].uri_path)) {
1264c87c5fbaSopenharmony_ci      break;
1265c87c5fbaSopenharmony_ci    }
1266c87c5fbaSopenharmony_ci  }
1267c87c5fbaSopenharmony_ci  if (i == dynamic_count) {
1268c87c5fbaSopenharmony_ci    coap_pdu_set_code(response, COAP_RESPONSE_CODE_NOT_FOUND);
1269c87c5fbaSopenharmony_ci    return;
1270c87c5fbaSopenharmony_ci  }
1271c87c5fbaSopenharmony_ci
1272c87c5fbaSopenharmony_ci  resource_entry = &dynamic_entry[i];
1273c87c5fbaSopenharmony_ci
1274c87c5fbaSopenharmony_ci  coap_pdu_set_code(response, COAP_RESPONSE_CODE_CONTENT);
1275c87c5fbaSopenharmony_ci  body = reference_resource_data(resource_entry->value);
1276c87c5fbaSopenharmony_ci  coap_add_data_large_response(resource, session, request, response,
1277c87c5fbaSopenharmony_ci                               query, resource_entry->media_type, -1, 0,
1278c87c5fbaSopenharmony_ci                               body.length,
1279c87c5fbaSopenharmony_ci                               body.s,
1280c87c5fbaSopenharmony_ci                               release_resource_data, resource_entry->value);
1281c87c5fbaSopenharmony_ci}
1282c87c5fbaSopenharmony_ci
1283c87c5fbaSopenharmony_ci/*
1284c87c5fbaSopenharmony_ci * Regular PUT or POST handler - used by resources created by the
1285c87c5fbaSopenharmony_ci * Unknown Resource PUT/POST handler
1286c87c5fbaSopenharmony_ci */
1287c87c5fbaSopenharmony_ci
1288c87c5fbaSopenharmony_cistatic void
1289c87c5fbaSopenharmony_cihnd_put_post(coap_resource_t *resource,
1290c87c5fbaSopenharmony_ci             coap_session_t *session,
1291c87c5fbaSopenharmony_ci             const coap_pdu_t *request,
1292c87c5fbaSopenharmony_ci             const coap_string_t *query COAP_UNUSED,
1293c87c5fbaSopenharmony_ci             coap_pdu_t *response) {
1294c87c5fbaSopenharmony_ci  coap_string_t *uri_path;
1295c87c5fbaSopenharmony_ci  int i;
1296c87c5fbaSopenharmony_ci  size_t size;
1297c87c5fbaSopenharmony_ci  const uint8_t *data;
1298c87c5fbaSopenharmony_ci  size_t offset;
1299c87c5fbaSopenharmony_ci  size_t total;
1300c87c5fbaSopenharmony_ci  dynamic_resource_t *resource_entry = NULL;
1301c87c5fbaSopenharmony_ci  unsigned char buf[6];      /* space to hold encoded/decoded uints */
1302c87c5fbaSopenharmony_ci  coap_opt_iterator_t opt_iter;
1303c87c5fbaSopenharmony_ci  coap_opt_t *option;
1304c87c5fbaSopenharmony_ci  coap_binary_t *data_so_far;
1305c87c5fbaSopenharmony_ci  transient_value_t *transient_value;
1306c87c5fbaSopenharmony_ci
1307c87c5fbaSopenharmony_ci  /* get the uri_path */
1308c87c5fbaSopenharmony_ci  uri_path = coap_get_uri_path(request);
1309c87c5fbaSopenharmony_ci  if (!uri_path) {
1310c87c5fbaSopenharmony_ci    coap_pdu_set_code(response, COAP_RESPONSE_CODE_NOT_FOUND);
1311c87c5fbaSopenharmony_ci    return;
1312c87c5fbaSopenharmony_ci  }
1313c87c5fbaSopenharmony_ci
1314c87c5fbaSopenharmony_ci  /*
1315c87c5fbaSopenharmony_ci   * Locate the correct dynamic block for this request
1316c87c5fbaSopenharmony_ci   */
1317c87c5fbaSopenharmony_ci  for (i = 0; i < dynamic_count; i++) {
1318c87c5fbaSopenharmony_ci    if (coap_string_equal(uri_path, dynamic_entry[i].uri_path)) {
1319c87c5fbaSopenharmony_ci      break;
1320c87c5fbaSopenharmony_ci    }
1321c87c5fbaSopenharmony_ci  }
1322c87c5fbaSopenharmony_ci  if (i == dynamic_count) {
1323c87c5fbaSopenharmony_ci    if (dynamic_count >= support_dynamic) {
1324c87c5fbaSopenharmony_ci      /* Should have been caught hnd_put_post_unknown() */
1325c87c5fbaSopenharmony_ci      coap_pdu_set_code(response, COAP_RESPONSE_CODE_NOT_ACCEPTABLE);
1326c87c5fbaSopenharmony_ci      coap_delete_string(uri_path);
1327c87c5fbaSopenharmony_ci      return;
1328c87c5fbaSopenharmony_ci    }
1329c87c5fbaSopenharmony_ci    dynamic_count++;
1330c87c5fbaSopenharmony_ci    dynamic_entry = realloc(dynamic_entry,
1331c87c5fbaSopenharmony_ci                            dynamic_count * sizeof(dynamic_entry[0]));
1332c87c5fbaSopenharmony_ci    if (dynamic_entry) {
1333c87c5fbaSopenharmony_ci      dynamic_entry[i].uri_path = uri_path;
1334c87c5fbaSopenharmony_ci      dynamic_entry[i].value = NULL;
1335c87c5fbaSopenharmony_ci      dynamic_entry[i].resource = resource;
1336c87c5fbaSopenharmony_ci      dynamic_entry[i].created = 1;
1337c87c5fbaSopenharmony_ci      if ((option = coap_check_option(request, COAP_OPTION_CONTENT_FORMAT,
1338c87c5fbaSopenharmony_ci                                      &opt_iter)) != NULL) {
1339c87c5fbaSopenharmony_ci        dynamic_entry[i].media_type =
1340c87c5fbaSopenharmony_ci            coap_decode_var_bytes(coap_opt_value(option),
1341c87c5fbaSopenharmony_ci                                  coap_opt_length(option));
1342c87c5fbaSopenharmony_ci      } else {
1343c87c5fbaSopenharmony_ci        dynamic_entry[i].media_type = COAP_MEDIATYPE_TEXT_PLAIN;
1344c87c5fbaSopenharmony_ci      }
1345c87c5fbaSopenharmony_ci      /* Store media type of new resource in ct. We can use buf here
1346c87c5fbaSopenharmony_ci       * as coap_add_attr() will copy the passed string. */
1347c87c5fbaSopenharmony_ci      memset(buf, 0, sizeof(buf));
1348c87c5fbaSopenharmony_ci      snprintf((char *)buf, sizeof(buf), "%d", dynamic_entry[i].media_type);
1349c87c5fbaSopenharmony_ci      /* ensure that buf is always zero-terminated */
1350c87c5fbaSopenharmony_ci      assert(buf[sizeof(buf) - 1] == '\0');
1351c87c5fbaSopenharmony_ci      buf[sizeof(buf) - 1] = '\0';
1352c87c5fbaSopenharmony_ci      coap_add_attr(resource,
1353c87c5fbaSopenharmony_ci                    coap_make_str_const("ct"),
1354c87c5fbaSopenharmony_ci                    coap_make_str_const((char *)buf),
1355c87c5fbaSopenharmony_ci                    0);
1356c87c5fbaSopenharmony_ci    } else {
1357c87c5fbaSopenharmony_ci      dynamic_count--;
1358c87c5fbaSopenharmony_ci      coap_pdu_set_code(response, COAP_RESPONSE_CODE_INTERNAL_ERROR);
1359c87c5fbaSopenharmony_ci      coap_delete_string(uri_path);
1360c87c5fbaSopenharmony_ci      return;
1361c87c5fbaSopenharmony_ci    }
1362c87c5fbaSopenharmony_ci  } else {
1363c87c5fbaSopenharmony_ci    /* Need to do this as coap_get_uri_path() created it */
1364c87c5fbaSopenharmony_ci    coap_delete_string(uri_path);
1365c87c5fbaSopenharmony_ci  }
1366c87c5fbaSopenharmony_ci
1367c87c5fbaSopenharmony_ci  resource_entry = &dynamic_entry[i];
1368c87c5fbaSopenharmony_ci
1369c87c5fbaSopenharmony_ci  if (coap_get_data_large(request, &size, &data, &offset, &total) &&
1370c87c5fbaSopenharmony_ci      size != total) {
1371c87c5fbaSopenharmony_ci    /*
1372c87c5fbaSopenharmony_ci     * A part of the data has been received (COAP_BLOCK_SINGLE_BODY not set).
1373c87c5fbaSopenharmony_ci     * However, total unfortunately is only an indication, so it is not safe to
1374c87c5fbaSopenharmony_ci     * allocate a block based on total.  As per
1375c87c5fbaSopenharmony_ci     * https://rfc-editor.org/rfc/rfc7959#section-4
1376c87c5fbaSopenharmony_ci     *   o  In a request carrying a Block1 Option, to indicate the current
1377c87c5fbaSopenharmony_ci     *         estimate the client has of the total size of the resource
1378c87c5fbaSopenharmony_ci     *         representation, measured in bytes ("size indication").
1379c87c5fbaSopenharmony_ci     *
1380c87c5fbaSopenharmony_ci     * coap_cache_ignore_options() must have previously been called with at
1381c87c5fbaSopenharmony_ci     * least COAP_OPTION_BLOCK1 set as the option value will change per block.
1382c87c5fbaSopenharmony_ci     */
1383c87c5fbaSopenharmony_ci    coap_cache_entry_t *cache_entry = coap_cache_get_by_pdu(session,
1384c87c5fbaSopenharmony_ci                                                            request,
1385c87c5fbaSopenharmony_ci                                                            COAP_CACHE_IS_SESSION_BASED);
1386c87c5fbaSopenharmony_ci
1387c87c5fbaSopenharmony_ci    if (offset == 0) {
1388c87c5fbaSopenharmony_ci      if (!cache_entry) {
1389c87c5fbaSopenharmony_ci        cache_entry = coap_new_cache_entry(session, request,
1390c87c5fbaSopenharmony_ci                                           COAP_CACHE_NOT_RECORD_PDU,
1391c87c5fbaSopenharmony_ci                                           COAP_CACHE_IS_SESSION_BASED, 0);
1392c87c5fbaSopenharmony_ci      } else {
1393c87c5fbaSopenharmony_ci        data_so_far = coap_cache_get_app_data(cache_entry);
1394c87c5fbaSopenharmony_ci        if (data_so_far) {
1395c87c5fbaSopenharmony_ci          coap_delete_binary(data_so_far);
1396c87c5fbaSopenharmony_ci          data_so_far = NULL;
1397c87c5fbaSopenharmony_ci        }
1398c87c5fbaSopenharmony_ci        coap_cache_set_app_data(cache_entry, NULL, NULL);
1399c87c5fbaSopenharmony_ci      }
1400c87c5fbaSopenharmony_ci    }
1401c87c5fbaSopenharmony_ci    if (!cache_entry) {
1402c87c5fbaSopenharmony_ci      if (offset == 0) {
1403c87c5fbaSopenharmony_ci        coap_log_warn("Unable to create a new cache entry\n");
1404c87c5fbaSopenharmony_ci      } else {
1405c87c5fbaSopenharmony_ci        coap_log_warn("No cache entry available for the non-first BLOCK\n");
1406c87c5fbaSopenharmony_ci      }
1407c87c5fbaSopenharmony_ci      coap_pdu_set_code(response, COAP_RESPONSE_CODE_INTERNAL_ERROR);
1408c87c5fbaSopenharmony_ci      return;
1409c87c5fbaSopenharmony_ci    }
1410c87c5fbaSopenharmony_ci
1411c87c5fbaSopenharmony_ci    if (size) {
1412c87c5fbaSopenharmony_ci      /* Add in the new data to cache entry */
1413c87c5fbaSopenharmony_ci      data_so_far = coap_cache_get_app_data(cache_entry);
1414c87c5fbaSopenharmony_ci      if (!data_so_far) {
1415c87c5fbaSopenharmony_ci        data_so_far = coap_new_binary(size);
1416c87c5fbaSopenharmony_ci        if (data_so_far)
1417c87c5fbaSopenharmony_ci          memcpy(data_so_far->s, data, size);
1418c87c5fbaSopenharmony_ci      } else {
1419c87c5fbaSopenharmony_ci        /* Add in new block to end of current data */
1420c87c5fbaSopenharmony_ci        coap_binary_t *new = coap_resize_binary(data_so_far, offset + size);
1421c87c5fbaSopenharmony_ci
1422c87c5fbaSopenharmony_ci        if (new) {
1423c87c5fbaSopenharmony_ci          data_so_far = new;
1424c87c5fbaSopenharmony_ci          memcpy(&data_so_far->s[offset], data, size);
1425c87c5fbaSopenharmony_ci        } else {
1426c87c5fbaSopenharmony_ci          /* Insufficient space to extend data_so_far */
1427c87c5fbaSopenharmony_ci          coap_delete_binary(data_so_far);
1428c87c5fbaSopenharmony_ci          data_so_far = NULL;
1429c87c5fbaSopenharmony_ci        }
1430c87c5fbaSopenharmony_ci      }
1431c87c5fbaSopenharmony_ci      /* Yes, data_so_far can be NULL */
1432c87c5fbaSopenharmony_ci      coap_cache_set_app_data(cache_entry, data_so_far, cache_free_app_data);
1433c87c5fbaSopenharmony_ci    }
1434c87c5fbaSopenharmony_ci    if (offset + size == total) {
1435c87c5fbaSopenharmony_ci      /* All the data is now in */
1436c87c5fbaSopenharmony_ci      data_so_far = coap_cache_get_app_data(cache_entry);
1437c87c5fbaSopenharmony_ci      coap_cache_set_app_data(cache_entry, NULL, NULL);
1438c87c5fbaSopenharmony_ci    } else {
1439c87c5fbaSopenharmony_ci      coap_pdu_set_code(response, COAP_RESPONSE_CODE_CONTINUE);
1440c87c5fbaSopenharmony_ci      return;
1441c87c5fbaSopenharmony_ci    }
1442c87c5fbaSopenharmony_ci  } else {
1443c87c5fbaSopenharmony_ci    /* single body of data received */
1444c87c5fbaSopenharmony_ci    data_so_far = coap_new_binary(size);
1445c87c5fbaSopenharmony_ci    if (data_so_far && size) {
1446c87c5fbaSopenharmony_ci      memcpy(data_so_far->s, data, size);
1447c87c5fbaSopenharmony_ci    }
1448c87c5fbaSopenharmony_ci  }
1449c87c5fbaSopenharmony_ci  /* Need to de-reference as value may be in use elsewhere */
1450c87c5fbaSopenharmony_ci  release_resource_data(session, resource_entry->value);
1451c87c5fbaSopenharmony_ci  resource_entry->value = NULL;
1452c87c5fbaSopenharmony_ci  transient_value = alloc_resource_data(data_so_far);
1453c87c5fbaSopenharmony_ci  if (!transient_value) {
1454c87c5fbaSopenharmony_ci    coap_pdu_set_code(response, COAP_RESPONSE_CODE_INTERNAL_ERROR);
1455c87c5fbaSopenharmony_ci    return;
1456c87c5fbaSopenharmony_ci  }
1457c87c5fbaSopenharmony_ci  resource_entry->value = transient_value;
1458c87c5fbaSopenharmony_ci
1459c87c5fbaSopenharmony_ci  if (resource_entry->created) {
1460c87c5fbaSopenharmony_ci    coap_pdu_code_t code = coap_pdu_get_code(request);
1461c87c5fbaSopenharmony_ci
1462c87c5fbaSopenharmony_ci    resource_entry->created = 0;
1463c87c5fbaSopenharmony_ci    coap_pdu_set_code(response, COAP_RESPONSE_CODE_CREATED);
1464c87c5fbaSopenharmony_ci    if (code == COAP_REQUEST_CODE_POST) {
1465c87c5fbaSopenharmony_ci      /* Add in Location-Path / Location-Query Options */
1466c87c5fbaSopenharmony_ci      coap_option_iterator_init(request, &opt_iter, COAP_OPT_ALL);
1467c87c5fbaSopenharmony_ci      while ((option = coap_option_next(&opt_iter))) {
1468c87c5fbaSopenharmony_ci        switch (opt_iter.number) {
1469c87c5fbaSopenharmony_ci        case COAP_OPTION_URI_PATH:
1470c87c5fbaSopenharmony_ci          if (!coap_add_option(response, COAP_OPTION_LOCATION_PATH,
1471c87c5fbaSopenharmony_ci                               coap_opt_length(option),
1472c87c5fbaSopenharmony_ci                               coap_opt_value(option)))
1473c87c5fbaSopenharmony_ci            goto fail;
1474c87c5fbaSopenharmony_ci          break;
1475c87c5fbaSopenharmony_ci        case COAP_OPTION_URI_QUERY:
1476c87c5fbaSopenharmony_ci          if (!coap_add_option(response, COAP_OPTION_LOCATION_QUERY,
1477c87c5fbaSopenharmony_ci                               coap_opt_length(option),
1478c87c5fbaSopenharmony_ci                               coap_opt_value(option)))
1479c87c5fbaSopenharmony_ci            goto fail;
1480c87c5fbaSopenharmony_ci          break;
1481c87c5fbaSopenharmony_ci        default:
1482c87c5fbaSopenharmony_ci          break;
1483c87c5fbaSopenharmony_ci        }
1484c87c5fbaSopenharmony_ci      }
1485c87c5fbaSopenharmony_ci    }
1486c87c5fbaSopenharmony_ci  } else {
1487c87c5fbaSopenharmony_ci    coap_pdu_set_code(response, COAP_RESPONSE_CODE_CHANGED);
1488c87c5fbaSopenharmony_ci    coap_resource_notify_observers(resource_entry->resource, NULL);
1489c87c5fbaSopenharmony_ci  }
1490c87c5fbaSopenharmony_ci
1491c87c5fbaSopenharmony_ci  if (echo_back) {
1492c87c5fbaSopenharmony_ci    coap_binary_t body;
1493c87c5fbaSopenharmony_ci
1494c87c5fbaSopenharmony_ci    body = reference_resource_data(resource_entry->value);
1495c87c5fbaSopenharmony_ci    coap_add_data_large_response(resource, session, request, response,
1496c87c5fbaSopenharmony_ci                                 query, resource_entry->media_type, -1, 0,
1497c87c5fbaSopenharmony_ci                                 body.length,
1498c87c5fbaSopenharmony_ci                                 body.s,
1499c87c5fbaSopenharmony_ci                                 release_resource_data, resource_entry->value);
1500c87c5fbaSopenharmony_ci  }
1501c87c5fbaSopenharmony_ci  return;
1502c87c5fbaSopenharmony_ci
1503c87c5fbaSopenharmony_cifail:
1504c87c5fbaSopenharmony_ci  coap_pdu_set_code(response, COAP_RESPONSE_CODE_INTERNAL_ERROR);
1505c87c5fbaSopenharmony_ci  return;
1506c87c5fbaSopenharmony_ci}
1507c87c5fbaSopenharmony_ci
1508c87c5fbaSopenharmony_ci/*
1509c87c5fbaSopenharmony_ci * Unknown Resource PUT handler
1510c87c5fbaSopenharmony_ci */
1511c87c5fbaSopenharmony_ci
1512c87c5fbaSopenharmony_cistatic void
1513c87c5fbaSopenharmony_cihnd_put_post_unknown(coap_resource_t *resource COAP_UNUSED,
1514c87c5fbaSopenharmony_ci                     coap_session_t *session,
1515c87c5fbaSopenharmony_ci                     const coap_pdu_t *request,
1516c87c5fbaSopenharmony_ci                     const coap_string_t *query,
1517c87c5fbaSopenharmony_ci                     coap_pdu_t *response) {
1518c87c5fbaSopenharmony_ci  coap_resource_t *r;
1519c87c5fbaSopenharmony_ci  coap_string_t *uri_path;
1520c87c5fbaSopenharmony_ci
1521c87c5fbaSopenharmony_ci  /* check if creating a new resource is allowed */
1522c87c5fbaSopenharmony_ci  if (dynamic_count >= support_dynamic) {
1523c87c5fbaSopenharmony_ci    coap_pdu_set_code(response, COAP_RESPONSE_CODE_NOT_ACCEPTABLE);
1524c87c5fbaSopenharmony_ci    return;
1525c87c5fbaSopenharmony_ci  }
1526c87c5fbaSopenharmony_ci
1527c87c5fbaSopenharmony_ci  /* get the uri_path - will get used by coap_resource_init() */
1528c87c5fbaSopenharmony_ci  uri_path = coap_get_uri_path(request);
1529c87c5fbaSopenharmony_ci  if (!uri_path) {
1530c87c5fbaSopenharmony_ci    coap_pdu_set_code(response, COAP_RESPONSE_CODE_NOT_FOUND);
1531c87c5fbaSopenharmony_ci    return;
1532c87c5fbaSopenharmony_ci  }
1533c87c5fbaSopenharmony_ci
1534c87c5fbaSopenharmony_ci  /*
1535c87c5fbaSopenharmony_ci   * Create a resource to handle the new URI
1536c87c5fbaSopenharmony_ci   * uri_path will get deleted when the resource is removed
1537c87c5fbaSopenharmony_ci   */
1538c87c5fbaSopenharmony_ci  r = coap_resource_init((coap_str_const_t *)uri_path,
1539c87c5fbaSopenharmony_ci                         COAP_RESOURCE_FLAGS_RELEASE_URI | resource_flags);
1540c87c5fbaSopenharmony_ci  coap_add_attr(r, coap_make_str_const("title"), coap_make_str_const("\"Dynamic\""), 0);
1541c87c5fbaSopenharmony_ci  coap_register_request_handler(r, COAP_REQUEST_PUT, hnd_put_post);
1542c87c5fbaSopenharmony_ci  coap_register_request_handler(r, COAP_REQUEST_POST, hnd_put_post);
1543c87c5fbaSopenharmony_ci  coap_register_request_handler(r, COAP_REQUEST_DELETE, hnd_delete);
1544c87c5fbaSopenharmony_ci  coap_register_request_handler(r, COAP_REQUEST_FETCH, hnd_get);
1545c87c5fbaSopenharmony_ci  /* We possibly want to Observe the GETs */
1546c87c5fbaSopenharmony_ci  coap_resource_set_get_observable(r, 1);
1547c87c5fbaSopenharmony_ci  coap_register_request_handler(r, COAP_REQUEST_GET, hnd_get);
1548c87c5fbaSopenharmony_ci  coap_add_resource(coap_session_get_context(session), r);
1549c87c5fbaSopenharmony_ci
1550c87c5fbaSopenharmony_ci  /* Do the PUT/POST for this first call */
1551c87c5fbaSopenharmony_ci  hnd_put_post(r, session, request, query, response);
1552c87c5fbaSopenharmony_ci}
1553c87c5fbaSopenharmony_ci
1554c87c5fbaSopenharmony_ci#if SERVER_CAN_PROXY
1555c87c5fbaSopenharmony_cistatic int
1556c87c5fbaSopenharmony_ciproxy_event_handler(coap_session_t *session,
1557c87c5fbaSopenharmony_ci                    coap_event_t event) {
1558c87c5fbaSopenharmony_ci
1559c87c5fbaSopenharmony_ci  switch (event) {
1560c87c5fbaSopenharmony_ci  case COAP_EVENT_DTLS_CLOSED:
1561c87c5fbaSopenharmony_ci  case COAP_EVENT_TCP_CLOSED:
1562c87c5fbaSopenharmony_ci  case COAP_EVENT_SESSION_CLOSED:
1563c87c5fbaSopenharmony_ci  case COAP_EVENT_OSCORE_DECRYPTION_FAILURE:
1564c87c5fbaSopenharmony_ci  case COAP_EVENT_OSCORE_NOT_ENABLED:
1565c87c5fbaSopenharmony_ci  case COAP_EVENT_OSCORE_NO_PROTECTED_PAYLOAD:
1566c87c5fbaSopenharmony_ci  case COAP_EVENT_OSCORE_NO_SECURITY:
1567c87c5fbaSopenharmony_ci  case COAP_EVENT_OSCORE_INTERNAL_ERROR:
1568c87c5fbaSopenharmony_ci  case COAP_EVENT_OSCORE_DECODE_ERROR:
1569c87c5fbaSopenharmony_ci  case COAP_EVENT_WS_PACKET_SIZE:
1570c87c5fbaSopenharmony_ci  case COAP_EVENT_WS_CLOSED:
1571c87c5fbaSopenharmony_ci    /* Need to remove any proxy associations */
1572c87c5fbaSopenharmony_ci    remove_proxy_association(session, 0);
1573c87c5fbaSopenharmony_ci    break;
1574c87c5fbaSopenharmony_ci  case COAP_EVENT_DTLS_CONNECTED:
1575c87c5fbaSopenharmony_ci  case COAP_EVENT_DTLS_RENEGOTIATE:
1576c87c5fbaSopenharmony_ci  case COAP_EVENT_DTLS_ERROR:
1577c87c5fbaSopenharmony_ci  case COAP_EVENT_TCP_CONNECTED:
1578c87c5fbaSopenharmony_ci  case COAP_EVENT_TCP_FAILED:
1579c87c5fbaSopenharmony_ci  case COAP_EVENT_SESSION_CONNECTED:
1580c87c5fbaSopenharmony_ci  case COAP_EVENT_SESSION_FAILED:
1581c87c5fbaSopenharmony_ci  case COAP_EVENT_PARTIAL_BLOCK:
1582c87c5fbaSopenharmony_ci  case COAP_EVENT_XMIT_BLOCK_FAIL:
1583c87c5fbaSopenharmony_ci  case COAP_EVENT_SERVER_SESSION_NEW:
1584c87c5fbaSopenharmony_ci  case COAP_EVENT_SERVER_SESSION_DEL:
1585c87c5fbaSopenharmony_ci  case COAP_EVENT_BAD_PACKET:
1586c87c5fbaSopenharmony_ci  case COAP_EVENT_MSG_RETRANSMITTED:
1587c87c5fbaSopenharmony_ci  case COAP_EVENT_WS_CONNECTED:
1588c87c5fbaSopenharmony_ci  case COAP_EVENT_KEEPALIVE_FAILURE:
1589c87c5fbaSopenharmony_ci  default:
1590c87c5fbaSopenharmony_ci    break;
1591c87c5fbaSopenharmony_ci  }
1592c87c5fbaSopenharmony_ci  return 0;
1593c87c5fbaSopenharmony_ci}
1594c87c5fbaSopenharmony_ci
1595c87c5fbaSopenharmony_cistatic coap_response_t
1596c87c5fbaSopenharmony_ciproxy_response_handler(coap_session_t *session,
1597c87c5fbaSopenharmony_ci                       const coap_pdu_t *sent COAP_UNUSED,
1598c87c5fbaSopenharmony_ci                       const coap_pdu_t *received,
1599c87c5fbaSopenharmony_ci                       const coap_mid_t id COAP_UNUSED) {
1600c87c5fbaSopenharmony_ci
1601c87c5fbaSopenharmony_ci  coap_pdu_t *pdu = NULL;
1602c87c5fbaSopenharmony_ci  coap_session_t *incoming = NULL;
1603c87c5fbaSopenharmony_ci  size_t i;
1604c87c5fbaSopenharmony_ci  size_t size;
1605c87c5fbaSopenharmony_ci  const uint8_t *data;
1606c87c5fbaSopenharmony_ci  coap_optlist_t *optlist = NULL;
1607c87c5fbaSopenharmony_ci  coap_opt_t *option;
1608c87c5fbaSopenharmony_ci  coap_opt_iterator_t opt_iter;
1609c87c5fbaSopenharmony_ci  size_t offset;
1610c87c5fbaSopenharmony_ci  size_t total;
1611c87c5fbaSopenharmony_ci  proxy_list_t *proxy_entry = NULL;
1612c87c5fbaSopenharmony_ci  uint16_t media_type = COAP_MEDIATYPE_TEXT_PLAIN;
1613c87c5fbaSopenharmony_ci  int maxage = -1;
1614c87c5fbaSopenharmony_ci  uint64_t etag = 0;
1615c87c5fbaSopenharmony_ci  coap_pdu_code_t rcv_code = coap_pdu_get_code(received);
1616c87c5fbaSopenharmony_ci  coap_bin_const_t rcv_token = coap_pdu_get_token(received);
1617c87c5fbaSopenharmony_ci  coap_binary_t *body_data = NULL;
1618c87c5fbaSopenharmony_ci
1619c87c5fbaSopenharmony_ci  for (i = 0; i < proxy_list_count; i++) {
1620c87c5fbaSopenharmony_ci    if (proxy_list[i].ongoing == session) {
1621c87c5fbaSopenharmony_ci      proxy_entry = &proxy_list[i];
1622c87c5fbaSopenharmony_ci      incoming = proxy_entry->incoming;
1623c87c5fbaSopenharmony_ci      break;
1624c87c5fbaSopenharmony_ci    }
1625c87c5fbaSopenharmony_ci  }
1626c87c5fbaSopenharmony_ci  if (i == proxy_list_count) {
1627c87c5fbaSopenharmony_ci    coap_log_debug("Unknown proxy ongoing session response received\n");
1628c87c5fbaSopenharmony_ci    return COAP_RESPONSE_OK;
1629c87c5fbaSopenharmony_ci  }
1630c87c5fbaSopenharmony_ci
1631c87c5fbaSopenharmony_ci  coap_log_debug("** process upstream incoming %d.%02d response:\n",
1632c87c5fbaSopenharmony_ci                 COAP_RESPONSE_CLASS(rcv_code), rcv_code & 0x1F);
1633c87c5fbaSopenharmony_ci  if (coap_get_log_level() < COAP_LOG_DEBUG)
1634c87c5fbaSopenharmony_ci    coap_show_pdu(COAP_LOG_INFO, received);
1635c87c5fbaSopenharmony_ci
1636c87c5fbaSopenharmony_ci  if (coap_get_data_large(received, &size, &data, &offset, &total)) {
1637c87c5fbaSopenharmony_ci    /* COAP_BLOCK_SINGLE_BODY is set, so single body should be given */
1638c87c5fbaSopenharmony_ci    assert(size == total);
1639c87c5fbaSopenharmony_ci    body_data = coap_new_binary(total);
1640c87c5fbaSopenharmony_ci    if (!body_data) {
1641c87c5fbaSopenharmony_ci      coap_log_debug("body build memory error\n");
1642c87c5fbaSopenharmony_ci      return COAP_RESPONSE_OK;
1643c87c5fbaSopenharmony_ci    }
1644c87c5fbaSopenharmony_ci    memcpy(body_data->s, data, size);
1645c87c5fbaSopenharmony_ci    data = body_data->s;
1646c87c5fbaSopenharmony_ci  }
1647c87c5fbaSopenharmony_ci
1648c87c5fbaSopenharmony_ci  /*
1649c87c5fbaSopenharmony_ci   * Build up the ongoing PDU that we are going to send to proxy originator
1650c87c5fbaSopenharmony_ci   * as separate response
1651c87c5fbaSopenharmony_ci   */
1652c87c5fbaSopenharmony_ci  pdu = coap_pdu_init(proxy_entry->req_type, rcv_code,
1653c87c5fbaSopenharmony_ci                      coap_new_message_id(incoming),
1654c87c5fbaSopenharmony_ci                      coap_session_max_pdu_size(incoming));
1655c87c5fbaSopenharmony_ci  if (!pdu) {
1656c87c5fbaSopenharmony_ci    coap_log_debug("Failed to create ongoing proxy response PDU\n");
1657c87c5fbaSopenharmony_ci    return COAP_RESPONSE_OK;
1658c87c5fbaSopenharmony_ci  }
1659c87c5fbaSopenharmony_ci
1660c87c5fbaSopenharmony_ci  if (!coap_add_token(pdu, rcv_token.length, rcv_token.s)) {
1661c87c5fbaSopenharmony_ci    coap_log_debug("cannot add token to ongoing proxy response PDU\n");
1662c87c5fbaSopenharmony_ci  }
1663c87c5fbaSopenharmony_ci
1664c87c5fbaSopenharmony_ci  /*
1665c87c5fbaSopenharmony_ci   * Copy the options across, skipping those needed for
1666c87c5fbaSopenharmony_ci   * coap_add_data_response_large()
1667c87c5fbaSopenharmony_ci   */
1668c87c5fbaSopenharmony_ci  coap_option_iterator_init(received, &opt_iter, COAP_OPT_ALL);
1669c87c5fbaSopenharmony_ci  while ((option = coap_option_next(&opt_iter))) {
1670c87c5fbaSopenharmony_ci    switch (opt_iter.number) {
1671c87c5fbaSopenharmony_ci    case COAP_OPTION_CONTENT_FORMAT:
1672c87c5fbaSopenharmony_ci      media_type = coap_decode_var_bytes(coap_opt_value(option),
1673c87c5fbaSopenharmony_ci                                         coap_opt_length(option));
1674c87c5fbaSopenharmony_ci      break;
1675c87c5fbaSopenharmony_ci    case COAP_OPTION_MAXAGE:
1676c87c5fbaSopenharmony_ci      maxage = coap_decode_var_bytes(coap_opt_value(option),
1677c87c5fbaSopenharmony_ci                                     coap_opt_length(option));
1678c87c5fbaSopenharmony_ci      break;
1679c87c5fbaSopenharmony_ci    case COAP_OPTION_ETAG:
1680c87c5fbaSopenharmony_ci      etag = coap_decode_var_bytes8(coap_opt_value(option),
1681c87c5fbaSopenharmony_ci                                    coap_opt_length(option));
1682c87c5fbaSopenharmony_ci      break;
1683c87c5fbaSopenharmony_ci    case COAP_OPTION_BLOCK2:
1684c87c5fbaSopenharmony_ci    case COAP_OPTION_Q_BLOCK2:
1685c87c5fbaSopenharmony_ci    case COAP_OPTION_SIZE2:
1686c87c5fbaSopenharmony_ci      break;
1687c87c5fbaSopenharmony_ci    default:
1688c87c5fbaSopenharmony_ci      coap_insert_optlist(&optlist,
1689c87c5fbaSopenharmony_ci                          coap_new_optlist(opt_iter.number,
1690c87c5fbaSopenharmony_ci                                           coap_opt_length(option),
1691c87c5fbaSopenharmony_ci                                           coap_opt_value(option)));
1692c87c5fbaSopenharmony_ci      break;
1693c87c5fbaSopenharmony_ci    }
1694c87c5fbaSopenharmony_ci  }
1695c87c5fbaSopenharmony_ci  coap_add_optlist_pdu(pdu, &optlist);
1696c87c5fbaSopenharmony_ci  coap_delete_optlist(optlist);
1697c87c5fbaSopenharmony_ci
1698c87c5fbaSopenharmony_ci  if (size > 0) {
1699c87c5fbaSopenharmony_ci    coap_pdu_t *dummy_pdu = coap_pdu_init(proxy_entry->req_type,
1700c87c5fbaSopenharmony_ci                                          proxy_entry->req_code, 0,
1701c87c5fbaSopenharmony_ci                                          coap_session_max_pdu_size(incoming));
1702c87c5fbaSopenharmony_ci
1703c87c5fbaSopenharmony_ci    coap_add_data_large_response(proxy_resource, incoming, dummy_pdu, pdu,
1704c87c5fbaSopenharmony_ci                                 proxy_entry->query,
1705c87c5fbaSopenharmony_ci                                 media_type, maxage, etag, size, data,
1706c87c5fbaSopenharmony_ci                                 release_proxy_body_data,
1707c87c5fbaSopenharmony_ci                                 body_data);
1708c87c5fbaSopenharmony_ci    coap_delete_pdu(dummy_pdu);
1709c87c5fbaSopenharmony_ci  }
1710c87c5fbaSopenharmony_ci
1711c87c5fbaSopenharmony_ci  if (coap_get_log_level() < COAP_LOG_DEBUG)
1712c87c5fbaSopenharmony_ci    coap_show_pdu(COAP_LOG_INFO, pdu);
1713c87c5fbaSopenharmony_ci
1714c87c5fbaSopenharmony_ci  coap_send(incoming, pdu);
1715c87c5fbaSopenharmony_ci  return COAP_RESPONSE_OK;
1716c87c5fbaSopenharmony_ci}
1717c87c5fbaSopenharmony_ci
1718c87c5fbaSopenharmony_cistatic void
1719c87c5fbaSopenharmony_ciproxy_nack_handler(coap_session_t *session,
1720c87c5fbaSopenharmony_ci                   const coap_pdu_t *sent COAP_UNUSED,
1721c87c5fbaSopenharmony_ci                   const coap_nack_reason_t reason,
1722c87c5fbaSopenharmony_ci                   const coap_mid_t mid COAP_UNUSED) {
1723c87c5fbaSopenharmony_ci
1724c87c5fbaSopenharmony_ci  switch (reason) {
1725c87c5fbaSopenharmony_ci  case COAP_NACK_TOO_MANY_RETRIES:
1726c87c5fbaSopenharmony_ci  case COAP_NACK_NOT_DELIVERABLE:
1727c87c5fbaSopenharmony_ci  case COAP_NACK_RST:
1728c87c5fbaSopenharmony_ci  case COAP_NACK_TLS_FAILED:
1729c87c5fbaSopenharmony_ci  case COAP_NACK_WS_FAILED:
1730c87c5fbaSopenharmony_ci  case COAP_NACK_TLS_LAYER_FAILED:
1731c87c5fbaSopenharmony_ci  case COAP_NACK_WS_LAYER_FAILED:
1732c87c5fbaSopenharmony_ci    /* Need to remove any proxy associations */
1733c87c5fbaSopenharmony_ci    remove_proxy_association(session, 1);
1734c87c5fbaSopenharmony_ci    break;
1735c87c5fbaSopenharmony_ci  case COAP_NACK_ICMP_ISSUE:
1736c87c5fbaSopenharmony_ci  case COAP_NACK_BAD_RESPONSE:
1737c87c5fbaSopenharmony_ci  default:
1738c87c5fbaSopenharmony_ci    break;
1739c87c5fbaSopenharmony_ci  }
1740c87c5fbaSopenharmony_ci  return;
1741c87c5fbaSopenharmony_ci}
1742c87c5fbaSopenharmony_ci
1743c87c5fbaSopenharmony_ci#endif /* SERVER_CAN_PROXY */
1744c87c5fbaSopenharmony_ci
1745c87c5fbaSopenharmony_cistatic void
1746c87c5fbaSopenharmony_ciinit_resources(coap_context_t *ctx) {
1747c87c5fbaSopenharmony_ci  coap_resource_t *r;
1748c87c5fbaSopenharmony_ci
1749c87c5fbaSopenharmony_ci  r = coap_resource_init(NULL, COAP_RESOURCE_FLAGS_HAS_MCAST_SUPPORT);
1750c87c5fbaSopenharmony_ci  coap_register_request_handler(r, COAP_REQUEST_GET, hnd_get_index);
1751c87c5fbaSopenharmony_ci
1752c87c5fbaSopenharmony_ci  coap_add_attr(r, coap_make_str_const("ct"), coap_make_str_const("0"), 0);
1753c87c5fbaSopenharmony_ci  coap_add_attr(r, coap_make_str_const("title"), coap_make_str_const("\"General Info\""), 0);
1754c87c5fbaSopenharmony_ci  coap_add_resource(ctx, r);
1755c87c5fbaSopenharmony_ci
1756c87c5fbaSopenharmony_ci  /* store clock base to use in /time */
1757c87c5fbaSopenharmony_ci  my_clock_base = clock_offset;
1758c87c5fbaSopenharmony_ci
1759c87c5fbaSopenharmony_ci  r = coap_resource_init(coap_make_str_const("time"), resource_flags);
1760c87c5fbaSopenharmony_ci  coap_register_request_handler(r, COAP_REQUEST_GET, hnd_get_fetch_time);
1761c87c5fbaSopenharmony_ci  coap_register_request_handler(r, COAP_REQUEST_FETCH, hnd_get_fetch_time);
1762c87c5fbaSopenharmony_ci  coap_register_request_handler(r, COAP_REQUEST_PUT, hnd_put_time);
1763c87c5fbaSopenharmony_ci  coap_register_request_handler(r, COAP_REQUEST_DELETE, hnd_delete_time);
1764c87c5fbaSopenharmony_ci  coap_resource_set_get_observable(r, 1);
1765c87c5fbaSopenharmony_ci
1766c87c5fbaSopenharmony_ci  coap_add_attr(r, coap_make_str_const("ct"), coap_make_str_const("0"), 0);
1767c87c5fbaSopenharmony_ci  coap_add_attr(r, coap_make_str_const("title"), coap_make_str_const("\"Internal Clock\""), 0);
1768c87c5fbaSopenharmony_ci  coap_add_attr(r, coap_make_str_const("rt"), coap_make_str_const("\"ticks\""), 0);
1769c87c5fbaSopenharmony_ci  coap_add_attr(r, coap_make_str_const("if"), coap_make_str_const("\"clock\""), 0);
1770c87c5fbaSopenharmony_ci
1771c87c5fbaSopenharmony_ci  coap_add_resource(ctx, r);
1772c87c5fbaSopenharmony_ci  time_resource = r;
1773c87c5fbaSopenharmony_ci
1774c87c5fbaSopenharmony_ci  if (support_dynamic > 0) {
1775c87c5fbaSopenharmony_ci    /* Create a resource to handle PUTs to unknown URIs */
1776c87c5fbaSopenharmony_ci    r = coap_resource_unknown_init2(hnd_put_post_unknown, 0);
1777c87c5fbaSopenharmony_ci    /* Add in handling POST as well */
1778c87c5fbaSopenharmony_ci    coap_register_handler(r, COAP_REQUEST_POST, hnd_put_post_unknown);
1779c87c5fbaSopenharmony_ci    coap_add_resource(ctx, r);
1780c87c5fbaSopenharmony_ci  }
1781c87c5fbaSopenharmony_ci
1782c87c5fbaSopenharmony_ci  if (coap_async_is_supported()) {
1783c87c5fbaSopenharmony_ci    r = coap_resource_init(coap_make_str_const("async"),
1784c87c5fbaSopenharmony_ci                           resource_flags |
1785c87c5fbaSopenharmony_ci                           COAP_RESOURCE_FLAGS_HAS_MCAST_SUPPORT |
1786c87c5fbaSopenharmony_ci                           COAP_RESOURCE_FLAGS_LIB_DIS_MCAST_DELAYS);
1787c87c5fbaSopenharmony_ci    coap_register_request_handler(r, COAP_REQUEST_GET, hnd_get_async);
1788c87c5fbaSopenharmony_ci
1789c87c5fbaSopenharmony_ci    coap_add_attr(r, coap_make_str_const("ct"), coap_make_str_const("0"), 0);
1790c87c5fbaSopenharmony_ci    coap_add_resource(ctx, r);
1791c87c5fbaSopenharmony_ci  }
1792c87c5fbaSopenharmony_ci
1793c87c5fbaSopenharmony_ci  r = coap_resource_init(coap_make_str_const("example_data"), resource_flags);
1794c87c5fbaSopenharmony_ci  coap_register_request_handler(r, COAP_REQUEST_GET, hnd_get_example_data);
1795c87c5fbaSopenharmony_ci  coap_register_request_handler(r, COAP_REQUEST_PUT, hnd_put_example_data);
1796c87c5fbaSopenharmony_ci  coap_register_request_handler(r, COAP_REQUEST_FETCH, hnd_get_example_data);
1797c87c5fbaSopenharmony_ci  coap_resource_set_get_observable(r, 1);
1798c87c5fbaSopenharmony_ci
1799c87c5fbaSopenharmony_ci  coap_add_attr(r, coap_make_str_const("ct"), coap_make_str_const("0"), 0);
1800c87c5fbaSopenharmony_ci  coap_add_attr(r, coap_make_str_const("title"), coap_make_str_const("\"Example Data\""), 0);
1801c87c5fbaSopenharmony_ci  coap_add_resource(ctx, r);
1802c87c5fbaSopenharmony_ci
1803c87c5fbaSopenharmony_ci#if SERVER_CAN_PROXY
1804c87c5fbaSopenharmony_ci  if (proxy_host_name_count) {
1805c87c5fbaSopenharmony_ci    r = coap_resource_proxy_uri_init2(hnd_proxy_uri, proxy_host_name_count,
1806c87c5fbaSopenharmony_ci                                      proxy_host_name_list, 0);
1807c87c5fbaSopenharmony_ci    coap_add_resource(ctx, r);
1808c87c5fbaSopenharmony_ci    coap_register_event_handler(ctx, proxy_event_handler);
1809c87c5fbaSopenharmony_ci    coap_register_response_handler(ctx, proxy_response_handler);
1810c87c5fbaSopenharmony_ci    coap_register_nack_handler(ctx, proxy_nack_handler);
1811c87c5fbaSopenharmony_ci    proxy_resource = r;
1812c87c5fbaSopenharmony_ci  }
1813c87c5fbaSopenharmony_ci#endif /* SERVER_CAN_PROXY */
1814c87c5fbaSopenharmony_ci}
1815c87c5fbaSopenharmony_ci
1816c87c5fbaSopenharmony_cistatic int
1817c87c5fbaSopenharmony_civerify_cn_callback(const char *cn,
1818c87c5fbaSopenharmony_ci                   const uint8_t *asn1_public_cert COAP_UNUSED,
1819c87c5fbaSopenharmony_ci                   size_t asn1_length COAP_UNUSED,
1820c87c5fbaSopenharmony_ci                   coap_session_t *session COAP_UNUSED,
1821c87c5fbaSopenharmony_ci                   unsigned depth,
1822c87c5fbaSopenharmony_ci                   int validated COAP_UNUSED,
1823c87c5fbaSopenharmony_ci                   void *arg) {
1824c87c5fbaSopenharmony_ci  union {
1825c87c5fbaSopenharmony_ci    coap_dtls_role_t r;
1826c87c5fbaSopenharmony_ci    void *v;
1827c87c5fbaSopenharmony_ci  } role = { .v = arg };
1828c87c5fbaSopenharmony_ci
1829c87c5fbaSopenharmony_ci  coap_log_info("CN '%s' presented by %s (%s)\n",
1830c87c5fbaSopenharmony_ci                cn, role.r == COAP_DTLS_ROLE_SERVER ? "client" : "server",
1831c87c5fbaSopenharmony_ci                depth ? "CA" : "Certificate");
1832c87c5fbaSopenharmony_ci  return 1;
1833c87c5fbaSopenharmony_ci}
1834c87c5fbaSopenharmony_ci
1835c87c5fbaSopenharmony_cistatic uint8_t *
1836c87c5fbaSopenharmony_ciread_file_mem(const char *file, size_t *length) {
1837c87c5fbaSopenharmony_ci  FILE *f;
1838c87c5fbaSopenharmony_ci  uint8_t *buf;
1839c87c5fbaSopenharmony_ci  struct stat statbuf;
1840c87c5fbaSopenharmony_ci
1841c87c5fbaSopenharmony_ci  *length = 0;
1842c87c5fbaSopenharmony_ci  if (!file || !(f = fopen(file, "r")))
1843c87c5fbaSopenharmony_ci    return NULL;
1844c87c5fbaSopenharmony_ci
1845c87c5fbaSopenharmony_ci  if (fstat(fileno(f), &statbuf) == -1) {
1846c87c5fbaSopenharmony_ci    fclose(f);
1847c87c5fbaSopenharmony_ci    return NULL;
1848c87c5fbaSopenharmony_ci  }
1849c87c5fbaSopenharmony_ci
1850c87c5fbaSopenharmony_ci  buf = coap_malloc(statbuf.st_size+1);
1851c87c5fbaSopenharmony_ci  if (!buf) {
1852c87c5fbaSopenharmony_ci    fclose(f);
1853c87c5fbaSopenharmony_ci    return NULL;
1854c87c5fbaSopenharmony_ci  }
1855c87c5fbaSopenharmony_ci
1856c87c5fbaSopenharmony_ci  if (fread(buf, 1, statbuf.st_size, f) != (size_t)statbuf.st_size) {
1857c87c5fbaSopenharmony_ci    fclose(f);
1858c87c5fbaSopenharmony_ci    coap_free(buf);
1859c87c5fbaSopenharmony_ci    return NULL;
1860c87c5fbaSopenharmony_ci  }
1861c87c5fbaSopenharmony_ci  buf[statbuf.st_size] = '\000';
1862c87c5fbaSopenharmony_ci  *length = (size_t)(statbuf.st_size + 1);
1863c87c5fbaSopenharmony_ci  fclose(f);
1864c87c5fbaSopenharmony_ci  return buf;
1865c87c5fbaSopenharmony_ci}
1866c87c5fbaSopenharmony_ci
1867c87c5fbaSopenharmony_cistatic void
1868c87c5fbaSopenharmony_ciupdate_pki_key(coap_dtls_key_t *dtls_key, const char *key_name,
1869c87c5fbaSopenharmony_ci               const char *cert_name, const char *ca_name) {
1870c87c5fbaSopenharmony_ci  memset(dtls_key, 0, sizeof(*dtls_key));
1871c87c5fbaSopenharmony_ci  if ((key_name && strncasecmp(key_name, "pkcs11:", 7) == 0) ||
1872c87c5fbaSopenharmony_ci      (cert_name && strncasecmp(cert_name, "pkcs11:", 7) == 0) ||
1873c87c5fbaSopenharmony_ci      (ca_name && strncasecmp(ca_name, "pkcs11:", 7) == 0)) {
1874c87c5fbaSopenharmony_ci    dtls_key->key_type = COAP_PKI_KEY_PKCS11;
1875c87c5fbaSopenharmony_ci    dtls_key->key.pkcs11.public_cert = cert_name;
1876c87c5fbaSopenharmony_ci    dtls_key->key.pkcs11.private_key = key_name ?  key_name : cert_name;
1877c87c5fbaSopenharmony_ci    dtls_key->key.pkcs11.ca = ca_name;
1878c87c5fbaSopenharmony_ci    dtls_key->key.pkcs11.user_pin = pkcs11_pin;
1879c87c5fbaSopenharmony_ci  } else if (!use_pem_buf && !is_rpk_not_cert) {
1880c87c5fbaSopenharmony_ci    dtls_key->key_type = COAP_PKI_KEY_PEM;
1881c87c5fbaSopenharmony_ci    dtls_key->key.pem.public_cert = cert_name;
1882c87c5fbaSopenharmony_ci    dtls_key->key.pem.private_key = key_name ? key_name : cert_name;
1883c87c5fbaSopenharmony_ci    dtls_key->key.pem.ca_file = ca_name;
1884c87c5fbaSopenharmony_ci  } else {
1885c87c5fbaSopenharmony_ci    /* Map file into memory */
1886c87c5fbaSopenharmony_ci    coap_free(ca_mem);
1887c87c5fbaSopenharmony_ci    coap_free(cert_mem);
1888c87c5fbaSopenharmony_ci    coap_free(key_mem);
1889c87c5fbaSopenharmony_ci    ca_mem = read_file_mem(ca_name, &ca_mem_len);
1890c87c5fbaSopenharmony_ci    cert_mem = read_file_mem(cert_name, &cert_mem_len);
1891c87c5fbaSopenharmony_ci    key_mem = read_file_mem(key_name, &key_mem_len);
1892c87c5fbaSopenharmony_ci
1893c87c5fbaSopenharmony_ci    dtls_key->key_type = COAP_PKI_KEY_PEM_BUF;
1894c87c5fbaSopenharmony_ci    dtls_key->key.pem_buf.ca_cert = ca_mem;
1895c87c5fbaSopenharmony_ci    dtls_key->key.pem_buf.public_cert = cert_mem;
1896c87c5fbaSopenharmony_ci    dtls_key->key.pem_buf.private_key = key_mem ? key_mem : cert_mem;
1897c87c5fbaSopenharmony_ci    dtls_key->key.pem_buf.ca_cert_len = ca_mem_len;
1898c87c5fbaSopenharmony_ci    dtls_key->key.pem_buf.public_cert_len = cert_mem_len;
1899c87c5fbaSopenharmony_ci    dtls_key->key.pem_buf.private_key_len = key_mem ?
1900c87c5fbaSopenharmony_ci                                            key_mem_len : cert_mem_len;
1901c87c5fbaSopenharmony_ci  }
1902c87c5fbaSopenharmony_ci}
1903c87c5fbaSopenharmony_ci
1904c87c5fbaSopenharmony_cistatic coap_dtls_key_t *
1905c87c5fbaSopenharmony_civerify_pki_sni_callback(const char *sni,
1906c87c5fbaSopenharmony_ci                        void *arg COAP_UNUSED) {
1907c87c5fbaSopenharmony_ci  static coap_dtls_key_t dtls_key;
1908c87c5fbaSopenharmony_ci
1909c87c5fbaSopenharmony_ci  update_pki_key(&dtls_key, key_file, cert_file, ca_file);
1910c87c5fbaSopenharmony_ci
1911c87c5fbaSopenharmony_ci  if (sni[0]) {
1912c87c5fbaSopenharmony_ci    size_t i;
1913c87c5fbaSopenharmony_ci    coap_log_info("SNI '%s' requested\n", sni);
1914c87c5fbaSopenharmony_ci    for (i = 0; i < valid_pki_snis.count; i++) {
1915c87c5fbaSopenharmony_ci      /* Test for SNI to change cert + ca */
1916c87c5fbaSopenharmony_ci      if (strcasecmp(sni, valid_pki_snis.pki_sni_list[i].sni_match) == 0) {
1917c87c5fbaSopenharmony_ci        coap_log_info("Switching to using cert '%s' + ca '%s'\n",
1918c87c5fbaSopenharmony_ci                      valid_pki_snis.pki_sni_list[i].new_cert,
1919c87c5fbaSopenharmony_ci                      valid_pki_snis.pki_sni_list[i].new_ca);
1920c87c5fbaSopenharmony_ci        update_pki_key(&dtls_key, valid_pki_snis.pki_sni_list[i].new_cert,
1921c87c5fbaSopenharmony_ci                       valid_pki_snis.pki_sni_list[i].new_cert,
1922c87c5fbaSopenharmony_ci                       valid_pki_snis.pki_sni_list[i].new_ca);
1923c87c5fbaSopenharmony_ci        break;
1924c87c5fbaSopenharmony_ci      }
1925c87c5fbaSopenharmony_ci    }
1926c87c5fbaSopenharmony_ci  } else {
1927c87c5fbaSopenharmony_ci    coap_log_debug("SNI not requested\n");
1928c87c5fbaSopenharmony_ci  }
1929c87c5fbaSopenharmony_ci  return &dtls_key;
1930c87c5fbaSopenharmony_ci}
1931c87c5fbaSopenharmony_ci
1932c87c5fbaSopenharmony_cistatic const coap_dtls_spsk_info_t *
1933c87c5fbaSopenharmony_civerify_psk_sni_callback(const char *sni,
1934c87c5fbaSopenharmony_ci                        coap_session_t *c_session COAP_UNUSED,
1935c87c5fbaSopenharmony_ci                        void *arg COAP_UNUSED) {
1936c87c5fbaSopenharmony_ci  static coap_dtls_spsk_info_t psk_info;
1937c87c5fbaSopenharmony_ci
1938c87c5fbaSopenharmony_ci  /* Preset with the defined keys */
1939c87c5fbaSopenharmony_ci  memset(&psk_info, 0, sizeof(psk_info));
1940c87c5fbaSopenharmony_ci  psk_info.hint.s = (const uint8_t *)hint;
1941c87c5fbaSopenharmony_ci  psk_info.hint.length = hint ? strlen(hint) : 0;
1942c87c5fbaSopenharmony_ci  psk_info.key.s = key;
1943c87c5fbaSopenharmony_ci  psk_info.key.length = key_length;
1944c87c5fbaSopenharmony_ci  if (sni) {
1945c87c5fbaSopenharmony_ci    size_t i;
1946c87c5fbaSopenharmony_ci    coap_log_info("SNI '%s' requested\n", sni);
1947c87c5fbaSopenharmony_ci    for (i = 0; i < valid_psk_snis.count; i++) {
1948c87c5fbaSopenharmony_ci      /* Test for identity match to change key */
1949c87c5fbaSopenharmony_ci      if (strcasecmp(sni,
1950c87c5fbaSopenharmony_ci                     valid_psk_snis.psk_sni_list[i].sni_match) == 0) {
1951c87c5fbaSopenharmony_ci        coap_log_info("Switching to using '%.*s' hint + '%.*s' key\n",
1952c87c5fbaSopenharmony_ci                      (int)valid_psk_snis.psk_sni_list[i].new_hint->length,
1953c87c5fbaSopenharmony_ci                      valid_psk_snis.psk_sni_list[i].new_hint->s,
1954c87c5fbaSopenharmony_ci                      (int)valid_psk_snis.psk_sni_list[i].new_key->length,
1955c87c5fbaSopenharmony_ci                      valid_psk_snis.psk_sni_list[i].new_key->s);
1956c87c5fbaSopenharmony_ci        psk_info.hint = *valid_psk_snis.psk_sni_list[i].new_hint;
1957c87c5fbaSopenharmony_ci        psk_info.key = *valid_psk_snis.psk_sni_list[i].new_key;
1958c87c5fbaSopenharmony_ci        break;
1959c87c5fbaSopenharmony_ci      }
1960c87c5fbaSopenharmony_ci    }
1961c87c5fbaSopenharmony_ci  } else {
1962c87c5fbaSopenharmony_ci    coap_log_debug("SNI not requested\n");
1963c87c5fbaSopenharmony_ci  }
1964c87c5fbaSopenharmony_ci  return &psk_info;
1965c87c5fbaSopenharmony_ci}
1966c87c5fbaSopenharmony_ci
1967c87c5fbaSopenharmony_cistatic const coap_bin_const_t *
1968c87c5fbaSopenharmony_civerify_id_callback(coap_bin_const_t *identity,
1969c87c5fbaSopenharmony_ci                   coap_session_t *c_session,
1970c87c5fbaSopenharmony_ci                   void *arg COAP_UNUSED) {
1971c87c5fbaSopenharmony_ci  static coap_bin_const_t psk_key;
1972c87c5fbaSopenharmony_ci  const coap_bin_const_t *s_psk_hint = coap_session_get_psk_hint(c_session);
1973c87c5fbaSopenharmony_ci  const coap_bin_const_t *s_psk_key;
1974c87c5fbaSopenharmony_ci  size_t i;
1975c87c5fbaSopenharmony_ci
1976c87c5fbaSopenharmony_ci  coap_log_info("Identity '%.*s' requested, current hint '%.*s'\n", (int)identity->length,
1977c87c5fbaSopenharmony_ci                identity->s,
1978c87c5fbaSopenharmony_ci                s_psk_hint ? (int)s_psk_hint->length : 0,
1979c87c5fbaSopenharmony_ci                s_psk_hint ? (const char *)s_psk_hint->s : "");
1980c87c5fbaSopenharmony_ci
1981c87c5fbaSopenharmony_ci  for (i = 0; i < valid_ids.count; i++) {
1982c87c5fbaSopenharmony_ci    /* Check for hint match */
1983c87c5fbaSopenharmony_ci    if (s_psk_hint &&
1984c87c5fbaSopenharmony_ci        strcmp((const char *)s_psk_hint->s,
1985c87c5fbaSopenharmony_ci               valid_ids.id_list[i].hint_match)) {
1986c87c5fbaSopenharmony_ci      continue;
1987c87c5fbaSopenharmony_ci    }
1988c87c5fbaSopenharmony_ci    /* Test for identity match to change key */
1989c87c5fbaSopenharmony_ci    if (coap_binary_equal(identity, valid_ids.id_list[i].identity_match)) {
1990c87c5fbaSopenharmony_ci      coap_log_info("Switching to using '%.*s' key\n",
1991c87c5fbaSopenharmony_ci                    (int)valid_ids.id_list[i].new_key->length,
1992c87c5fbaSopenharmony_ci                    valid_ids.id_list[i].new_key->s);
1993c87c5fbaSopenharmony_ci      return valid_ids.id_list[i].new_key;
1994c87c5fbaSopenharmony_ci    }
1995c87c5fbaSopenharmony_ci  }
1996c87c5fbaSopenharmony_ci
1997c87c5fbaSopenharmony_ci  s_psk_key = coap_session_get_psk_key(c_session);
1998c87c5fbaSopenharmony_ci  if (s_psk_key) {
1999c87c5fbaSopenharmony_ci    /* Been updated by SNI callback */
2000c87c5fbaSopenharmony_ci    psk_key = *s_psk_key;
2001c87c5fbaSopenharmony_ci    return &psk_key;
2002c87c5fbaSopenharmony_ci  }
2003c87c5fbaSopenharmony_ci
2004c87c5fbaSopenharmony_ci  /* Just use the defined key for now */
2005c87c5fbaSopenharmony_ci  psk_key.s = key;
2006c87c5fbaSopenharmony_ci  psk_key.length = key_length;
2007c87c5fbaSopenharmony_ci  return &psk_key;
2008c87c5fbaSopenharmony_ci}
2009c87c5fbaSopenharmony_ci
2010c87c5fbaSopenharmony_cistatic coap_dtls_pki_t *
2011c87c5fbaSopenharmony_cisetup_pki(coap_context_t *ctx, coap_dtls_role_t role, char *client_sni) {
2012c87c5fbaSopenharmony_ci  static coap_dtls_pki_t dtls_pki;
2013c87c5fbaSopenharmony_ci
2014c87c5fbaSopenharmony_ci  /* If general root CAs are defined */
2015c87c5fbaSopenharmony_ci  if (role == COAP_DTLS_ROLE_SERVER && root_ca_file) {
2016c87c5fbaSopenharmony_ci    struct stat stbuf;
2017c87c5fbaSopenharmony_ci    if ((stat(root_ca_file, &stbuf) == 0) && S_ISDIR(stbuf.st_mode)) {
2018c87c5fbaSopenharmony_ci      coap_context_set_pki_root_cas(ctx, NULL, root_ca_file);
2019c87c5fbaSopenharmony_ci    } else {
2020c87c5fbaSopenharmony_ci      coap_context_set_pki_root_cas(ctx, root_ca_file, NULL);
2021c87c5fbaSopenharmony_ci    }
2022c87c5fbaSopenharmony_ci  }
2023c87c5fbaSopenharmony_ci
2024c87c5fbaSopenharmony_ci  memset(&dtls_pki, 0, sizeof(dtls_pki));
2025c87c5fbaSopenharmony_ci  dtls_pki.version = COAP_DTLS_PKI_SETUP_VERSION;
2026c87c5fbaSopenharmony_ci  if (ca_file || root_ca_file) {
2027c87c5fbaSopenharmony_ci    /*
2028c87c5fbaSopenharmony_ci     * Add in additional certificate checking.
2029c87c5fbaSopenharmony_ci     * This list of enabled can be tuned for the specific
2030c87c5fbaSopenharmony_ci     * requirements - see 'man coap_encryption'.
2031c87c5fbaSopenharmony_ci     *
2032c87c5fbaSopenharmony_ci     * Note: root_ca_file is setup separately using
2033c87c5fbaSopenharmony_ci     * coap_context_set_pki_root_cas(), but this is used to define what
2034c87c5fbaSopenharmony_ci     * checking actually takes place.
2035c87c5fbaSopenharmony_ci     */
2036c87c5fbaSopenharmony_ci    dtls_pki.verify_peer_cert        = verify_peer_cert;
2037c87c5fbaSopenharmony_ci    dtls_pki.check_common_ca         = !root_ca_file;
2038c87c5fbaSopenharmony_ci    dtls_pki.allow_self_signed       = 1;
2039c87c5fbaSopenharmony_ci    dtls_pki.allow_expired_certs     = 1;
2040c87c5fbaSopenharmony_ci    dtls_pki.cert_chain_validation   = 1;
2041c87c5fbaSopenharmony_ci    dtls_pki.cert_chain_verify_depth = 2;
2042c87c5fbaSopenharmony_ci    dtls_pki.check_cert_revocation   = 1;
2043c87c5fbaSopenharmony_ci    dtls_pki.allow_no_crl            = 1;
2044c87c5fbaSopenharmony_ci    dtls_pki.allow_expired_crl       = 1;
2045c87c5fbaSopenharmony_ci  } else if (is_rpk_not_cert) {
2046c87c5fbaSopenharmony_ci    dtls_pki.verify_peer_cert        = verify_peer_cert;
2047c87c5fbaSopenharmony_ci  }
2048c87c5fbaSopenharmony_ci  dtls_pki.is_rpk_not_cert        = is_rpk_not_cert;
2049c87c5fbaSopenharmony_ci  dtls_pki.validate_cn_call_back  = verify_cn_callback;
2050c87c5fbaSopenharmony_ci  dtls_pki.cn_call_back_arg       = (void *)role;
2051c87c5fbaSopenharmony_ci  dtls_pki.validate_sni_call_back = role == COAP_DTLS_ROLE_SERVER ?
2052c87c5fbaSopenharmony_ci                                    verify_pki_sni_callback : NULL;
2053c87c5fbaSopenharmony_ci  dtls_pki.sni_call_back_arg      = NULL;
2054c87c5fbaSopenharmony_ci
2055c87c5fbaSopenharmony_ci  if (role == COAP_DTLS_ROLE_CLIENT) {
2056c87c5fbaSopenharmony_ci    dtls_pki.client_sni = client_sni;
2057c87c5fbaSopenharmony_ci  }
2058c87c5fbaSopenharmony_ci
2059c87c5fbaSopenharmony_ci  update_pki_key(&dtls_pki.pki_key, key_file, cert_file, ca_file);
2060c87c5fbaSopenharmony_ci  /* Need to keep base initialization copies of any COAP_PKI_KEY_PEM_BUF */
2061c87c5fbaSopenharmony_ci  ca_mem_base = ca_mem;
2062c87c5fbaSopenharmony_ci  cert_mem_base = cert_mem;
2063c87c5fbaSopenharmony_ci  key_mem_base = key_mem;
2064c87c5fbaSopenharmony_ci  ca_mem = NULL;
2065c87c5fbaSopenharmony_ci  cert_mem = NULL;
2066c87c5fbaSopenharmony_ci  key_mem = NULL;
2067c87c5fbaSopenharmony_ci  return &dtls_pki;
2068c87c5fbaSopenharmony_ci}
2069c87c5fbaSopenharmony_ci
2070c87c5fbaSopenharmony_cistatic coap_dtls_spsk_t *
2071c87c5fbaSopenharmony_cisetup_spsk(void) {
2072c87c5fbaSopenharmony_ci  static coap_dtls_spsk_t dtls_spsk;
2073c87c5fbaSopenharmony_ci
2074c87c5fbaSopenharmony_ci  memset(&dtls_spsk, 0, sizeof(dtls_spsk));
2075c87c5fbaSopenharmony_ci  dtls_spsk.version = COAP_DTLS_SPSK_SETUP_VERSION;
2076c87c5fbaSopenharmony_ci  dtls_spsk.validate_id_call_back = valid_ids.count ?
2077c87c5fbaSopenharmony_ci                                    verify_id_callback : NULL;
2078c87c5fbaSopenharmony_ci  dtls_spsk.validate_sni_call_back = valid_psk_snis.count ?
2079c87c5fbaSopenharmony_ci                                     verify_psk_sni_callback : NULL;
2080c87c5fbaSopenharmony_ci  dtls_spsk.psk_info.hint.s = (const uint8_t *)hint;
2081c87c5fbaSopenharmony_ci  dtls_spsk.psk_info.hint.length = hint ? strlen(hint) : 0;
2082c87c5fbaSopenharmony_ci  dtls_spsk.psk_info.key.s = key;
2083c87c5fbaSopenharmony_ci  dtls_spsk.psk_info.key.length = key_length;
2084c87c5fbaSopenharmony_ci  return &dtls_spsk;
2085c87c5fbaSopenharmony_ci}
2086c87c5fbaSopenharmony_ci
2087c87c5fbaSopenharmony_cistatic void
2088c87c5fbaSopenharmony_cifill_keystore(coap_context_t *ctx) {
2089c87c5fbaSopenharmony_ci
2090c87c5fbaSopenharmony_ci  if (cert_file == NULL && key_defined == 0) {
2091c87c5fbaSopenharmony_ci    if (coap_dtls_is_supported() || coap_tls_is_supported()) {
2092c87c5fbaSopenharmony_ci      coap_log_debug("(D)TLS not enabled as none of -k, -c or -M options specified\n");
2093c87c5fbaSopenharmony_ci    }
2094c87c5fbaSopenharmony_ci    return;
2095c87c5fbaSopenharmony_ci  }
2096c87c5fbaSopenharmony_ci  if (cert_file) {
2097c87c5fbaSopenharmony_ci    coap_dtls_pki_t *dtls_pki = setup_pki(ctx,
2098c87c5fbaSopenharmony_ci                                          COAP_DTLS_ROLE_SERVER, NULL);
2099c87c5fbaSopenharmony_ci    if (!coap_context_set_pki(ctx, dtls_pki)) {
2100c87c5fbaSopenharmony_ci      coap_log_info("Unable to set up %s keys\n",
2101c87c5fbaSopenharmony_ci                    is_rpk_not_cert ? "RPK" : "PKI");
2102c87c5fbaSopenharmony_ci      /* So we do not set up DTLS */
2103c87c5fbaSopenharmony_ci      cert_file = NULL;
2104c87c5fbaSopenharmony_ci    }
2105c87c5fbaSopenharmony_ci  }
2106c87c5fbaSopenharmony_ci  if (key_defined) {
2107c87c5fbaSopenharmony_ci    coap_dtls_spsk_t *dtls_spsk = setup_spsk();
2108c87c5fbaSopenharmony_ci
2109c87c5fbaSopenharmony_ci    if (!coap_context_set_psk2(ctx, dtls_spsk)) {
2110c87c5fbaSopenharmony_ci      coap_log_info("Unable to set up PSK\n");
2111c87c5fbaSopenharmony_ci      /* So we do not set up DTLS */
2112c87c5fbaSopenharmony_ci      key_defined = 0;
2113c87c5fbaSopenharmony_ci    }
2114c87c5fbaSopenharmony_ci  }
2115c87c5fbaSopenharmony_ci}
2116c87c5fbaSopenharmony_ci
2117c87c5fbaSopenharmony_cistatic void
2118c87c5fbaSopenharmony_ciusage(const char *program, const char *version) {
2119c87c5fbaSopenharmony_ci  const char *p;
2120c87c5fbaSopenharmony_ci  char buffer[120];
2121c87c5fbaSopenharmony_ci  const char *lib_build = coap_package_build();
2122c87c5fbaSopenharmony_ci
2123c87c5fbaSopenharmony_ci  p = strrchr(program, '/');
2124c87c5fbaSopenharmony_ci  if (p)
2125c87c5fbaSopenharmony_ci    program = ++p;
2126c87c5fbaSopenharmony_ci
2127c87c5fbaSopenharmony_ci  fprintf(stderr, "%s v%s -- a small CoAP implementation\n"
2128c87c5fbaSopenharmony_ci          "(c) 2010,2011,2015-2023 Olaf Bergmann <bergmann@tzi.org> and others\n\n"
2129c87c5fbaSopenharmony_ci          "Build: %s\n"
2130c87c5fbaSopenharmony_ci          "%s\n"
2131c87c5fbaSopenharmony_ci          , program, version, lib_build,
2132c87c5fbaSopenharmony_ci          coap_string_tls_version(buffer, sizeof(buffer)));
2133c87c5fbaSopenharmony_ci  fprintf(stderr, "%s\n", coap_string_tls_support(buffer, sizeof(buffer)));
2134c87c5fbaSopenharmony_ci  fprintf(stderr, "\n"
2135c87c5fbaSopenharmony_ci          "Usage: %s [-d max] [-e] [-g group] [-l loss] [-p port] [-r] [-v num]\n"
2136c87c5fbaSopenharmony_ci          "\t\t[-w [port][,secure_port]] [-A address]\n"
2137c87c5fbaSopenharmony_ci          "\t\t[-E oscore_conf_file[,seq_file]] [-G group_if] [-L value] [-N]\n"
2138c87c5fbaSopenharmony_ci          "\t\t[-P scheme://address[:port],[name1[,name2..]]]\n"
2139c87c5fbaSopenharmony_ci          "\t\t[-T max_token_size] [-U type] [-V num] [-X size]\n"
2140c87c5fbaSopenharmony_ci          "\t\t[[-h hint] [-i match_identity_file] [-k key]\n"
2141c87c5fbaSopenharmony_ci          "\t\t[-s match_psk_sni_file] [-u user]]\n"
2142c87c5fbaSopenharmony_ci          "\t\t[[-c certfile] [-j keyfile] [-m] [-n] [-C cafile]\n"
2143c87c5fbaSopenharmony_ci          "\t\t[-J pkcs11_pin] [-M rpk_file] [-R trust_casfile]\n"
2144c87c5fbaSopenharmony_ci          "\t\t[-S match_pki_sni_file]]\n"
2145c87c5fbaSopenharmony_ci          "General Options\n"
2146c87c5fbaSopenharmony_ci          "\t-d max \t\tAllow dynamic creation of up to a total of max\n"
2147c87c5fbaSopenharmony_ci          "\t       \t\tresources. If max is reached, a 4.06 code is returned\n"
2148c87c5fbaSopenharmony_ci          "\t       \t\tuntil one of the dynamic resources has been deleted\n"
2149c87c5fbaSopenharmony_ci          "\t-e     \t\tEcho back the data sent with a PUT\n"
2150c87c5fbaSopenharmony_ci          "\t-g group\tJoin the given multicast group\n"
2151c87c5fbaSopenharmony_ci          "\t       \t\tNote: DTLS over multicast is not currently supported\n"
2152c87c5fbaSopenharmony_ci          "\t-l list\t\tFail to send some datagrams specified by a comma\n"
2153c87c5fbaSopenharmony_ci          "\t       \t\tseparated list of numbers or number ranges\n"
2154c87c5fbaSopenharmony_ci          "\t       \t\t(for debugging only)\n"
2155c87c5fbaSopenharmony_ci          "\t-l loss%%\tRandomly fail to send datagrams with the specified\n"
2156c87c5fbaSopenharmony_ci          "\t       \t\tprobability - 100%% all datagrams, 0%% no datagrams\n"
2157c87c5fbaSopenharmony_ci          "\t       \t\t(for debugging only)\n"
2158c87c5fbaSopenharmony_ci          "\t-p port\t\tListen on specified port for UDP and TCP. If (D)TLS is\n"
2159c87c5fbaSopenharmony_ci          "\t       \t\tenabled, then the coap-server will also listen on\n"
2160c87c5fbaSopenharmony_ci          "\t       \t\t'port'+1 for DTLS and TLS.  The default port is 5683\n"
2161c87c5fbaSopenharmony_ci          "\t-r     \t\tEnable multicast per resource support.  If enabled,\n"
2162c87c5fbaSopenharmony_ci          "\t       \t\tonly '/', '/async' and '/.well-known/core' are enabled\n"
2163c87c5fbaSopenharmony_ci          "\t       \t\tfor multicast requests support, otherwise all\n"
2164c87c5fbaSopenharmony_ci          "\t       \t\tresources are enabled\n"
2165c87c5fbaSopenharmony_ci          "\t-t     \t\tTrack resource's observe values so observe\n"
2166c87c5fbaSopenharmony_ci          "\t       \t\tsubscriptions can be maintained over a server restart.\n"
2167c87c5fbaSopenharmony_ci          "\t       \t\tNote: Use 'kill SIGUSR2 <pid>' for controlled shutdown\n"
2168c87c5fbaSopenharmony_ci          "\t-v num \t\tVerbosity level (default 4, maximum is 8) for general\n"
2169c87c5fbaSopenharmony_ci          "\t       \t\tCoAP logging\n"
2170c87c5fbaSopenharmony_ci          "\t-w [port][,secure_port]\n"
2171c87c5fbaSopenharmony_ci          "\t       \t\tEnable WebSockets support on port (WS) and/or secure_port\n"
2172c87c5fbaSopenharmony_ci          "\t       \t\t(WSS), comma separated\n"
2173c87c5fbaSopenharmony_ci          "\t-A address\tInterface address to bind to\n"
2174c87c5fbaSopenharmony_ci          "\t-E oscore_conf_file[,seq_file]\n"
2175c87c5fbaSopenharmony_ci          "\t       \t\toscore_conf_file contains OSCORE configuration. See\n"
2176c87c5fbaSopenharmony_ci          "\t       \t\tcoap-oscore-conf(5) for definitions.\n"
2177c87c5fbaSopenharmony_ci          "\t       \t\tOptional seq_file is used to save the current transmit\n"
2178c87c5fbaSopenharmony_ci          "\t       \t\tsequence number, so on restart sequence numbers continue\n"
2179c87c5fbaSopenharmony_ci          "\t-G group_if\tUse this interface for listening for the multicast\n"
2180c87c5fbaSopenharmony_ci          "\t       \t\tgroup. This can be different from the implied interface\n"
2181c87c5fbaSopenharmony_ci          "\t       \t\tif the -A option is used\n"
2182c87c5fbaSopenharmony_ci          "\t-L value\tSum of one or more COAP_BLOCK_* flag valuess for block\n"
2183c87c5fbaSopenharmony_ci          "\t       \t\thandling methods. Default is 1 (COAP_BLOCK_USE_LIBCOAP)\n"
2184c87c5fbaSopenharmony_ci          "\t       \t\t(Sum of one or more of 1,2 and 4)\n"
2185c87c5fbaSopenharmony_ci          "\t-N     \t\tMake \"observe\" responses NON-confirmable. Even if set\n"
2186c87c5fbaSopenharmony_ci          "\t       \t\tevery fifth response will still be sent as a confirmable\n"
2187c87c5fbaSopenharmony_ci          "\t       \t\tresponse (RFC 7641 requirement)\n"
2188c87c5fbaSopenharmony_ci          , program);
2189c87c5fbaSopenharmony_ci  fprintf(stderr,
2190c87c5fbaSopenharmony_ci          "\t-P scheme://address[:port],[name1[,name2[,name3..]]]\n"
2191c87c5fbaSopenharmony_ci          "\t       \t\tScheme, address, optional port of how to connect to the\n"
2192c87c5fbaSopenharmony_ci          "\t       \t\tnext proxy server and zero or more names (comma\n"
2193c87c5fbaSopenharmony_ci          "\t       \t\tseparated) that this proxy server is known by. The\n"
2194c87c5fbaSopenharmony_ci          "\t       \t\t, (comma) is required. If there is no name1 or if the\n"
2195c87c5fbaSopenharmony_ci          "\t       \t\thostname of the incoming proxy request matches one of\n"
2196c87c5fbaSopenharmony_ci          "\t       \t\tthese names, then this server is considered to be the\n"
2197c87c5fbaSopenharmony_ci          "\t       \t\tfinal endpoint. If scheme://address[:port] is not\n"
2198c87c5fbaSopenharmony_ci          "\t       \t\tdefined before the leading , (comma) of the first name,\n"
2199c87c5fbaSopenharmony_ci          "\t       \t\tthen the ongoing connection will be a direct connection.\n"
2200c87c5fbaSopenharmony_ci          "\t       \t\tScheme is one of coap, coaps, coap+tcp and coaps+tcp\n"
2201c87c5fbaSopenharmony_ci          "\t-T max_token_length\tSet the maximum token length (8-65804)\n"
2202c87c5fbaSopenharmony_ci          "\t-U type\t\tTreat address defined by -A as a Unix socket address.\n"
2203c87c5fbaSopenharmony_ci          "\t       \t\ttype is 'coap', 'coaps', 'coap+tcp' or 'coaps+tcp'\n"
2204c87c5fbaSopenharmony_ci          "\t-V num \t\tVerbosity level (default 3, maximum is 7) for (D)TLS\n"
2205c87c5fbaSopenharmony_ci          "\t       \t\tlibrary logging\n"
2206c87c5fbaSopenharmony_ci          "\t-X size\t\tMaximum message size to use for TCP based connections\n"
2207c87c5fbaSopenharmony_ci          "\t       \t\t(default is 8388864). Maximum value of 2^32 -1\n"
2208c87c5fbaSopenharmony_ci          "PSK Options (if supported by underlying (D)TLS library)\n"
2209c87c5fbaSopenharmony_ci          "\t-h hint\t\tIdentity Hint to send. Default is CoAP. Zero length is\n"
2210c87c5fbaSopenharmony_ci          "\t       \t\tno hint\n"
2211c87c5fbaSopenharmony_ci          "\t-i match_identity_file\n"
2212c87c5fbaSopenharmony_ci          "\t       \t\tThis is a file that contains one or more lines of\n"
2213c87c5fbaSopenharmony_ci          "\t       \t\tIdentity Hints and (user) Identities to match for\n"
2214c87c5fbaSopenharmony_ci          "\t       \t\ta different new Pre-Shared Key (PSK) (comma separated)\n"
2215c87c5fbaSopenharmony_ci          "\t       \t\tto be used. E.g., per line\n"
2216c87c5fbaSopenharmony_ci          "\t       \t\t hint_to_match,identity_to_match,use_key\n"
2217c87c5fbaSopenharmony_ci          "\t       \t\tNote: -k still needs to be defined for the default case\n"
2218c87c5fbaSopenharmony_ci          "\t       \t\tNote: A match using the -s option may mean that the\n"
2219c87c5fbaSopenharmony_ci          "\t       \t\tcurrent Identity Hint is different to that defined by -h\n"
2220c87c5fbaSopenharmony_ci          "\t-k key \t\tPre-Shared Key. This argument requires (D)TLS with PSK\n"
2221c87c5fbaSopenharmony_ci          "\t       \t\tto be available. This cannot be empty if defined.\n"
2222c87c5fbaSopenharmony_ci          "\t       \t\tNote that both -c and -k need to be defined for both\n"
2223c87c5fbaSopenharmony_ci          "\t       \t\tPSK and PKI to be concurrently supported\n"
2224c87c5fbaSopenharmony_ci          "\t-s match_psk_sni_file\n"
2225c87c5fbaSopenharmony_ci          "\t       \t\tThis is a file that contains one or more lines of\n"
2226c87c5fbaSopenharmony_ci          "\t       \t\treceived Subject Name Identifier (SNI) to match to use\n"
2227c87c5fbaSopenharmony_ci          "\t       \t\ta different Identity Hint and associated Pre-Shared Key\n"
2228c87c5fbaSopenharmony_ci          "\t       \t\t(PSK) (comma separated) instead of the '-h hint' and\n"
2229c87c5fbaSopenharmony_ci          "\t       \t\t'-k key' options. E.g., per line\n"
2230c87c5fbaSopenharmony_ci          "\t       \t\t sni_to_match,use_hint,with_key\n"
2231c87c5fbaSopenharmony_ci          "\t       \t\tNote: -k still needs to be defined for the default case\n"
2232c87c5fbaSopenharmony_ci          "\t       \t\tif there is not a match\n"
2233c87c5fbaSopenharmony_ci          "\t       \t\tNote: The associated Pre-Shared Key will get updated if\n"
2234c87c5fbaSopenharmony_ci          "\t       \t\tthere is also a -i match.  The update checking order is\n"
2235c87c5fbaSopenharmony_ci          "\t       \t\t-s followed by -i\n"
2236c87c5fbaSopenharmony_ci          "\t-u user\t\tUser identity for pre-shared key mode (only used if\n"
2237c87c5fbaSopenharmony_ci          "\t       \t\toption -P is set)\n"
2238c87c5fbaSopenharmony_ci         );
2239c87c5fbaSopenharmony_ci  fprintf(stderr,
2240c87c5fbaSopenharmony_ci          "PKI Options (if supported by underlying (D)TLS library)\n"
2241c87c5fbaSopenharmony_ci          "\tNote: If any one of '-c certfile', '-j keyfile' or '-C cafile' is in\n"
2242c87c5fbaSopenharmony_ci          "\tPKCS11 URI naming format (pkcs11: prefix), then any remaining non\n"
2243c87c5fbaSopenharmony_ci          "\tPKCS11 URI file definitions have to be in DER, not PEM, format.\n"
2244c87c5fbaSopenharmony_ci          "\tOtherwise all of '-c certfile', '-j keyfile' or '-C cafile' are in\n"
2245c87c5fbaSopenharmony_ci          "\tPEM format.\n\n"
2246c87c5fbaSopenharmony_ci          "\t-c certfile\tPEM file or PKCS11 URI for the certificate. The private\n"
2247c87c5fbaSopenharmony_ci          "\t       \t\tkey can also be in the PEM file, or has the same PKCS11\n"
2248c87c5fbaSopenharmony_ci          "\t       \t\tURI. If not, the private key is defined by '-j keyfile'.\n"
2249c87c5fbaSopenharmony_ci          "\t       \t\tNote that both -c and -k need to be defined for both\n"
2250c87c5fbaSopenharmony_ci          "\t       \t\tPSK and PKI to be concurrently supported\n"
2251c87c5fbaSopenharmony_ci          "\t-j keyfile\tPEM file or PKCS11 URI for the private key for the\n"
2252c87c5fbaSopenharmony_ci          "\t       \t\tcertificate in '-c certfile' if the parameter is\n"
2253c87c5fbaSopenharmony_ci          "\t       \t\tdifferent from certfile in '-c certfile'\n"
2254c87c5fbaSopenharmony_ci          "\t-m     \t\tUse COAP_PKI_KEY_PEM_BUF instead of COAP_PKI_KEY_PEM i/f\n"
2255c87c5fbaSopenharmony_ci          "\t       \t\tby reading into memory the Cert / CA file (for testing)\n"
2256c87c5fbaSopenharmony_ci          "\t-n     \t\tDisable remote peer certificate checking. This gives\n"
2257c87c5fbaSopenharmony_ci          "\t       \t\tclients the ability to use PKI, but without any defined\n"
2258c87c5fbaSopenharmony_ci          "\t       \t\tcertificates\n"
2259c87c5fbaSopenharmony_ci          "\t-C cafile\tPEM file or PKCS11 URI that contains a list of one or\n"
2260c87c5fbaSopenharmony_ci          "\t       \t\tmore CAs that are to be passed to the client for the\n"
2261c87c5fbaSopenharmony_ci          "\t       \t\tclient to determine what client certificate to use.\n"
2262c87c5fbaSopenharmony_ci          "\t       \t\tNormally, this list of CAs would be the root CA and and\n"
2263c87c5fbaSopenharmony_ci          "\t       \t\tany intermediate CAs. Ideally the server certificate\n"
2264c87c5fbaSopenharmony_ci          "\t       \t\tshould be signed by the same CA so that mutual\n"
2265c87c5fbaSopenharmony_ci          "\t       \t\tauthentication can take place. The contents of cafile\n"
2266c87c5fbaSopenharmony_ci          "\t       \t\tare added to the trusted store of root CAs.\n"
2267c87c5fbaSopenharmony_ci          "\t       \t\tUsing the -C or -R options will will trigger the\n"
2268c87c5fbaSopenharmony_ci          "\t       \t\tvalidation of the client certificate unless overridden\n"
2269c87c5fbaSopenharmony_ci          "\t       \t\tby the -n option\n"
2270c87c5fbaSopenharmony_ci          "\t-J pkcs11_pin\tThe user pin to unlock access to the PKCS11 token\n"
2271c87c5fbaSopenharmony_ci          "\t-M rpk_file\tRaw Public Key (RPK) PEM file or PKCS11 URI that\n"
2272c87c5fbaSopenharmony_ci          "\t       \t\tcontains both PUBLIC KEY and PRIVATE KEY or just\n"
2273c87c5fbaSopenharmony_ci          "\t       \t\tEC PRIVATE KEY. (GnuTLS and TinyDTLS(PEM) support only).\n"
2274c87c5fbaSopenharmony_ci          "\t       \t\t'-C cafile' or '-R trust_casfile' are not required\n"
2275c87c5fbaSopenharmony_ci          "\t-R trust_casfile\n"
2276c87c5fbaSopenharmony_ci          "\t       \t\tPEM file containing the set of trusted root CAs\n"
2277c87c5fbaSopenharmony_ci          "\t       \t\tthat are to be used to validate the client certificate.\n"
2278c87c5fbaSopenharmony_ci          "\t       \t\tAlternatively, this can point to a directory containing\n"
2279c87c5fbaSopenharmony_ci          "\t       \t\ta set of CA PEM files.\n"
2280c87c5fbaSopenharmony_ci          "\t       \t\tUsing '-R trust_casfile' disables common CA mutual\n"
2281c87c5fbaSopenharmony_ci          "\t       \t\tauthentication which can only be done by using\n"
2282c87c5fbaSopenharmony_ci          "\t       \t\t'-C cafile'.\n"
2283c87c5fbaSopenharmony_ci          "\t       \t\tUsing the -C or -R options will will trigger the\n"
2284c87c5fbaSopenharmony_ci          "\t       \t\tvalidation of the client certificate unless overridden\n"
2285c87c5fbaSopenharmony_ci          "\t       \t\tby the -n option\n"
2286c87c5fbaSopenharmony_ci          "\t-S match_pki_sni_file\n"
2287c87c5fbaSopenharmony_ci          "\t       \t\tThis option denotes a file that contains one or more\n"
2288c87c5fbaSopenharmony_ci          "\t       \t\tlines of Subject Name Identifier (SNI) to match for new\n"
2289c87c5fbaSopenharmony_ci          "\t       \t\tCert file and new CA file (comma separated) to be used.\n"
2290c87c5fbaSopenharmony_ci          "\t       \t\tE.g., per line\n"
2291c87c5fbaSopenharmony_ci          "\t       \t\t sni_to_match,new_cert_file,new_ca_file\n"
2292c87c5fbaSopenharmony_ci          "\t       \t\tNote: -c and -C still need to be defined for the default\n"
2293c87c5fbaSopenharmony_ci          "\t       \t\tcase\n"
2294c87c5fbaSopenharmony_ci         );
2295c87c5fbaSopenharmony_ci}
2296c87c5fbaSopenharmony_ci
2297c87c5fbaSopenharmony_cistatic coap_context_t *
2298c87c5fbaSopenharmony_ciget_context(const char *node, const char *port) {
2299c87c5fbaSopenharmony_ci  coap_context_t *ctx = NULL;
2300c87c5fbaSopenharmony_ci  coap_addr_info_t *info = NULL;
2301c87c5fbaSopenharmony_ci  coap_addr_info_t *info_list = NULL;
2302c87c5fbaSopenharmony_ci  coap_str_const_t local;
2303c87c5fbaSopenharmony_ci  int have_ep = 0;
2304c87c5fbaSopenharmony_ci  uint16_t u_s_port = 0;
2305c87c5fbaSopenharmony_ci  uint16_t s_port = 0;
2306c87c5fbaSopenharmony_ci  uint32_t scheme_hint_bits = 0;
2307c87c5fbaSopenharmony_ci
2308c87c5fbaSopenharmony_ci  ctx = coap_new_context(NULL);
2309c87c5fbaSopenharmony_ci  if (!ctx) {
2310c87c5fbaSopenharmony_ci    return NULL;
2311c87c5fbaSopenharmony_ci  }
2312c87c5fbaSopenharmony_ci
2313c87c5fbaSopenharmony_ci  /* Need PKI/RPK/PSK set up before we set up (D)TLS endpoints */
2314c87c5fbaSopenharmony_ci  fill_keystore(ctx);
2315c87c5fbaSopenharmony_ci
2316c87c5fbaSopenharmony_ci  if (node) {
2317c87c5fbaSopenharmony_ci    local.s = (const uint8_t *)node;
2318c87c5fbaSopenharmony_ci    local.length = strlen(node);
2319c87c5fbaSopenharmony_ci  }
2320c87c5fbaSopenharmony_ci
2321c87c5fbaSopenharmony_ci  if (port) {
2322c87c5fbaSopenharmony_ci    u_s_port = atoi(port);
2323c87c5fbaSopenharmony_ci    s_port = u_s_port + 1;
2324c87c5fbaSopenharmony_ci  }
2325c87c5fbaSopenharmony_ci  scheme_hint_bits =
2326c87c5fbaSopenharmony_ci      coap_get_available_scheme_hint_bits(cert_file != NULL || key_defined != 0,
2327c87c5fbaSopenharmony_ci                                          enable_ws, use_unix_proto);
2328c87c5fbaSopenharmony_ci  info_list = coap_resolve_address_info(node ? &local : NULL, u_s_port, s_port,
2329c87c5fbaSopenharmony_ci                                        ws_port, wss_port,
2330c87c5fbaSopenharmony_ci                                        AI_PASSIVE | AI_NUMERICHOST,
2331c87c5fbaSopenharmony_ci                                        scheme_hint_bits,
2332c87c5fbaSopenharmony_ci                                        COAP_RESOLVE_TYPE_LOCAL);
2333c87c5fbaSopenharmony_ci  for (info = info_list; info != NULL; info = info->next) {
2334c87c5fbaSopenharmony_ci    coap_endpoint_t *ep;
2335c87c5fbaSopenharmony_ci
2336c87c5fbaSopenharmony_ci    ep = coap_new_endpoint(ctx, &info->addr, info->proto);
2337c87c5fbaSopenharmony_ci    if (!ep) {
2338c87c5fbaSopenharmony_ci      coap_log_warn("cannot create endpoint for proto %u\n",
2339c87c5fbaSopenharmony_ci                    info->proto);
2340c87c5fbaSopenharmony_ci    } else {
2341c87c5fbaSopenharmony_ci      have_ep = 1;
2342c87c5fbaSopenharmony_ci    }
2343c87c5fbaSopenharmony_ci  }
2344c87c5fbaSopenharmony_ci  coap_free_address_info(info_list);
2345c87c5fbaSopenharmony_ci  if (!have_ep) {
2346c87c5fbaSopenharmony_ci    coap_log_err("No context available for interface '%s'\n", node);
2347c87c5fbaSopenharmony_ci    coap_free_context(ctx);
2348c87c5fbaSopenharmony_ci    return NULL;
2349c87c5fbaSopenharmony_ci  }
2350c87c5fbaSopenharmony_ci  return ctx;
2351c87c5fbaSopenharmony_ci}
2352c87c5fbaSopenharmony_ci
2353c87c5fbaSopenharmony_ci#if SERVER_CAN_PROXY
2354c87c5fbaSopenharmony_cistatic int
2355c87c5fbaSopenharmony_cicmdline_proxy(char *arg) {
2356c87c5fbaSopenharmony_ci  char *host_start = strchr(arg, ',');
2357c87c5fbaSopenharmony_ci  char *next_name = host_start;
2358c87c5fbaSopenharmony_ci  size_t ofs;
2359c87c5fbaSopenharmony_ci
2360c87c5fbaSopenharmony_ci  if (!host_start) {
2361c87c5fbaSopenharmony_ci    coap_log_warn("Zero or more proxy host names not defined\n");
2362c87c5fbaSopenharmony_ci    return 0;
2363c87c5fbaSopenharmony_ci  }
2364c87c5fbaSopenharmony_ci  *host_start = '\000';
2365c87c5fbaSopenharmony_ci
2366c87c5fbaSopenharmony_ci  if (host_start != arg) {
2367c87c5fbaSopenharmony_ci    /* Next upstream proxy is defined */
2368c87c5fbaSopenharmony_ci    if (coap_split_uri((unsigned char *)arg, strlen(arg), &proxy) < 0 ||
2369c87c5fbaSopenharmony_ci        proxy.path.length != 0 || proxy.query.length != 0) {
2370c87c5fbaSopenharmony_ci      coap_log_err("invalid CoAP Proxy definition\n");
2371c87c5fbaSopenharmony_ci      return 0;
2372c87c5fbaSopenharmony_ci    }
2373c87c5fbaSopenharmony_ci  }
2374c87c5fbaSopenharmony_ci  proxy_host_name_count = 0;
2375c87c5fbaSopenharmony_ci  while (next_name) {
2376c87c5fbaSopenharmony_ci    proxy_host_name_count++;
2377c87c5fbaSopenharmony_ci    next_name = strchr(next_name+1, ',');
2378c87c5fbaSopenharmony_ci  }
2379c87c5fbaSopenharmony_ci  proxy_host_name_list = coap_malloc(proxy_host_name_count * sizeof(char *));
2380c87c5fbaSopenharmony_ci  next_name = host_start;
2381c87c5fbaSopenharmony_ci  ofs = 0;
2382c87c5fbaSopenharmony_ci  while (next_name) {
2383c87c5fbaSopenharmony_ci    proxy_host_name_list[ofs++] = next_name+1;
2384c87c5fbaSopenharmony_ci    next_name = strchr(next_name+1, ',');
2385c87c5fbaSopenharmony_ci    if (next_name)
2386c87c5fbaSopenharmony_ci      *next_name = '\000';
2387c87c5fbaSopenharmony_ci  }
2388c87c5fbaSopenharmony_ci  return 1;
2389c87c5fbaSopenharmony_ci}
2390c87c5fbaSopenharmony_ci
2391c87c5fbaSopenharmony_cistatic ssize_t
2392c87c5fbaSopenharmony_cicmdline_read_user(char *arg, unsigned char **buf, size_t maxlen) {
2393c87c5fbaSopenharmony_ci  size_t len = strnlen(arg, maxlen);
2394c87c5fbaSopenharmony_ci  if (len) {
2395c87c5fbaSopenharmony_ci    *buf = (unsigned char *)arg;
2396c87c5fbaSopenharmony_ci    /* len is the size or less, so 0 terminate to maxlen */
2397c87c5fbaSopenharmony_ci    (*buf)[len] = '\000';
2398c87c5fbaSopenharmony_ci  }
2399c87c5fbaSopenharmony_ci  /* 0 length Identity is valid */
2400c87c5fbaSopenharmony_ci  return len;
2401c87c5fbaSopenharmony_ci}
2402c87c5fbaSopenharmony_ci#endif /* SERVER_CAN_PROXY */
2403c87c5fbaSopenharmony_ci
2404c87c5fbaSopenharmony_cistatic FILE *oscore_seq_num_fp = NULL;
2405c87c5fbaSopenharmony_cistatic const char *oscore_conf_file = NULL;
2406c87c5fbaSopenharmony_cistatic const char *oscore_seq_save_file = NULL;
2407c87c5fbaSopenharmony_ci
2408c87c5fbaSopenharmony_cistatic int
2409c87c5fbaSopenharmony_cioscore_save_seq_num(uint64_t sender_seq_num, void *param COAP_UNUSED) {
2410c87c5fbaSopenharmony_ci  if (oscore_seq_num_fp) {
2411c87c5fbaSopenharmony_ci    rewind(oscore_seq_num_fp);
2412c87c5fbaSopenharmony_ci    fprintf(oscore_seq_num_fp, "%" PRIu64 "\n", sender_seq_num);
2413c87c5fbaSopenharmony_ci    fflush(oscore_seq_num_fp);
2414c87c5fbaSopenharmony_ci  }
2415c87c5fbaSopenharmony_ci  return 1;
2416c87c5fbaSopenharmony_ci}
2417c87c5fbaSopenharmony_ci
2418c87c5fbaSopenharmony_cistatic coap_oscore_conf_t *
2419c87c5fbaSopenharmony_ciget_oscore_conf(coap_context_t *context) {
2420c87c5fbaSopenharmony_ci  uint8_t *buf;
2421c87c5fbaSopenharmony_ci  size_t length;
2422c87c5fbaSopenharmony_ci  coap_str_const_t file_mem;
2423c87c5fbaSopenharmony_ci  uint64_t start_seq_num = 0;
2424c87c5fbaSopenharmony_ci
2425c87c5fbaSopenharmony_ci  /* Need a rw var to free off later and file_mem.s is a const */
2426c87c5fbaSopenharmony_ci  buf = read_file_mem(oscore_conf_file, &length);
2427c87c5fbaSopenharmony_ci  if (buf == NULL) {
2428c87c5fbaSopenharmony_ci    fprintf(stderr, "OSCORE configuration file error: %s\n", oscore_conf_file);
2429c87c5fbaSopenharmony_ci    return NULL;
2430c87c5fbaSopenharmony_ci  }
2431c87c5fbaSopenharmony_ci  file_mem.s = buf;
2432c87c5fbaSopenharmony_ci  file_mem.length = length;
2433c87c5fbaSopenharmony_ci  if (oscore_seq_save_file) {
2434c87c5fbaSopenharmony_ci    oscore_seq_num_fp = fopen(oscore_seq_save_file, "r+");
2435c87c5fbaSopenharmony_ci    if (oscore_seq_num_fp == NULL) {
2436c87c5fbaSopenharmony_ci      /* Try creating it */
2437c87c5fbaSopenharmony_ci      oscore_seq_num_fp = fopen(oscore_seq_save_file, "w+");
2438c87c5fbaSopenharmony_ci      if (oscore_seq_num_fp == NULL) {
2439c87c5fbaSopenharmony_ci        fprintf(stderr, "OSCORE save restart info file error: %s\n",
2440c87c5fbaSopenharmony_ci                oscore_seq_save_file);
2441c87c5fbaSopenharmony_ci        return NULL;
2442c87c5fbaSopenharmony_ci      }
2443c87c5fbaSopenharmony_ci    }
2444c87c5fbaSopenharmony_ci    if (fscanf(oscore_seq_num_fp, "%" PRIu64, &start_seq_num) != 1) {
2445c87c5fbaSopenharmony_ci      /* Must be empty */
2446c87c5fbaSopenharmony_ci      start_seq_num = 0;
2447c87c5fbaSopenharmony_ci    }
2448c87c5fbaSopenharmony_ci  }
2449c87c5fbaSopenharmony_ci  oscore_conf = coap_new_oscore_conf(file_mem,
2450c87c5fbaSopenharmony_ci                                     oscore_save_seq_num,
2451c87c5fbaSopenharmony_ci                                     NULL, start_seq_num);
2452c87c5fbaSopenharmony_ci  coap_free(buf);
2453c87c5fbaSopenharmony_ci  if (oscore_conf == NULL) {
2454c87c5fbaSopenharmony_ci    fprintf(stderr, "OSCORE configuration file error: %s\n", oscore_conf_file);
2455c87c5fbaSopenharmony_ci    return NULL;
2456c87c5fbaSopenharmony_ci  }
2457c87c5fbaSopenharmony_ci  coap_context_oscore_server(context, oscore_conf);
2458c87c5fbaSopenharmony_ci  return oscore_conf;
2459c87c5fbaSopenharmony_ci}
2460c87c5fbaSopenharmony_ci
2461c87c5fbaSopenharmony_cistatic int
2462c87c5fbaSopenharmony_cicmdline_oscore(char *arg) {
2463c87c5fbaSopenharmony_ci  if (coap_oscore_is_supported()) {
2464c87c5fbaSopenharmony_ci    char *sep = strchr(arg, ',');
2465c87c5fbaSopenharmony_ci
2466c87c5fbaSopenharmony_ci    if (sep)
2467c87c5fbaSopenharmony_ci      *sep = '\000';
2468c87c5fbaSopenharmony_ci    oscore_conf_file = arg;
2469c87c5fbaSopenharmony_ci
2470c87c5fbaSopenharmony_ci    if (sep) {
2471c87c5fbaSopenharmony_ci      sep++;
2472c87c5fbaSopenharmony_ci      oscore_seq_save_file = sep;
2473c87c5fbaSopenharmony_ci    }
2474c87c5fbaSopenharmony_ci    return 1;
2475c87c5fbaSopenharmony_ci  }
2476c87c5fbaSopenharmony_ci  fprintf(stderr, "OSCORE support not enabled\n");
2477c87c5fbaSopenharmony_ci  return 0;
2478c87c5fbaSopenharmony_ci}
2479c87c5fbaSopenharmony_ci
2480c87c5fbaSopenharmony_cistatic ssize_t
2481c87c5fbaSopenharmony_cicmdline_read_key(char *arg, unsigned char **buf, size_t maxlen) {
2482c87c5fbaSopenharmony_ci  size_t len = strnlen(arg, maxlen);
2483c87c5fbaSopenharmony_ci  if (len) {
2484c87c5fbaSopenharmony_ci    *buf = (unsigned char *)arg;
2485c87c5fbaSopenharmony_ci    return len;
2486c87c5fbaSopenharmony_ci  }
2487c87c5fbaSopenharmony_ci  /* Need at least one byte for the pre-shared key */
2488c87c5fbaSopenharmony_ci  coap_log_crit("Invalid Pre-Shared Key specified\n");
2489c87c5fbaSopenharmony_ci  return -1;
2490c87c5fbaSopenharmony_ci}
2491c87c5fbaSopenharmony_ci
2492c87c5fbaSopenharmony_cistatic int
2493c87c5fbaSopenharmony_cicmdline_read_psk_sni_check(char *arg) {
2494c87c5fbaSopenharmony_ci  FILE *fp = fopen(arg, "r");
2495c87c5fbaSopenharmony_ci  static char tmpbuf[256];
2496c87c5fbaSopenharmony_ci  if (fp == NULL) {
2497c87c5fbaSopenharmony_ci    coap_log_err("SNI file: %s: Unable to open\n", arg);
2498c87c5fbaSopenharmony_ci    return 0;
2499c87c5fbaSopenharmony_ci  }
2500c87c5fbaSopenharmony_ci  while (fgets(tmpbuf, sizeof(tmpbuf), fp) != NULL) {
2501c87c5fbaSopenharmony_ci    char *cp = tmpbuf;
2502c87c5fbaSopenharmony_ci    char *tcp = strchr(cp, '\n');
2503c87c5fbaSopenharmony_ci
2504c87c5fbaSopenharmony_ci    if (tmpbuf[0] == '#')
2505c87c5fbaSopenharmony_ci      continue;
2506c87c5fbaSopenharmony_ci    if (tcp)
2507c87c5fbaSopenharmony_ci      *tcp = '\000';
2508c87c5fbaSopenharmony_ci
2509c87c5fbaSopenharmony_ci    tcp = strchr(cp, ',');
2510c87c5fbaSopenharmony_ci    if (tcp) {
2511c87c5fbaSopenharmony_ci      psk_sni_def_t *new_psk_sni_list;
2512c87c5fbaSopenharmony_ci      new_psk_sni_list = realloc(valid_psk_snis.psk_sni_list,
2513c87c5fbaSopenharmony_ci                                 (valid_psk_snis.count + 1)*sizeof(valid_psk_snis.psk_sni_list[0]));
2514c87c5fbaSopenharmony_ci      if (new_psk_sni_list == NULL) {
2515c87c5fbaSopenharmony_ci        break;
2516c87c5fbaSopenharmony_ci      }
2517c87c5fbaSopenharmony_ci      valid_psk_snis.psk_sni_list = new_psk_sni_list;
2518c87c5fbaSopenharmony_ci      valid_psk_snis.psk_sni_list[valid_psk_snis.count].sni_match = strndup(cp, tcp-cp);
2519c87c5fbaSopenharmony_ci      cp = tcp+1;
2520c87c5fbaSopenharmony_ci      tcp = strchr(cp, ',');
2521c87c5fbaSopenharmony_ci      if (tcp) {
2522c87c5fbaSopenharmony_ci        valid_psk_snis.psk_sni_list[valid_psk_snis.count].new_hint =
2523c87c5fbaSopenharmony_ci            coap_new_bin_const((const uint8_t *)cp, tcp-cp);
2524c87c5fbaSopenharmony_ci        cp = tcp+1;
2525c87c5fbaSopenharmony_ci        valid_psk_snis.psk_sni_list[valid_psk_snis.count].new_key =
2526c87c5fbaSopenharmony_ci            coap_new_bin_const((const uint8_t *)cp, strlen(cp));
2527c87c5fbaSopenharmony_ci        valid_psk_snis.count++;
2528c87c5fbaSopenharmony_ci      } else {
2529c87c5fbaSopenharmony_ci        free(valid_psk_snis.psk_sni_list[valid_psk_snis.count].sni_match);
2530c87c5fbaSopenharmony_ci      }
2531c87c5fbaSopenharmony_ci    }
2532c87c5fbaSopenharmony_ci  }
2533c87c5fbaSopenharmony_ci  fclose(fp);
2534c87c5fbaSopenharmony_ci  return valid_psk_snis.count > 0;
2535c87c5fbaSopenharmony_ci}
2536c87c5fbaSopenharmony_ci
2537c87c5fbaSopenharmony_cistatic int
2538c87c5fbaSopenharmony_cicmdline_read_identity_check(char *arg) {
2539c87c5fbaSopenharmony_ci  FILE *fp = fopen(arg, "r");
2540c87c5fbaSopenharmony_ci  static char tmpbuf[256];
2541c87c5fbaSopenharmony_ci  if (fp == NULL) {
2542c87c5fbaSopenharmony_ci    coap_log_err("Identity file: %s: Unable to open\n", arg);
2543c87c5fbaSopenharmony_ci    return 0;
2544c87c5fbaSopenharmony_ci  }
2545c87c5fbaSopenharmony_ci  while (fgets(tmpbuf, sizeof(tmpbuf), fp) != NULL) {
2546c87c5fbaSopenharmony_ci    char *cp = tmpbuf;
2547c87c5fbaSopenharmony_ci    char *tcp = strchr(cp, '\n');
2548c87c5fbaSopenharmony_ci
2549c87c5fbaSopenharmony_ci    if (tmpbuf[0] == '#')
2550c87c5fbaSopenharmony_ci      continue;
2551c87c5fbaSopenharmony_ci    if (tcp)
2552c87c5fbaSopenharmony_ci      *tcp = '\000';
2553c87c5fbaSopenharmony_ci
2554c87c5fbaSopenharmony_ci    tcp = strchr(cp, ',');
2555c87c5fbaSopenharmony_ci    if (tcp) {
2556c87c5fbaSopenharmony_ci      id_def_t *new_id_list;
2557c87c5fbaSopenharmony_ci      new_id_list = realloc(valid_ids.id_list,
2558c87c5fbaSopenharmony_ci                            (valid_ids.count + 1)*sizeof(valid_ids.id_list[0]));
2559c87c5fbaSopenharmony_ci      if (new_id_list == NULL) {
2560c87c5fbaSopenharmony_ci        break;
2561c87c5fbaSopenharmony_ci      }
2562c87c5fbaSopenharmony_ci      valid_ids.id_list = new_id_list;
2563c87c5fbaSopenharmony_ci      valid_ids.id_list[valid_ids.count].hint_match = strndup(cp, tcp-cp);
2564c87c5fbaSopenharmony_ci      cp = tcp+1;
2565c87c5fbaSopenharmony_ci      tcp = strchr(cp, ',');
2566c87c5fbaSopenharmony_ci      if (tcp) {
2567c87c5fbaSopenharmony_ci        valid_ids.id_list[valid_ids.count].identity_match =
2568c87c5fbaSopenharmony_ci            coap_new_bin_const((const uint8_t *)cp, tcp-cp);
2569c87c5fbaSopenharmony_ci        cp = tcp+1;
2570c87c5fbaSopenharmony_ci        valid_ids.id_list[valid_ids.count].new_key =
2571c87c5fbaSopenharmony_ci            coap_new_bin_const((const uint8_t *)cp, strlen(cp));
2572c87c5fbaSopenharmony_ci        valid_ids.count++;
2573c87c5fbaSopenharmony_ci      } else {
2574c87c5fbaSopenharmony_ci        free(valid_ids.id_list[valid_ids.count].hint_match);
2575c87c5fbaSopenharmony_ci      }
2576c87c5fbaSopenharmony_ci    }
2577c87c5fbaSopenharmony_ci  }
2578c87c5fbaSopenharmony_ci  fclose(fp);
2579c87c5fbaSopenharmony_ci  return valid_ids.count > 0;
2580c87c5fbaSopenharmony_ci}
2581c87c5fbaSopenharmony_ci
2582c87c5fbaSopenharmony_cistatic int
2583c87c5fbaSopenharmony_cicmdline_unix(char *arg) {
2584c87c5fbaSopenharmony_ci  if (!strcmp("coap", arg)) {
2585c87c5fbaSopenharmony_ci    use_unix_proto = COAP_PROTO_UDP;
2586c87c5fbaSopenharmony_ci    return 1;
2587c87c5fbaSopenharmony_ci  } else if (!strcmp("coaps", arg)) {
2588c87c5fbaSopenharmony_ci    if (!coap_dtls_is_supported()) {
2589c87c5fbaSopenharmony_ci      coap_log_err("unix with dtls is not supported\n");
2590c87c5fbaSopenharmony_ci      return 0;
2591c87c5fbaSopenharmony_ci    }
2592c87c5fbaSopenharmony_ci    use_unix_proto = COAP_PROTO_DTLS;
2593c87c5fbaSopenharmony_ci    return 1;
2594c87c5fbaSopenharmony_ci  } else if (!strcmp("coap+tcp", arg)) {
2595c87c5fbaSopenharmony_ci    if (!coap_tcp_is_supported()) {
2596c87c5fbaSopenharmony_ci      coap_log_err("unix with stream is not supported\n");
2597c87c5fbaSopenharmony_ci      return 0;
2598c87c5fbaSopenharmony_ci    }
2599c87c5fbaSopenharmony_ci    use_unix_proto = COAP_PROTO_TCP;
2600c87c5fbaSopenharmony_ci    return 1;
2601c87c5fbaSopenharmony_ci  } else if (!strcmp("coaps+tcp", arg)) {
2602c87c5fbaSopenharmony_ci    if (!coap_tls_is_supported()) {
2603c87c5fbaSopenharmony_ci      coap_log_err("unix with tls is not supported\n");
2604c87c5fbaSopenharmony_ci      return 0;
2605c87c5fbaSopenharmony_ci    }
2606c87c5fbaSopenharmony_ci    use_unix_proto = COAP_PROTO_TLS;
2607c87c5fbaSopenharmony_ci    return 1;
2608c87c5fbaSopenharmony_ci  }
2609c87c5fbaSopenharmony_ci  return 0;
2610c87c5fbaSopenharmony_ci}
2611c87c5fbaSopenharmony_ci
2612c87c5fbaSopenharmony_cistatic int
2613c87c5fbaSopenharmony_cicmdline_ws(char *arg) {
2614c87c5fbaSopenharmony_ci  char *cp = strchr(arg, ',');
2615c87c5fbaSopenharmony_ci
2616c87c5fbaSopenharmony_ci  if (cp) {
2617c87c5fbaSopenharmony_ci    if (cp != arg)
2618c87c5fbaSopenharmony_ci      ws_port = atoi(arg);
2619c87c5fbaSopenharmony_ci    cp++;
2620c87c5fbaSopenharmony_ci    if (*cp != '\000')
2621c87c5fbaSopenharmony_ci      wss_port = atoi(cp);
2622c87c5fbaSopenharmony_ci  } else {
2623c87c5fbaSopenharmony_ci    ws_port = atoi(arg);
2624c87c5fbaSopenharmony_ci  }
2625c87c5fbaSopenharmony_ci  return 1;
2626c87c5fbaSopenharmony_ci}
2627c87c5fbaSopenharmony_ci
2628c87c5fbaSopenharmony_cistatic int
2629c87c5fbaSopenharmony_cicmdline_read_pki_sni_check(char *arg) {
2630c87c5fbaSopenharmony_ci  FILE *fp = fopen(arg, "r");
2631c87c5fbaSopenharmony_ci  static char tmpbuf[256];
2632c87c5fbaSopenharmony_ci  if (fp == NULL) {
2633c87c5fbaSopenharmony_ci    coap_log_err("SNI file: %s: Unable to open\n", arg);
2634c87c5fbaSopenharmony_ci    return 0;
2635c87c5fbaSopenharmony_ci  }
2636c87c5fbaSopenharmony_ci  while (fgets(tmpbuf, sizeof(tmpbuf), fp) != NULL) {
2637c87c5fbaSopenharmony_ci    char *cp = tmpbuf;
2638c87c5fbaSopenharmony_ci    char *tcp = strchr(cp, '\n');
2639c87c5fbaSopenharmony_ci
2640c87c5fbaSopenharmony_ci    if (tmpbuf[0] == '#')
2641c87c5fbaSopenharmony_ci      continue;
2642c87c5fbaSopenharmony_ci    if (tcp)
2643c87c5fbaSopenharmony_ci      *tcp = '\000';
2644c87c5fbaSopenharmony_ci
2645c87c5fbaSopenharmony_ci    tcp = strchr(cp, ',');
2646c87c5fbaSopenharmony_ci    if (tcp) {
2647c87c5fbaSopenharmony_ci      pki_sni_def_t *new_pki_sni_list;
2648c87c5fbaSopenharmony_ci      new_pki_sni_list = realloc(valid_pki_snis.pki_sni_list,
2649c87c5fbaSopenharmony_ci                                 (valid_pki_snis.count + 1)*sizeof(valid_pki_snis.pki_sni_list[0]));
2650c87c5fbaSopenharmony_ci      if (new_pki_sni_list == NULL) {
2651c87c5fbaSopenharmony_ci        break;
2652c87c5fbaSopenharmony_ci      }
2653c87c5fbaSopenharmony_ci      valid_pki_snis.pki_sni_list = new_pki_sni_list;
2654c87c5fbaSopenharmony_ci      valid_pki_snis.pki_sni_list[valid_pki_snis.count].sni_match =
2655c87c5fbaSopenharmony_ci          strndup(cp, tcp-cp);
2656c87c5fbaSopenharmony_ci      cp = tcp+1;
2657c87c5fbaSopenharmony_ci      tcp = strchr(cp, ',');
2658c87c5fbaSopenharmony_ci      if (tcp) {
2659c87c5fbaSopenharmony_ci        int fail = 0;
2660c87c5fbaSopenharmony_ci        valid_pki_snis.pki_sni_list[valid_pki_snis.count].new_cert =
2661c87c5fbaSopenharmony_ci            strndup(cp, tcp-cp);
2662c87c5fbaSopenharmony_ci        cp = tcp+1;
2663c87c5fbaSopenharmony_ci        valid_pki_snis.pki_sni_list[valid_pki_snis.count].new_ca =
2664c87c5fbaSopenharmony_ci            strndup(cp, strlen(cp));
2665c87c5fbaSopenharmony_ci        if (access(valid_pki_snis.pki_sni_list[valid_pki_snis.count].new_cert,
2666c87c5fbaSopenharmony_ci                   R_OK)) {
2667c87c5fbaSopenharmony_ci          coap_log_err("SNI file: Cert File: %s: Unable to access\n",
2668c87c5fbaSopenharmony_ci                       valid_pki_snis.pki_sni_list[valid_pki_snis.count].new_cert);
2669c87c5fbaSopenharmony_ci          fail = 1;
2670c87c5fbaSopenharmony_ci        }
2671c87c5fbaSopenharmony_ci        if (access(valid_pki_snis.pki_sni_list[valid_pki_snis.count].new_ca,
2672c87c5fbaSopenharmony_ci                   R_OK)) {
2673c87c5fbaSopenharmony_ci          coap_log_err("SNI file: CA File: %s: Unable to access\n",
2674c87c5fbaSopenharmony_ci                       valid_pki_snis.pki_sni_list[valid_pki_snis.count].new_ca);
2675c87c5fbaSopenharmony_ci          fail = 1;
2676c87c5fbaSopenharmony_ci        }
2677c87c5fbaSopenharmony_ci        if (fail) {
2678c87c5fbaSopenharmony_ci          free(valid_pki_snis.pki_sni_list[valid_pki_snis.count].sni_match);
2679c87c5fbaSopenharmony_ci          free(valid_pki_snis.pki_sni_list[valid_pki_snis.count].new_cert);
2680c87c5fbaSopenharmony_ci          free(valid_pki_snis.pki_sni_list[valid_pki_snis.count].new_ca);
2681c87c5fbaSopenharmony_ci        } else {
2682c87c5fbaSopenharmony_ci          valid_pki_snis.count++;
2683c87c5fbaSopenharmony_ci        }
2684c87c5fbaSopenharmony_ci      } else {
2685c87c5fbaSopenharmony_ci        coap_log_err("SNI file: SNI_match,Use_Cert_file,Use_CA_file not defined\n");
2686c87c5fbaSopenharmony_ci        free(valid_pki_snis.pki_sni_list[valid_pki_snis.count].sni_match);
2687c87c5fbaSopenharmony_ci      }
2688c87c5fbaSopenharmony_ci    }
2689c87c5fbaSopenharmony_ci  }
2690c87c5fbaSopenharmony_ci  fclose(fp);
2691c87c5fbaSopenharmony_ci  return valid_pki_snis.count > 0;
2692c87c5fbaSopenharmony_ci}
2693c87c5fbaSopenharmony_ci
2694c87c5fbaSopenharmony_cistatic int
2695c87c5fbaSopenharmony_cicmdline_read_extended_token_size(char *arg) {
2696c87c5fbaSopenharmony_ci  extended_token_size = strtoul(arg, NULL, 0);
2697c87c5fbaSopenharmony_ci  if (extended_token_size < COAP_TOKEN_DEFAULT_MAX) {
2698c87c5fbaSopenharmony_ci    coap_log_err("Extended Token Length must be 8 or greater\n");
2699c87c5fbaSopenharmony_ci    return 0;
2700c87c5fbaSopenharmony_ci  } else if (extended_token_size > COAP_TOKEN_EXT_MAX) {
2701c87c5fbaSopenharmony_ci    coap_log_err("Extended Token Length must be 65804 or less\n");
2702c87c5fbaSopenharmony_ci    return 0;
2703c87c5fbaSopenharmony_ci  }
2704c87c5fbaSopenharmony_ci  return 1;
2705c87c5fbaSopenharmony_ci}
2706c87c5fbaSopenharmony_ci
2707c87c5fbaSopenharmony_ciint
2708c87c5fbaSopenharmony_cimain(int argc, char **argv) {
2709c87c5fbaSopenharmony_ci  coap_context_t *ctx = NULL;
2710c87c5fbaSopenharmony_ci  char *group = NULL;
2711c87c5fbaSopenharmony_ci  char *group_if = NULL;
2712c87c5fbaSopenharmony_ci  coap_tick_t now;
2713c87c5fbaSopenharmony_ci  char addr_str[NI_MAXHOST] = "::";
2714c87c5fbaSopenharmony_ci  char *port_str = NULL;
2715c87c5fbaSopenharmony_ci  int opt;
2716c87c5fbaSopenharmony_ci  int mcast_per_resource = 0;
2717c87c5fbaSopenharmony_ci  coap_log_t log_level = COAP_LOG_WARN;
2718c87c5fbaSopenharmony_ci  coap_log_t dtls_log_level = COAP_LOG_ERR;
2719c87c5fbaSopenharmony_ci  unsigned wait_ms;
2720c87c5fbaSopenharmony_ci  coap_time_t t_last = 0;
2721c87c5fbaSopenharmony_ci  int coap_fd;
2722c87c5fbaSopenharmony_ci  fd_set m_readfds;
2723c87c5fbaSopenharmony_ci  int nfds = 0;
2724c87c5fbaSopenharmony_ci  size_t i;
2725c87c5fbaSopenharmony_ci  int exit_code = 0;
2726c87c5fbaSopenharmony_ci  uint16_t cache_ignore_options[] = { COAP_OPTION_BLOCK1,
2727c87c5fbaSopenharmony_ci                                      COAP_OPTION_BLOCK2,
2728c87c5fbaSopenharmony_ci                                      /* See https://rfc-editor.org/rfc/rfc7959#section-2.10 */
2729c87c5fbaSopenharmony_ci                                      COAP_OPTION_MAXAGE,
2730c87c5fbaSopenharmony_ci                                      /* See https://rfc-editor.org/rfc/rfc7959#section-2.10 */
2731c87c5fbaSopenharmony_ci                                      COAP_OPTION_IF_NONE_MATCH
2732c87c5fbaSopenharmony_ci                                    };
2733c87c5fbaSopenharmony_ci#ifndef _WIN32
2734c87c5fbaSopenharmony_ci  struct sigaction sa;
2735c87c5fbaSopenharmony_ci#endif
2736c87c5fbaSopenharmony_ci
2737c87c5fbaSopenharmony_ci  /* Initialize libcoap library */
2738c87c5fbaSopenharmony_ci  coap_startup();
2739c87c5fbaSopenharmony_ci
2740c87c5fbaSopenharmony_ci  clock_offset = time(NULL);
2741c87c5fbaSopenharmony_ci
2742c87c5fbaSopenharmony_ci  while ((opt = getopt(argc, argv,
2743c87c5fbaSopenharmony_ci                       "c:d:eg:G:h:i:j:J:k:l:mnp:rs:tu:v:w:A:C:E:L:M:NP:R:S:T:U:V:X:")) != -1) {
2744c87c5fbaSopenharmony_ci    switch (opt) {
2745c87c5fbaSopenharmony_ci    case 'A' :
2746c87c5fbaSopenharmony_ci      strncpy(addr_str, optarg, NI_MAXHOST-1);
2747c87c5fbaSopenharmony_ci      addr_str[NI_MAXHOST - 1] = '\0';
2748c87c5fbaSopenharmony_ci      break;
2749c87c5fbaSopenharmony_ci    case 'c' :
2750c87c5fbaSopenharmony_ci      cert_file = optarg;
2751c87c5fbaSopenharmony_ci      break;
2752c87c5fbaSopenharmony_ci    case 'C' :
2753c87c5fbaSopenharmony_ci      ca_file = optarg;
2754c87c5fbaSopenharmony_ci      break;
2755c87c5fbaSopenharmony_ci    case 'd' :
2756c87c5fbaSopenharmony_ci      support_dynamic = atoi(optarg);
2757c87c5fbaSopenharmony_ci      break;
2758c87c5fbaSopenharmony_ci    case 'e':
2759c87c5fbaSopenharmony_ci      echo_back = 1;
2760c87c5fbaSopenharmony_ci      break;
2761c87c5fbaSopenharmony_ci    case 'E':
2762c87c5fbaSopenharmony_ci      doing_oscore = cmdline_oscore(optarg);
2763c87c5fbaSopenharmony_ci      if (!doing_oscore) {
2764c87c5fbaSopenharmony_ci        goto failed;
2765c87c5fbaSopenharmony_ci      }
2766c87c5fbaSopenharmony_ci      break;
2767c87c5fbaSopenharmony_ci    case 'g' :
2768c87c5fbaSopenharmony_ci      group = optarg;
2769c87c5fbaSopenharmony_ci      break;
2770c87c5fbaSopenharmony_ci    case 'G' :
2771c87c5fbaSopenharmony_ci      group_if = optarg;
2772c87c5fbaSopenharmony_ci      break;
2773c87c5fbaSopenharmony_ci    case 'h' :
2774c87c5fbaSopenharmony_ci      if (!optarg[0]) {
2775c87c5fbaSopenharmony_ci        hint = NULL;
2776c87c5fbaSopenharmony_ci        break;
2777c87c5fbaSopenharmony_ci      }
2778c87c5fbaSopenharmony_ci      hint = optarg;
2779c87c5fbaSopenharmony_ci      break;
2780c87c5fbaSopenharmony_ci    case 'i':
2781c87c5fbaSopenharmony_ci      if (!cmdline_read_identity_check(optarg)) {
2782c87c5fbaSopenharmony_ci        usage(argv[0], LIBCOAP_PACKAGE_VERSION);
2783c87c5fbaSopenharmony_ci        goto failed;
2784c87c5fbaSopenharmony_ci      }
2785c87c5fbaSopenharmony_ci      break;
2786c87c5fbaSopenharmony_ci    case 'j' :
2787c87c5fbaSopenharmony_ci      key_file = optarg;
2788c87c5fbaSopenharmony_ci      break;
2789c87c5fbaSopenharmony_ci    case 'J' :
2790c87c5fbaSopenharmony_ci      pkcs11_pin = optarg;
2791c87c5fbaSopenharmony_ci      break;
2792c87c5fbaSopenharmony_ci    case 'k' :
2793c87c5fbaSopenharmony_ci      key_length = cmdline_read_key(optarg, &key, MAX_KEY);
2794c87c5fbaSopenharmony_ci      if (key_length < 0) {
2795c87c5fbaSopenharmony_ci        break;
2796c87c5fbaSopenharmony_ci      }
2797c87c5fbaSopenharmony_ci      key_defined = 1;
2798c87c5fbaSopenharmony_ci      break;
2799c87c5fbaSopenharmony_ci    case 'l':
2800c87c5fbaSopenharmony_ci      if (!coap_debug_set_packet_loss(optarg)) {
2801c87c5fbaSopenharmony_ci        usage(argv[0], LIBCOAP_PACKAGE_VERSION);
2802c87c5fbaSopenharmony_ci        goto failed;
2803c87c5fbaSopenharmony_ci      }
2804c87c5fbaSopenharmony_ci      break;
2805c87c5fbaSopenharmony_ci    case 'L':
2806c87c5fbaSopenharmony_ci      block_mode = strtoul(optarg, NULL, 0);
2807c87c5fbaSopenharmony_ci      if (!(block_mode & COAP_BLOCK_USE_LIBCOAP)) {
2808c87c5fbaSopenharmony_ci        fprintf(stderr, "Block mode must include COAP_BLOCK_USE_LIBCOAP (1)\n");
2809c87c5fbaSopenharmony_ci        goto failed;
2810c87c5fbaSopenharmony_ci      }
2811c87c5fbaSopenharmony_ci      break;
2812c87c5fbaSopenharmony_ci    case 'm':
2813c87c5fbaSopenharmony_ci      use_pem_buf = 1;
2814c87c5fbaSopenharmony_ci      break;
2815c87c5fbaSopenharmony_ci    case 'M':
2816c87c5fbaSopenharmony_ci      cert_file = optarg;
2817c87c5fbaSopenharmony_ci      is_rpk_not_cert = 1;
2818c87c5fbaSopenharmony_ci      break;
2819c87c5fbaSopenharmony_ci    case 'n':
2820c87c5fbaSopenharmony_ci      verify_peer_cert = 0;
2821c87c5fbaSopenharmony_ci      break;
2822c87c5fbaSopenharmony_ci    case 'N':
2823c87c5fbaSopenharmony_ci      resource_flags = COAP_RESOURCE_FLAGS_NOTIFY_NON;
2824c87c5fbaSopenharmony_ci      break;
2825c87c5fbaSopenharmony_ci    case 'p' :
2826c87c5fbaSopenharmony_ci      port_str = optarg;
2827c87c5fbaSopenharmony_ci      break;
2828c87c5fbaSopenharmony_ci    case 'P':
2829c87c5fbaSopenharmony_ci#if SERVER_CAN_PROXY
2830c87c5fbaSopenharmony_ci      if (!cmdline_proxy(optarg)) {
2831c87c5fbaSopenharmony_ci        fprintf(stderr, "error specifying proxy address or host names\n");
2832c87c5fbaSopenharmony_ci        goto failed;
2833c87c5fbaSopenharmony_ci      }
2834c87c5fbaSopenharmony_ci      block_mode |= COAP_BLOCK_SINGLE_BODY;
2835c87c5fbaSopenharmony_ci#else /* ! SERVER_CAN_PROXY */
2836c87c5fbaSopenharmony_ci      fprintf(stderr, "Proxy support not available as no Client mode code\n");
2837c87c5fbaSopenharmony_ci      goto failed;
2838c87c5fbaSopenharmony_ci#endif /* ! SERVER_CAN_PROXY */
2839c87c5fbaSopenharmony_ci      break;
2840c87c5fbaSopenharmony_ci    case 'r' :
2841c87c5fbaSopenharmony_ci      mcast_per_resource = 1;
2842c87c5fbaSopenharmony_ci      break;
2843c87c5fbaSopenharmony_ci    case 'R' :
2844c87c5fbaSopenharmony_ci      root_ca_file = optarg;
2845c87c5fbaSopenharmony_ci      break;
2846c87c5fbaSopenharmony_ci    case 's':
2847c87c5fbaSopenharmony_ci      if (!cmdline_read_psk_sni_check(optarg)) {
2848c87c5fbaSopenharmony_ci        goto failed;
2849c87c5fbaSopenharmony_ci      }
2850c87c5fbaSopenharmony_ci      break;
2851c87c5fbaSopenharmony_ci    case 'S':
2852c87c5fbaSopenharmony_ci      if (!cmdline_read_pki_sni_check(optarg)) {
2853c87c5fbaSopenharmony_ci        goto failed;
2854c87c5fbaSopenharmony_ci      }
2855c87c5fbaSopenharmony_ci      break;
2856c87c5fbaSopenharmony_ci    case 'T':
2857c87c5fbaSopenharmony_ci      if (!cmdline_read_extended_token_size(optarg)) {
2858c87c5fbaSopenharmony_ci        goto failed;
2859c87c5fbaSopenharmony_ci      }
2860c87c5fbaSopenharmony_ci      break;
2861c87c5fbaSopenharmony_ci    case 't':
2862c87c5fbaSopenharmony_ci      track_observes = 1;
2863c87c5fbaSopenharmony_ci      break;
2864c87c5fbaSopenharmony_ci    case 'u':
2865c87c5fbaSopenharmony_ci#if SERVER_CAN_PROXY
2866c87c5fbaSopenharmony_ci      user_length = cmdline_read_user(optarg, &user, MAX_USER);
2867c87c5fbaSopenharmony_ci#else /* ! SERVER_CAN_PROXY */
2868c87c5fbaSopenharmony_ci      fprintf(stderr, "Proxy support not available as no Client mode code\n");
2869c87c5fbaSopenharmony_ci      goto failed;
2870c87c5fbaSopenharmony_ci#endif /* ! SERVER_CAN_PROXY */
2871c87c5fbaSopenharmony_ci      break;
2872c87c5fbaSopenharmony_ci    case 'U':
2873c87c5fbaSopenharmony_ci      if (!cmdline_unix(optarg)) {
2874c87c5fbaSopenharmony_ci        usage(argv[0], LIBCOAP_PACKAGE_VERSION);
2875c87c5fbaSopenharmony_ci        goto failed;
2876c87c5fbaSopenharmony_ci      }
2877c87c5fbaSopenharmony_ci      break;
2878c87c5fbaSopenharmony_ci    case 'v' :
2879c87c5fbaSopenharmony_ci      log_level = strtol(optarg, NULL, 10);
2880c87c5fbaSopenharmony_ci      break;
2881c87c5fbaSopenharmony_ci    case 'V':
2882c87c5fbaSopenharmony_ci      dtls_log_level = strtol(optarg, NULL, 10);
2883c87c5fbaSopenharmony_ci      break;
2884c87c5fbaSopenharmony_ci    case 'w':
2885c87c5fbaSopenharmony_ci      if (!coap_ws_is_supported() || !cmdline_ws(optarg)) {
2886c87c5fbaSopenharmony_ci        fprintf(stderr, "WebSockets not enabled in libcoap\n");
2887c87c5fbaSopenharmony_ci        exit(1);
2888c87c5fbaSopenharmony_ci      }
2889c87c5fbaSopenharmony_ci      enable_ws = 1;
2890c87c5fbaSopenharmony_ci      break;
2891c87c5fbaSopenharmony_ci    case 'X':
2892c87c5fbaSopenharmony_ci      csm_max_message_size = strtol(optarg, NULL, 10);
2893c87c5fbaSopenharmony_ci      break;
2894c87c5fbaSopenharmony_ci    default:
2895c87c5fbaSopenharmony_ci      usage(argv[0], LIBCOAP_PACKAGE_VERSION);
2896c87c5fbaSopenharmony_ci      goto failed;
2897c87c5fbaSopenharmony_ci    }
2898c87c5fbaSopenharmony_ci  }
2899c87c5fbaSopenharmony_ci
2900c87c5fbaSopenharmony_ci#ifdef _WIN32
2901c87c5fbaSopenharmony_ci  signal(SIGINT, handle_sigint);
2902c87c5fbaSopenharmony_ci#else
2903c87c5fbaSopenharmony_ci  memset(&sa, 0, sizeof(sa));
2904c87c5fbaSopenharmony_ci  sigemptyset(&sa.sa_mask);
2905c87c5fbaSopenharmony_ci  sa.sa_handler = handle_sigint;
2906c87c5fbaSopenharmony_ci  sa.sa_flags = 0;
2907c87c5fbaSopenharmony_ci  sigaction(SIGINT, &sa, NULL);
2908c87c5fbaSopenharmony_ci  sigaction(SIGTERM, &sa, NULL);
2909c87c5fbaSopenharmony_ci  sa.sa_handler = handle_sigusr2;
2910c87c5fbaSopenharmony_ci  sigaction(SIGUSR2, &sa, NULL);
2911c87c5fbaSopenharmony_ci  /* So we do not exit on a SIGPIPE */
2912c87c5fbaSopenharmony_ci  sa.sa_handler = SIG_IGN;
2913c87c5fbaSopenharmony_ci  sigaction(SIGPIPE, &sa, NULL);
2914c87c5fbaSopenharmony_ci#endif
2915c87c5fbaSopenharmony_ci
2916c87c5fbaSopenharmony_ci  coap_set_log_level(log_level);
2917c87c5fbaSopenharmony_ci  coap_dtls_set_log_level(dtls_log_level);
2918c87c5fbaSopenharmony_ci
2919c87c5fbaSopenharmony_ci  ctx = get_context(addr_str, port_str);
2920c87c5fbaSopenharmony_ci  if (!ctx)
2921c87c5fbaSopenharmony_ci    return -1;
2922c87c5fbaSopenharmony_ci
2923c87c5fbaSopenharmony_ci  init_resources(ctx);
2924c87c5fbaSopenharmony_ci  if (mcast_per_resource)
2925c87c5fbaSopenharmony_ci    coap_mcast_per_resource(ctx);
2926c87c5fbaSopenharmony_ci  coap_context_set_block_mode(ctx, block_mode);
2927c87c5fbaSopenharmony_ci  if (csm_max_message_size)
2928c87c5fbaSopenharmony_ci    coap_context_set_csm_max_message_size(ctx, csm_max_message_size);
2929c87c5fbaSopenharmony_ci  if (doing_oscore) {
2930c87c5fbaSopenharmony_ci    if (get_oscore_conf(ctx) == NULL)
2931c87c5fbaSopenharmony_ci      goto failed;
2932c87c5fbaSopenharmony_ci  }
2933c87c5fbaSopenharmony_ci  if (extended_token_size > COAP_TOKEN_DEFAULT_MAX)
2934c87c5fbaSopenharmony_ci    coap_context_set_max_token_size(ctx, extended_token_size);
2935c87c5fbaSopenharmony_ci
2936c87c5fbaSopenharmony_ci  /* Define the options to ignore when setting up cache-keys */
2937c87c5fbaSopenharmony_ci  coap_cache_ignore_options(ctx, cache_ignore_options,
2938c87c5fbaSopenharmony_ci                            sizeof(cache_ignore_options)/sizeof(cache_ignore_options[0]));
2939c87c5fbaSopenharmony_ci  /* join multicast group if requested at command line */
2940c87c5fbaSopenharmony_ci  if (group)
2941c87c5fbaSopenharmony_ci    coap_join_mcast_group_intf(ctx, group, group_if);
2942c87c5fbaSopenharmony_ci
2943c87c5fbaSopenharmony_ci  if (track_observes) {
2944c87c5fbaSopenharmony_ci    /*
2945c87c5fbaSopenharmony_ci     * Read in and set up appropriate persist information.
2946c87c5fbaSopenharmony_ci     * Note that this should be done after ctx is properly set up.
2947c87c5fbaSopenharmony_ci     */
2948c87c5fbaSopenharmony_ci    if (!coap_persist_startup(ctx,
2949c87c5fbaSopenharmony_ci                              "/tmp/coap_dyn_resource_save_file",
2950c87c5fbaSopenharmony_ci                              "/tmp/coap_observe_save_file",
2951c87c5fbaSopenharmony_ci                              "/tmp/coap_obs_cnt_save_file", 10)) {
2952c87c5fbaSopenharmony_ci      fprintf(stderr, "Unable to set up persist logic\n");
2953c87c5fbaSopenharmony_ci      goto finish;
2954c87c5fbaSopenharmony_ci    }
2955c87c5fbaSopenharmony_ci  }
2956c87c5fbaSopenharmony_ci
2957c87c5fbaSopenharmony_ci  coap_fd = coap_context_get_coap_fd(ctx);
2958c87c5fbaSopenharmony_ci  if (coap_fd != -1) {
2959c87c5fbaSopenharmony_ci    /* if coap_fd is -1, then epoll is not supported within libcoap */
2960c87c5fbaSopenharmony_ci    FD_ZERO(&m_readfds);
2961c87c5fbaSopenharmony_ci    FD_SET(coap_fd, &m_readfds);
2962c87c5fbaSopenharmony_ci    nfds = coap_fd + 1;
2963c87c5fbaSopenharmony_ci  }
2964c87c5fbaSopenharmony_ci
2965c87c5fbaSopenharmony_ci  wait_ms = COAP_RESOURCE_CHECK_TIME * 1000;
2966c87c5fbaSopenharmony_ci
2967c87c5fbaSopenharmony_ci  while (!quit) {
2968c87c5fbaSopenharmony_ci    int result;
2969c87c5fbaSopenharmony_ci
2970c87c5fbaSopenharmony_ci    if (coap_fd != -1) {
2971c87c5fbaSopenharmony_ci      /*
2972c87c5fbaSopenharmony_ci       * Using epoll.  It is more usual to call coap_io_process() with wait_ms
2973c87c5fbaSopenharmony_ci       * (as in the non-epoll branch), but doing it this way gives the
2974c87c5fbaSopenharmony_ci       * flexibility of potentially working with other file descriptors that
2975c87c5fbaSopenharmony_ci       * are not a part of libcoap.
2976c87c5fbaSopenharmony_ci       */
2977c87c5fbaSopenharmony_ci      fd_set readfds = m_readfds;
2978c87c5fbaSopenharmony_ci      struct timeval tv;
2979c87c5fbaSopenharmony_ci      coap_tick_t begin, end;
2980c87c5fbaSopenharmony_ci
2981c87c5fbaSopenharmony_ci      coap_ticks(&begin);
2982c87c5fbaSopenharmony_ci
2983c87c5fbaSopenharmony_ci      tv.tv_sec = wait_ms / 1000;
2984c87c5fbaSopenharmony_ci      tv.tv_usec = (wait_ms % 1000) * 1000;
2985c87c5fbaSopenharmony_ci      /* Wait until any i/o takes place or timeout */
2986c87c5fbaSopenharmony_ci      result = select(nfds, &readfds, NULL, NULL, &tv);
2987c87c5fbaSopenharmony_ci      if (result == -1) {
2988c87c5fbaSopenharmony_ci        if (errno != EAGAIN) {
2989c87c5fbaSopenharmony_ci          coap_log_debug("select: %s (%d)\n", coap_socket_strerror(), errno);
2990c87c5fbaSopenharmony_ci          break;
2991c87c5fbaSopenharmony_ci        }
2992c87c5fbaSopenharmony_ci      }
2993c87c5fbaSopenharmony_ci      if (result > 0) {
2994c87c5fbaSopenharmony_ci        if (FD_ISSET(coap_fd, &readfds)) {
2995c87c5fbaSopenharmony_ci          result = coap_io_process(ctx, COAP_IO_NO_WAIT);
2996c87c5fbaSopenharmony_ci        }
2997c87c5fbaSopenharmony_ci      }
2998c87c5fbaSopenharmony_ci      if (result >= 0) {
2999c87c5fbaSopenharmony_ci        coap_ticks(&end);
3000c87c5fbaSopenharmony_ci        /* Track the overall time spent in select() and coap_io_process() */
3001c87c5fbaSopenharmony_ci        result = (int)(end - begin);
3002c87c5fbaSopenharmony_ci      }
3003c87c5fbaSopenharmony_ci    } else {
3004c87c5fbaSopenharmony_ci      /*
3005c87c5fbaSopenharmony_ci       * epoll is not supported within libcoap
3006c87c5fbaSopenharmony_ci       *
3007c87c5fbaSopenharmony_ci       * result is time spent in coap_io_process()
3008c87c5fbaSopenharmony_ci       */
3009c87c5fbaSopenharmony_ci      result = coap_io_process(ctx, wait_ms);
3010c87c5fbaSopenharmony_ci    }
3011c87c5fbaSopenharmony_ci    if (result < 0) {
3012c87c5fbaSopenharmony_ci      break;
3013c87c5fbaSopenharmony_ci    } else if (result && (unsigned)result < wait_ms) {
3014c87c5fbaSopenharmony_ci      /* decrement if there is a result wait time returned */
3015c87c5fbaSopenharmony_ci      wait_ms -= result;
3016c87c5fbaSopenharmony_ci    } else {
3017c87c5fbaSopenharmony_ci      /*
3018c87c5fbaSopenharmony_ci       * result == 0, or result >= wait_ms
3019c87c5fbaSopenharmony_ci       * (wait_ms could have decremented to a small value, below
3020c87c5fbaSopenharmony_ci       * the granularity of the timer in coap_io_process() and hence
3021c87c5fbaSopenharmony_ci       * result == 0)
3022c87c5fbaSopenharmony_ci       */
3023c87c5fbaSopenharmony_ci      wait_ms = COAP_RESOURCE_CHECK_TIME * 1000;
3024c87c5fbaSopenharmony_ci    }
3025c87c5fbaSopenharmony_ci    if (time_resource) {
3026c87c5fbaSopenharmony_ci      coap_time_t t_now;
3027c87c5fbaSopenharmony_ci      unsigned int next_sec_ms;
3028c87c5fbaSopenharmony_ci
3029c87c5fbaSopenharmony_ci      coap_ticks(&now);
3030c87c5fbaSopenharmony_ci      t_now = coap_ticks_to_rt(now);
3031c87c5fbaSopenharmony_ci      if (t_last != t_now) {
3032c87c5fbaSopenharmony_ci        /* Happens once per second */
3033c87c5fbaSopenharmony_ci        t_last = t_now;
3034c87c5fbaSopenharmony_ci        coap_resource_notify_observers(time_resource, NULL);
3035c87c5fbaSopenharmony_ci      }
3036c87c5fbaSopenharmony_ci      /* need to wait until next second starts if wait_ms is too large */
3037c87c5fbaSopenharmony_ci      next_sec_ms = 1000 - (now % COAP_TICKS_PER_SECOND) *
3038c87c5fbaSopenharmony_ci                    1000 / COAP_TICKS_PER_SECOND;
3039c87c5fbaSopenharmony_ci      if (next_sec_ms && next_sec_ms < wait_ms)
3040c87c5fbaSopenharmony_ci        wait_ms = next_sec_ms;
3041c87c5fbaSopenharmony_ci    }
3042c87c5fbaSopenharmony_ci  }
3043c87c5fbaSopenharmony_ci  exit_code = 0;
3044c87c5fbaSopenharmony_ci
3045c87c5fbaSopenharmony_cifinish:
3046c87c5fbaSopenharmony_ci  /* Clean up local usage */
3047c87c5fbaSopenharmony_ci  if (keep_persist)
3048c87c5fbaSopenharmony_ci    coap_persist_stop(ctx);
3049c87c5fbaSopenharmony_ci
3050c87c5fbaSopenharmony_ci  coap_free(ca_mem);
3051c87c5fbaSopenharmony_ci  coap_free(cert_mem);
3052c87c5fbaSopenharmony_ci  coap_free(key_mem);
3053c87c5fbaSopenharmony_ci  coap_free(ca_mem_base);
3054c87c5fbaSopenharmony_ci  coap_free(cert_mem_base);
3055c87c5fbaSopenharmony_ci  coap_free(key_mem_base);
3056c87c5fbaSopenharmony_ci  for (i = 0; i < valid_psk_snis.count; i++) {
3057c87c5fbaSopenharmony_ci    free(valid_psk_snis.psk_sni_list[i].sni_match);
3058c87c5fbaSopenharmony_ci    coap_delete_bin_const(valid_psk_snis.psk_sni_list[i].new_hint);
3059c87c5fbaSopenharmony_ci    coap_delete_bin_const(valid_psk_snis.psk_sni_list[i].new_key);
3060c87c5fbaSopenharmony_ci  }
3061c87c5fbaSopenharmony_ci  if (valid_psk_snis.count)
3062c87c5fbaSopenharmony_ci    free(valid_psk_snis.psk_sni_list);
3063c87c5fbaSopenharmony_ci
3064c87c5fbaSopenharmony_ci  for (i = 0; i < valid_ids.count; i++) {
3065c87c5fbaSopenharmony_ci    free(valid_ids.id_list[i].hint_match);
3066c87c5fbaSopenharmony_ci    coap_delete_bin_const(valid_ids.id_list[i].identity_match);
3067c87c5fbaSopenharmony_ci    coap_delete_bin_const(valid_ids.id_list[i].new_key);
3068c87c5fbaSopenharmony_ci  }
3069c87c5fbaSopenharmony_ci  if (valid_ids.count)
3070c87c5fbaSopenharmony_ci    free(valid_ids.id_list);
3071c87c5fbaSopenharmony_ci
3072c87c5fbaSopenharmony_ci  for (i = 0; i < valid_pki_snis.count; i++) {
3073c87c5fbaSopenharmony_ci    free(valid_pki_snis.pki_sni_list[i].sni_match);
3074c87c5fbaSopenharmony_ci    free(valid_pki_snis.pki_sni_list[i].new_cert);
3075c87c5fbaSopenharmony_ci    free(valid_pki_snis.pki_sni_list[i].new_ca);
3076c87c5fbaSopenharmony_ci  }
3077c87c5fbaSopenharmony_ci  if (valid_pki_snis.count)
3078c87c5fbaSopenharmony_ci    free(valid_pki_snis.pki_sni_list);
3079c87c5fbaSopenharmony_ci
3080c87c5fbaSopenharmony_ci  for (i = 0; i < (size_t)dynamic_count; i++) {
3081c87c5fbaSopenharmony_ci    coap_delete_string(dynamic_entry[i].uri_path);
3082c87c5fbaSopenharmony_ci    release_resource_data(NULL, dynamic_entry[i].value);
3083c87c5fbaSopenharmony_ci  }
3084c87c5fbaSopenharmony_ci  free(dynamic_entry);
3085c87c5fbaSopenharmony_ci  release_resource_data(NULL, example_data_value);
3086c87c5fbaSopenharmony_ci#if SERVER_CAN_PROXY
3087c87c5fbaSopenharmony_ci  for (i = 0; i < proxy_list_count; i++) {
3088c87c5fbaSopenharmony_ci    coap_delete_binary(proxy_list[i].token);
3089c87c5fbaSopenharmony_ci    coap_delete_string(proxy_list[i].query);
3090c87c5fbaSopenharmony_ci  }
3091c87c5fbaSopenharmony_ci  free(proxy_list);
3092c87c5fbaSopenharmony_ci  proxy_list = NULL;
3093c87c5fbaSopenharmony_ci  proxy_list_count = 0;
3094c87c5fbaSopenharmony_ci#if defined(_WIN32) && !defined(__MINGW32__)
3095c87c5fbaSopenharmony_ci#pragma warning( disable : 4090 )
3096c87c5fbaSopenharmony_ci#endif
3097c87c5fbaSopenharmony_ci  coap_free(proxy_host_name_list);
3098c87c5fbaSopenharmony_ci#endif /* SERVER_CAN_PROXY */
3099c87c5fbaSopenharmony_ci  if (oscore_seq_num_fp)
3100c87c5fbaSopenharmony_ci    fclose(oscore_seq_num_fp);
3101c87c5fbaSopenharmony_ci
3102c87c5fbaSopenharmony_ci  /* Clean up library usage */
3103c87c5fbaSopenharmony_ci  coap_free_context(ctx);
3104c87c5fbaSopenharmony_ci  coap_cleanup();
3105c87c5fbaSopenharmony_ci
3106c87c5fbaSopenharmony_ci  return exit_code;
3107c87c5fbaSopenharmony_ci
3108c87c5fbaSopenharmony_cifailed:
3109c87c5fbaSopenharmony_ci  exit_code = 1;
3110c87c5fbaSopenharmony_ci  goto finish;
3111c87c5fbaSopenharmony_ci}
3112