1c87c5fbaSopenharmony_ci/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2c87c5fbaSopenharmony_ci
3c87c5fbaSopenharmony_ci/* coap-client -- simple CoAP client
4c87c5fbaSopenharmony_ci *
5c87c5fbaSopenharmony_ci * Copyright (C) 2010--2023 Olaf Bergmann <bergmann@tzi.org> and others
6c87c5fbaSopenharmony_ci *
7c87c5fbaSopenharmony_ci * SPDX-License-Identifier: BSD-2-Clause
8c87c5fbaSopenharmony_ci *
9c87c5fbaSopenharmony_ci * This file is part of the CoAP library libcoap. Please see README for terms of
10c87c5fbaSopenharmony_ci * use.
11c87c5fbaSopenharmony_ci */
12c87c5fbaSopenharmony_ci
13c87c5fbaSopenharmony_ci#include <string.h>
14c87c5fbaSopenharmony_ci#include <stdlib.h>
15c87c5fbaSopenharmony_ci#include <stdio.h>
16c87c5fbaSopenharmony_ci#include <ctype.h>
17c87c5fbaSopenharmony_ci#include <signal.h>
18c87c5fbaSopenharmony_ci#include <inttypes.h>
19c87c5fbaSopenharmony_ci#include <sys/types.h>
20c87c5fbaSopenharmony_ci#include <sys/stat.h>
21c87c5fbaSopenharmony_ci#ifdef _WIN32
22c87c5fbaSopenharmony_ci#define strcasecmp _stricmp
23c87c5fbaSopenharmony_ci#define strncasecmp _strnicmp
24c87c5fbaSopenharmony_ci#define fileno _fileno
25c87c5fbaSopenharmony_ci#define getpid GetCurrentProcessId
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_cichar *strndup(const char *s1, size_t n);
31c87c5fbaSopenharmony_cichar *
32c87c5fbaSopenharmony_cistrndup(const char *s1, size_t n) {
33c87c5fbaSopenharmony_ci  char *copy = (char *)malloc(n + 1);
34c87c5fbaSopenharmony_ci  if (copy) {
35c87c5fbaSopenharmony_ci    memcpy(copy, s1, n);
36c87c5fbaSopenharmony_ci    copy[n] = 0;
37c87c5fbaSopenharmony_ci  }
38c87c5fbaSopenharmony_ci  return copy;
39c87c5fbaSopenharmony_ci}
40c87c5fbaSopenharmony_ci#else
41c87c5fbaSopenharmony_ci#include <unistd.h>
42c87c5fbaSopenharmony_ci#include <sys/select.h>
43c87c5fbaSopenharmony_ci#include <sys/socket.h>
44c87c5fbaSopenharmony_ci#include <netinet/in.h>
45c87c5fbaSopenharmony_ci#include <arpa/inet.h>
46c87c5fbaSopenharmony_ci#include <netdb.h>
47c87c5fbaSopenharmony_ci#include <syslog.h>
48c87c5fbaSopenharmony_ci#endif
49c87c5fbaSopenharmony_ci
50c87c5fbaSopenharmony_ci#include <coap3/coap.h>
51c87c5fbaSopenharmony_ci
52c87c5fbaSopenharmony_ci#define MAX_USER 128 /* Maximum length of a user name (i.e., PSK
53c87c5fbaSopenharmony_ci                      * identity) in bytes. */
54c87c5fbaSopenharmony_ci#define MAX_KEY   64 /* Maximum length of a key (i.e., PSK) in bytes. */
55c87c5fbaSopenharmony_ci
56c87c5fbaSopenharmony_ciint flags = 0;
57c87c5fbaSopenharmony_ci
58c87c5fbaSopenharmony_cistatic unsigned char _token_data[24]; /* With support for RFC8974 */
59c87c5fbaSopenharmony_cicoap_binary_t the_token = { 0, _token_data };
60c87c5fbaSopenharmony_ci
61c87c5fbaSopenharmony_citypedef struct {
62c87c5fbaSopenharmony_ci  coap_binary_t *token;
63c87c5fbaSopenharmony_ci  int observe;
64c87c5fbaSopenharmony_ci} track_token;
65c87c5fbaSopenharmony_ci
66c87c5fbaSopenharmony_citrack_token *tracked_tokens = NULL;
67c87c5fbaSopenharmony_cisize_t tracked_tokens_count = 0;
68c87c5fbaSopenharmony_ci
69c87c5fbaSopenharmony_ci#define FLAGS_BLOCK 0x01
70c87c5fbaSopenharmony_ci
71c87c5fbaSopenharmony_cistatic coap_optlist_t *optlist = NULL;
72c87c5fbaSopenharmony_ci/* Request URI.
73c87c5fbaSopenharmony_ci * TODO: associate the resources with transaction id and make it expireable */
74c87c5fbaSopenharmony_cistatic coap_uri_t uri;
75c87c5fbaSopenharmony_cistatic coap_uri_t proxy = { {0, NULL}, 0, {0, NULL}, {0, NULL}, 0 };
76c87c5fbaSopenharmony_cistatic int proxy_scheme_option = 0;
77c87c5fbaSopenharmony_cistatic int uri_host_option = 0;
78c87c5fbaSopenharmony_cistatic unsigned int ping_seconds = 0;
79c87c5fbaSopenharmony_ci
80c87c5fbaSopenharmony_ci#define REPEAT_DELAY_MS 1000
81c87c5fbaSopenharmony_cistatic size_t repeat_count = 1;
82c87c5fbaSopenharmony_ci
83c87c5fbaSopenharmony_ci/* reading is done when this flag is set */
84c87c5fbaSopenharmony_cistatic int ready = 0;
85c87c5fbaSopenharmony_ci
86c87c5fbaSopenharmony_ci/* processing a block response when this flag is set */
87c87c5fbaSopenharmony_cistatic int doing_getting_block = 0;
88c87c5fbaSopenharmony_cistatic int single_block_requested = 0;
89c87c5fbaSopenharmony_cistatic uint32_t block_mode = COAP_BLOCK_USE_LIBCOAP;
90c87c5fbaSopenharmony_ci
91c87c5fbaSopenharmony_cistatic coap_string_t output_file = { 0, NULL };   /* output file name */
92c87c5fbaSopenharmony_cistatic FILE *file = NULL;               /* output file stream */
93c87c5fbaSopenharmony_ci
94c87c5fbaSopenharmony_cistatic coap_string_t payload = { 0, NULL };       /* optional payload to send */
95c87c5fbaSopenharmony_ci
96c87c5fbaSopenharmony_cistatic int reliable = 0;
97c87c5fbaSopenharmony_ci
98c87c5fbaSopenharmony_cistatic int add_nl = 0;
99c87c5fbaSopenharmony_cistatic int is_mcast = 0;
100c87c5fbaSopenharmony_cistatic uint32_t csm_max_message_size = 0;
101c87c5fbaSopenharmony_ci
102c87c5fbaSopenharmony_ciunsigned char msgtype = COAP_MESSAGE_CON; /* usually, requests are sent confirmable */
103c87c5fbaSopenharmony_ci
104c87c5fbaSopenharmony_cistatic char *cert_file = NULL; /* certificate and optional private key in PEM,
105c87c5fbaSopenharmony_ci                                  or PKCS11 URI*/
106c87c5fbaSopenharmony_cistatic char *key_file = NULL; /* private key in PEM, DER or PKCS11 URI */
107c87c5fbaSopenharmony_cistatic char *pkcs11_pin = NULL; /* PKCS11 pin to unlock access to token */
108c87c5fbaSopenharmony_cistatic char *ca_file = NULL;   /* CA for cert_file - for cert checking in PEM,
109c87c5fbaSopenharmony_ci                                  DER or PKCS11 URI */
110c87c5fbaSopenharmony_cistatic char *root_ca_file = NULL; /* List of trusted Root CAs in PEM */
111c87c5fbaSopenharmony_cistatic int is_rpk_not_cert = 0; /* Cert is RPK if set */
112c87c5fbaSopenharmony_cistatic uint8_t *cert_mem = NULL; /* certificate and private key in PEM_BUF */
113c87c5fbaSopenharmony_cistatic uint8_t *key_mem = NULL; /* private key in PEM_BUF */
114c87c5fbaSopenharmony_cistatic uint8_t *ca_mem = NULL;   /* CA for cert checking in PEM_BUF */
115c87c5fbaSopenharmony_cistatic size_t cert_mem_len = 0;
116c87c5fbaSopenharmony_cistatic size_t key_mem_len = 0;
117c87c5fbaSopenharmony_cistatic size_t ca_mem_len = 0;
118c87c5fbaSopenharmony_cistatic int verify_peer_cert = 1; /* PKI granularity - by default set */
119c87c5fbaSopenharmony_ci
120c87c5fbaSopenharmony_citypedef struct ih_def_t {
121c87c5fbaSopenharmony_ci  char *hint_match;
122c87c5fbaSopenharmony_ci  coap_bin_const_t *new_identity;
123c87c5fbaSopenharmony_ci  coap_bin_const_t *new_key;
124c87c5fbaSopenharmony_ci} ih_def_t;
125c87c5fbaSopenharmony_ci
126c87c5fbaSopenharmony_citypedef struct valid_ihs_t {
127c87c5fbaSopenharmony_ci  size_t count;
128c87c5fbaSopenharmony_ci  ih_def_t *ih_list;
129c87c5fbaSopenharmony_ci} valid_ihs_t;
130c87c5fbaSopenharmony_ci
131c87c5fbaSopenharmony_cistatic valid_ihs_t valid_ihs = {0, NULL};
132c87c5fbaSopenharmony_ci
133c87c5fbaSopenharmony_citypedef unsigned char method_t;
134c87c5fbaSopenharmony_cimethod_t method = 1;                    /* the method we are using in our requests */
135c87c5fbaSopenharmony_ci
136c87c5fbaSopenharmony_cicoap_block_t block = { .num = 0, .m = 0, .szx = 6 };
137c87c5fbaSopenharmony_ciuint16_t last_block1_mid = 0;
138c87c5fbaSopenharmony_ci
139c87c5fbaSopenharmony_ci#define DEFAULT_WAIT_TIME 90
140c87c5fbaSopenharmony_ci
141c87c5fbaSopenharmony_ciunsigned int wait_seconds = DEFAULT_WAIT_TIME; /* default timeout in seconds */
142c87c5fbaSopenharmony_ciunsigned int wait_ms = 0;
143c87c5fbaSopenharmony_ciint obs_started = 0;
144c87c5fbaSopenharmony_ciunsigned int obs_seconds = 30;          /* default observe time */
145c87c5fbaSopenharmony_ciunsigned int obs_ms = 0;                /* timeout for current subscription */
146c87c5fbaSopenharmony_ciint obs_ms_reset = 0;
147c87c5fbaSopenharmony_ciint doing_observe = 0;
148c87c5fbaSopenharmony_ci
149c87c5fbaSopenharmony_ci#ifndef min
150c87c5fbaSopenharmony_ci#define min(a,b) ((a) < (b) ? (a) : (b))
151c87c5fbaSopenharmony_ci#endif
152c87c5fbaSopenharmony_ci
153c87c5fbaSopenharmony_cistatic coap_oscore_conf_t *oscore_conf = NULL;
154c87c5fbaSopenharmony_cistatic int doing_oscore = 0;
155c87c5fbaSopenharmony_ci
156c87c5fbaSopenharmony_cistatic int quit = 0;
157c87c5fbaSopenharmony_ci
158c87c5fbaSopenharmony_ci/* SIGINT handler: set quit to 1 for graceful termination */
159c87c5fbaSopenharmony_cistatic void
160c87c5fbaSopenharmony_cihandle_sigint(int signum COAP_UNUSED) {
161c87c5fbaSopenharmony_ci  quit = 1;
162c87c5fbaSopenharmony_ci}
163c87c5fbaSopenharmony_ci
164c87c5fbaSopenharmony_cistatic int
165c87c5fbaSopenharmony_ciappend_to_output(const uint8_t *data, size_t len) {
166c87c5fbaSopenharmony_ci  size_t written;
167c87c5fbaSopenharmony_ci
168c87c5fbaSopenharmony_ci  if (!file) {
169c87c5fbaSopenharmony_ci    if (!output_file.s || (output_file.length && output_file.s[0] == '-')) {
170c87c5fbaSopenharmony_ci      file = stdout;
171c87c5fbaSopenharmony_ci    } else {
172c87c5fbaSopenharmony_ci      if (!(file = fopen((char *)output_file.s, "w"))) {
173c87c5fbaSopenharmony_ci        perror("fopen");
174c87c5fbaSopenharmony_ci        return -1;
175c87c5fbaSopenharmony_ci      }
176c87c5fbaSopenharmony_ci    }
177c87c5fbaSopenharmony_ci  }
178c87c5fbaSopenharmony_ci
179c87c5fbaSopenharmony_ci  do {
180c87c5fbaSopenharmony_ci    written = fwrite(data, 1, len, file);
181c87c5fbaSopenharmony_ci    len -= written;
182c87c5fbaSopenharmony_ci    data += written;
183c87c5fbaSopenharmony_ci  } while (written && len);
184c87c5fbaSopenharmony_ci  fflush(file);
185c87c5fbaSopenharmony_ci
186c87c5fbaSopenharmony_ci  return 0;
187c87c5fbaSopenharmony_ci}
188c87c5fbaSopenharmony_ci
189c87c5fbaSopenharmony_cistatic void
190c87c5fbaSopenharmony_ciclose_output(void) {
191c87c5fbaSopenharmony_ci  if (file) {
192c87c5fbaSopenharmony_ci
193c87c5fbaSopenharmony_ci    /* add a newline before closing if no option '-o' was specified */
194c87c5fbaSopenharmony_ci    if (!output_file.s)
195c87c5fbaSopenharmony_ci      (void)fwrite("\n", 1, 1, file);
196c87c5fbaSopenharmony_ci
197c87c5fbaSopenharmony_ci    fflush(file);
198c87c5fbaSopenharmony_ci    fclose(file);
199c87c5fbaSopenharmony_ci  }
200c87c5fbaSopenharmony_ci}
201c87c5fbaSopenharmony_ci
202c87c5fbaSopenharmony_cistatic void
203c87c5fbaSopenharmony_cifree_xmit_data(coap_session_t *session COAP_UNUSED, void *app_ptr) {
204c87c5fbaSopenharmony_ci  coap_free(app_ptr);
205c87c5fbaSopenharmony_ci  return;
206c87c5fbaSopenharmony_ci}
207c87c5fbaSopenharmony_ci
208c87c5fbaSopenharmony_cistatic void
209c87c5fbaSopenharmony_citrack_new_token(size_t tokenlen, uint8_t *token) {
210c87c5fbaSopenharmony_ci  track_token *new_list = realloc(tracked_tokens,
211c87c5fbaSopenharmony_ci                                  (tracked_tokens_count + 1) * sizeof(tracked_tokens[0]));
212c87c5fbaSopenharmony_ci  if (!new_list) {
213c87c5fbaSopenharmony_ci    coap_log_info("Unable to track new token\n");
214c87c5fbaSopenharmony_ci    return;
215c87c5fbaSopenharmony_ci  }
216c87c5fbaSopenharmony_ci  tracked_tokens = new_list;
217c87c5fbaSopenharmony_ci  tracked_tokens[tracked_tokens_count].token = coap_new_binary(tokenlen);
218c87c5fbaSopenharmony_ci  if (!tracked_tokens[tracked_tokens_count].token)
219c87c5fbaSopenharmony_ci    return;
220c87c5fbaSopenharmony_ci  memcpy(tracked_tokens[tracked_tokens_count].token->s, token, tokenlen);
221c87c5fbaSopenharmony_ci  tracked_tokens[tracked_tokens_count].observe = doing_observe;
222c87c5fbaSopenharmony_ci  tracked_tokens_count++;
223c87c5fbaSopenharmony_ci}
224c87c5fbaSopenharmony_ci
225c87c5fbaSopenharmony_cistatic int
226c87c5fbaSopenharmony_citrack_check_token(coap_bin_const_t *token) {
227c87c5fbaSopenharmony_ci  size_t i;
228c87c5fbaSopenharmony_ci
229c87c5fbaSopenharmony_ci  for (i = 0; i < tracked_tokens_count; i++) {
230c87c5fbaSopenharmony_ci    if (coap_binary_equal(token, tracked_tokens[i].token)) {
231c87c5fbaSopenharmony_ci      return 1;
232c87c5fbaSopenharmony_ci    }
233c87c5fbaSopenharmony_ci  }
234c87c5fbaSopenharmony_ci  return 0;
235c87c5fbaSopenharmony_ci}
236c87c5fbaSopenharmony_ci
237c87c5fbaSopenharmony_cistatic void
238c87c5fbaSopenharmony_citrack_flush_token(coap_bin_const_t *token, int force) {
239c87c5fbaSopenharmony_ci  size_t i;
240c87c5fbaSopenharmony_ci
241c87c5fbaSopenharmony_ci  for (i = 0; i < tracked_tokens_count; i++) {
242c87c5fbaSopenharmony_ci    if (coap_binary_equal(token, tracked_tokens[i].token)) {
243c87c5fbaSopenharmony_ci      if (force || !tracked_tokens[i].observe || !obs_started) {
244c87c5fbaSopenharmony_ci        /* Only remove if not Observing */
245c87c5fbaSopenharmony_ci        coap_delete_binary(tracked_tokens[i].token);
246c87c5fbaSopenharmony_ci        if (tracked_tokens_count-i > 1) {
247c87c5fbaSopenharmony_ci          memmove(&tracked_tokens[i],
248c87c5fbaSopenharmony_ci                  &tracked_tokens[i+1],
249c87c5fbaSopenharmony_ci                  (tracked_tokens_count-i-1) * sizeof(tracked_tokens[0]));
250c87c5fbaSopenharmony_ci        }
251c87c5fbaSopenharmony_ci        tracked_tokens_count--;
252c87c5fbaSopenharmony_ci      }
253c87c5fbaSopenharmony_ci      break;
254c87c5fbaSopenharmony_ci    }
255c87c5fbaSopenharmony_ci  }
256c87c5fbaSopenharmony_ci}
257c87c5fbaSopenharmony_ci
258c87c5fbaSopenharmony_ci
259c87c5fbaSopenharmony_cistatic coap_pdu_t *
260c87c5fbaSopenharmony_cicoap_new_request(coap_context_t *ctx,
261c87c5fbaSopenharmony_ci                 coap_session_t *session,
262c87c5fbaSopenharmony_ci                 method_t m,
263c87c5fbaSopenharmony_ci                 coap_optlist_t **options,
264c87c5fbaSopenharmony_ci                 unsigned char *data,
265c87c5fbaSopenharmony_ci                 size_t length) {
266c87c5fbaSopenharmony_ci  coap_pdu_t *pdu;
267c87c5fbaSopenharmony_ci  uint8_t token[8];
268c87c5fbaSopenharmony_ci  size_t tokenlen;
269c87c5fbaSopenharmony_ci  (void)ctx;
270c87c5fbaSopenharmony_ci
271c87c5fbaSopenharmony_ci  if (!(pdu = coap_new_pdu(msgtype, m, session))) {
272c87c5fbaSopenharmony_ci    free_xmit_data(session, data);
273c87c5fbaSopenharmony_ci    return NULL;
274c87c5fbaSopenharmony_ci  }
275c87c5fbaSopenharmony_ci
276c87c5fbaSopenharmony_ci  /*
277c87c5fbaSopenharmony_ci   * Create unique token for this request for handling unsolicited /
278c87c5fbaSopenharmony_ci   * delayed responses.
279c87c5fbaSopenharmony_ci   * Note that only up to 8 bytes are returned
280c87c5fbaSopenharmony_ci   */
281c87c5fbaSopenharmony_ci  if (the_token.length > COAP_TOKEN_DEFAULT_MAX) {
282c87c5fbaSopenharmony_ci    coap_session_new_token(session, &tokenlen, token);
283c87c5fbaSopenharmony_ci    /* Update the last part 8 bytes of the large token */
284c87c5fbaSopenharmony_ci    memcpy(&the_token.s[the_token.length - tokenlen], token, tokenlen);
285c87c5fbaSopenharmony_ci  } else {
286c87c5fbaSopenharmony_ci    coap_session_new_token(session, &the_token.length, the_token.s);
287c87c5fbaSopenharmony_ci  }
288c87c5fbaSopenharmony_ci  track_new_token(the_token.length, the_token.s);
289c87c5fbaSopenharmony_ci  if (!coap_add_token(pdu, the_token.length, the_token.s)) {
290c87c5fbaSopenharmony_ci    coap_log_debug("cannot add token to request\n");
291c87c5fbaSopenharmony_ci  }
292c87c5fbaSopenharmony_ci
293c87c5fbaSopenharmony_ci  if (options)
294c87c5fbaSopenharmony_ci    coap_add_optlist_pdu(pdu, options);
295c87c5fbaSopenharmony_ci
296c87c5fbaSopenharmony_ci  if (length) {
297c87c5fbaSopenharmony_ci    /* Let the underlying libcoap decide how this data should be sent */
298c87c5fbaSopenharmony_ci    coap_add_data_large_request(session, pdu, length, data,
299c87c5fbaSopenharmony_ci                                free_xmit_data, data);
300c87c5fbaSopenharmony_ci  }
301c87c5fbaSopenharmony_ci
302c87c5fbaSopenharmony_ci  return pdu;
303c87c5fbaSopenharmony_ci}
304c87c5fbaSopenharmony_ci
305c87c5fbaSopenharmony_cistatic int
306c87c5fbaSopenharmony_cievent_handler(coap_session_t *session COAP_UNUSED,
307c87c5fbaSopenharmony_ci              const coap_event_t event) {
308c87c5fbaSopenharmony_ci
309c87c5fbaSopenharmony_ci  switch (event) {
310c87c5fbaSopenharmony_ci  case COAP_EVENT_DTLS_CLOSED:
311c87c5fbaSopenharmony_ci  case COAP_EVENT_TCP_CLOSED:
312c87c5fbaSopenharmony_ci  case COAP_EVENT_SESSION_CLOSED:
313c87c5fbaSopenharmony_ci  case COAP_EVENT_OSCORE_DECRYPTION_FAILURE:
314c87c5fbaSopenharmony_ci  case COAP_EVENT_OSCORE_NOT_ENABLED:
315c87c5fbaSopenharmony_ci  case COAP_EVENT_OSCORE_NO_PROTECTED_PAYLOAD:
316c87c5fbaSopenharmony_ci  case COAP_EVENT_OSCORE_NO_SECURITY:
317c87c5fbaSopenharmony_ci  case COAP_EVENT_OSCORE_INTERNAL_ERROR:
318c87c5fbaSopenharmony_ci  case COAP_EVENT_OSCORE_DECODE_ERROR:
319c87c5fbaSopenharmony_ci  case COAP_EVENT_WS_PACKET_SIZE:
320c87c5fbaSopenharmony_ci  case COAP_EVENT_WS_CLOSED:
321c87c5fbaSopenharmony_ci    quit = 1;
322c87c5fbaSopenharmony_ci    break;
323c87c5fbaSopenharmony_ci  case COAP_EVENT_DTLS_CONNECTED:
324c87c5fbaSopenharmony_ci  case COAP_EVENT_DTLS_RENEGOTIATE:
325c87c5fbaSopenharmony_ci  case COAP_EVENT_DTLS_ERROR:
326c87c5fbaSopenharmony_ci  case COAP_EVENT_TCP_CONNECTED:
327c87c5fbaSopenharmony_ci  case COAP_EVENT_TCP_FAILED:
328c87c5fbaSopenharmony_ci  case COAP_EVENT_SESSION_CONNECTED:
329c87c5fbaSopenharmony_ci  case COAP_EVENT_SESSION_FAILED:
330c87c5fbaSopenharmony_ci  case COAP_EVENT_PARTIAL_BLOCK:
331c87c5fbaSopenharmony_ci  case COAP_EVENT_XMIT_BLOCK_FAIL:
332c87c5fbaSopenharmony_ci  case COAP_EVENT_SERVER_SESSION_NEW:
333c87c5fbaSopenharmony_ci  case COAP_EVENT_SERVER_SESSION_DEL:
334c87c5fbaSopenharmony_ci  case COAP_EVENT_BAD_PACKET:
335c87c5fbaSopenharmony_ci  case COAP_EVENT_MSG_RETRANSMITTED:
336c87c5fbaSopenharmony_ci  case COAP_EVENT_WS_CONNECTED:
337c87c5fbaSopenharmony_ci  case COAP_EVENT_KEEPALIVE_FAILURE:
338c87c5fbaSopenharmony_ci  default:
339c87c5fbaSopenharmony_ci    break;
340c87c5fbaSopenharmony_ci  }
341c87c5fbaSopenharmony_ci  return 0;
342c87c5fbaSopenharmony_ci}
343c87c5fbaSopenharmony_ci
344c87c5fbaSopenharmony_cistatic void
345c87c5fbaSopenharmony_cinack_handler(coap_session_t *session COAP_UNUSED,
346c87c5fbaSopenharmony_ci             const coap_pdu_t *sent,
347c87c5fbaSopenharmony_ci             const coap_nack_reason_t reason,
348c87c5fbaSopenharmony_ci             const coap_mid_t mid COAP_UNUSED) {
349c87c5fbaSopenharmony_ci  if (sent) {
350c87c5fbaSopenharmony_ci    coap_bin_const_t token = coap_pdu_get_token(sent);
351c87c5fbaSopenharmony_ci
352c87c5fbaSopenharmony_ci    if (!track_check_token(&token)) {
353c87c5fbaSopenharmony_ci      coap_log_err("nack_handler: Unexpected token\n");
354c87c5fbaSopenharmony_ci    }
355c87c5fbaSopenharmony_ci  }
356c87c5fbaSopenharmony_ci
357c87c5fbaSopenharmony_ci  switch (reason) {
358c87c5fbaSopenharmony_ci  case COAP_NACK_TOO_MANY_RETRIES:
359c87c5fbaSopenharmony_ci  case COAP_NACK_NOT_DELIVERABLE:
360c87c5fbaSopenharmony_ci  case COAP_NACK_RST:
361c87c5fbaSopenharmony_ci  case COAP_NACK_TLS_FAILED:
362c87c5fbaSopenharmony_ci  case COAP_NACK_WS_FAILED:
363c87c5fbaSopenharmony_ci  case COAP_NACK_TLS_LAYER_FAILED:
364c87c5fbaSopenharmony_ci  case COAP_NACK_WS_LAYER_FAILED:
365c87c5fbaSopenharmony_ci    coap_log_err("cannot send CoAP pdu\n");
366c87c5fbaSopenharmony_ci    quit = 1;
367c87c5fbaSopenharmony_ci    break;
368c87c5fbaSopenharmony_ci  case COAP_NACK_ICMP_ISSUE:
369c87c5fbaSopenharmony_ci  case COAP_NACK_BAD_RESPONSE:
370c87c5fbaSopenharmony_ci  default:
371c87c5fbaSopenharmony_ci    ;
372c87c5fbaSopenharmony_ci  }
373c87c5fbaSopenharmony_ci  return;
374c87c5fbaSopenharmony_ci}
375c87c5fbaSopenharmony_ci
376c87c5fbaSopenharmony_ci/*
377c87c5fbaSopenharmony_ci * Response handler used for coap_send() responses
378c87c5fbaSopenharmony_ci */
379c87c5fbaSopenharmony_cistatic coap_response_t
380c87c5fbaSopenharmony_cimessage_handler(coap_session_t *session COAP_UNUSED,
381c87c5fbaSopenharmony_ci                const coap_pdu_t *sent,
382c87c5fbaSopenharmony_ci                const coap_pdu_t *received,
383c87c5fbaSopenharmony_ci                const coap_mid_t id COAP_UNUSED) {
384c87c5fbaSopenharmony_ci
385c87c5fbaSopenharmony_ci  coap_opt_t *block_opt;
386c87c5fbaSopenharmony_ci  coap_opt_iterator_t opt_iter;
387c87c5fbaSopenharmony_ci  size_t len;
388c87c5fbaSopenharmony_ci  const uint8_t *databuf;
389c87c5fbaSopenharmony_ci  size_t offset;
390c87c5fbaSopenharmony_ci  size_t total;
391c87c5fbaSopenharmony_ci  coap_pdu_code_t rcv_code = coap_pdu_get_code(received);
392c87c5fbaSopenharmony_ci  coap_pdu_type_t rcv_type = coap_pdu_get_type(received);
393c87c5fbaSopenharmony_ci  coap_bin_const_t token = coap_pdu_get_token(received);
394c87c5fbaSopenharmony_ci
395c87c5fbaSopenharmony_ci  coap_log_debug("** process incoming %d.%02d response:\n",
396c87c5fbaSopenharmony_ci                 COAP_RESPONSE_CLASS(rcv_code), rcv_code & 0x1F);
397c87c5fbaSopenharmony_ci  if (coap_get_log_level() < COAP_LOG_DEBUG)
398c87c5fbaSopenharmony_ci    coap_show_pdu(COAP_LOG_INFO, received);
399c87c5fbaSopenharmony_ci
400c87c5fbaSopenharmony_ci  /* check if this is a response to our original request */
401c87c5fbaSopenharmony_ci  if (!track_check_token(&token)) {
402c87c5fbaSopenharmony_ci    /* drop if this was just some message, or send RST in case of notification */
403c87c5fbaSopenharmony_ci    if (!sent && (rcv_type == COAP_MESSAGE_CON ||
404c87c5fbaSopenharmony_ci                  rcv_type == COAP_MESSAGE_NON)) {
405c87c5fbaSopenharmony_ci      /* Cause a CoAP RST to be sent */
406c87c5fbaSopenharmony_ci      return COAP_RESPONSE_FAIL;
407c87c5fbaSopenharmony_ci    }
408c87c5fbaSopenharmony_ci    return COAP_RESPONSE_OK;
409c87c5fbaSopenharmony_ci  }
410c87c5fbaSopenharmony_ci
411c87c5fbaSopenharmony_ci  if (rcv_type == COAP_MESSAGE_RST) {
412c87c5fbaSopenharmony_ci    coap_log_info("got RST\n");
413c87c5fbaSopenharmony_ci    return COAP_RESPONSE_OK;
414c87c5fbaSopenharmony_ci  }
415c87c5fbaSopenharmony_ci
416c87c5fbaSopenharmony_ci  /* output the received data, if any */
417c87c5fbaSopenharmony_ci  if (COAP_RESPONSE_CLASS(rcv_code) == 2) {
418c87c5fbaSopenharmony_ci
419c87c5fbaSopenharmony_ci    /* set obs timer if we have successfully subscribed a resource */
420c87c5fbaSopenharmony_ci    if (doing_observe && !obs_started &&
421c87c5fbaSopenharmony_ci        coap_check_option(received, COAP_OPTION_OBSERVE, &opt_iter)) {
422c87c5fbaSopenharmony_ci      coap_log_debug("observation relationship established, set timeout to %d\n",
423c87c5fbaSopenharmony_ci                     obs_seconds);
424c87c5fbaSopenharmony_ci      obs_started = 1;
425c87c5fbaSopenharmony_ci      obs_ms = obs_seconds * 1000;
426c87c5fbaSopenharmony_ci      obs_ms_reset = 1;
427c87c5fbaSopenharmony_ci    }
428c87c5fbaSopenharmony_ci
429c87c5fbaSopenharmony_ci    if (coap_get_data_large(received, &len, &databuf, &offset, &total)) {
430c87c5fbaSopenharmony_ci      append_to_output(databuf, len);
431c87c5fbaSopenharmony_ci      if ((len + offset == total) && add_nl)
432c87c5fbaSopenharmony_ci        append_to_output((const uint8_t *)"\n", 1);
433c87c5fbaSopenharmony_ci    }
434c87c5fbaSopenharmony_ci
435c87c5fbaSopenharmony_ci    /* Check if Block2 option is set */
436c87c5fbaSopenharmony_ci    block_opt = coap_check_option(received, COAP_OPTION_BLOCK2, &opt_iter);
437c87c5fbaSopenharmony_ci    if (!single_block_requested && block_opt) { /* handle Block2 */
438c87c5fbaSopenharmony_ci
439c87c5fbaSopenharmony_ci      /* TODO: check if we are looking at the correct block number */
440c87c5fbaSopenharmony_ci      if (coap_opt_block_num(block_opt) == 0) {
441c87c5fbaSopenharmony_ci        /* See if observe is set in first response */
442c87c5fbaSopenharmony_ci        ready = doing_observe ? coap_check_option(received,
443c87c5fbaSopenharmony_ci                                                  COAP_OPTION_OBSERVE, &opt_iter) == NULL : 1;
444c87c5fbaSopenharmony_ci      }
445c87c5fbaSopenharmony_ci      if (COAP_OPT_BLOCK_MORE(block_opt)) {
446c87c5fbaSopenharmony_ci        doing_getting_block = 1;
447c87c5fbaSopenharmony_ci      } else {
448c87c5fbaSopenharmony_ci        doing_getting_block = 0;
449c87c5fbaSopenharmony_ci        if (!is_mcast)
450c87c5fbaSopenharmony_ci          track_flush_token(&token, 0);
451c87c5fbaSopenharmony_ci      }
452c87c5fbaSopenharmony_ci      return COAP_RESPONSE_OK;
453c87c5fbaSopenharmony_ci    }
454c87c5fbaSopenharmony_ci  } else {      /* no 2.05 */
455c87c5fbaSopenharmony_ci    /* check if an error was signaled and output payload if so */
456c87c5fbaSopenharmony_ci    if (COAP_RESPONSE_CLASS(rcv_code) >= 4) {
457c87c5fbaSopenharmony_ci      fprintf(stderr, "%d.%02d", COAP_RESPONSE_CLASS(rcv_code),
458c87c5fbaSopenharmony_ci              rcv_code & 0x1F);
459c87c5fbaSopenharmony_ci      if (coap_get_data_large(received, &len, &databuf, &offset, &total)) {
460c87c5fbaSopenharmony_ci        fprintf(stderr, " ");
461c87c5fbaSopenharmony_ci        while (len--) {
462c87c5fbaSopenharmony_ci          fprintf(stderr, "%c", isprint(*databuf) ? *databuf : '.');
463c87c5fbaSopenharmony_ci          databuf++;
464c87c5fbaSopenharmony_ci        }
465c87c5fbaSopenharmony_ci      }
466c87c5fbaSopenharmony_ci      fprintf(stderr, "\n");
467c87c5fbaSopenharmony_ci      track_flush_token(&token, 1);
468c87c5fbaSopenharmony_ci    }
469c87c5fbaSopenharmony_ci
470c87c5fbaSopenharmony_ci  }
471c87c5fbaSopenharmony_ci  if (!is_mcast)
472c87c5fbaSopenharmony_ci    track_flush_token(&token, 0);
473c87c5fbaSopenharmony_ci
474c87c5fbaSopenharmony_ci  /* our job is done, we can exit at any time */
475c87c5fbaSopenharmony_ci  ready = doing_observe ? coap_check_option(received,
476c87c5fbaSopenharmony_ci                                            COAP_OPTION_OBSERVE, &opt_iter) == NULL : 1;
477c87c5fbaSopenharmony_ci  return COAP_RESPONSE_OK;
478c87c5fbaSopenharmony_ci}
479c87c5fbaSopenharmony_ci
480c87c5fbaSopenharmony_cistatic void
481c87c5fbaSopenharmony_ciusage(const char *program, const char *version) {
482c87c5fbaSopenharmony_ci  const char *p;
483c87c5fbaSopenharmony_ci  char buffer[120];
484c87c5fbaSopenharmony_ci  const char *lib_build = coap_package_build();
485c87c5fbaSopenharmony_ci
486c87c5fbaSopenharmony_ci  p = strrchr(program, '/');
487c87c5fbaSopenharmony_ci  if (p)
488c87c5fbaSopenharmony_ci    program = ++p;
489c87c5fbaSopenharmony_ci
490c87c5fbaSopenharmony_ci  fprintf(stderr, "%s v%s -- a small CoAP implementation\n"
491c87c5fbaSopenharmony_ci          "Copyright (C) 2010-2023 Olaf Bergmann <bergmann@tzi.org> and others\n\n"
492c87c5fbaSopenharmony_ci          "Build: %s\n"
493c87c5fbaSopenharmony_ci          "%s\n"
494c87c5fbaSopenharmony_ci          , program, version, lib_build,
495c87c5fbaSopenharmony_ci          coap_string_tls_version(buffer, sizeof(buffer)));
496c87c5fbaSopenharmony_ci  fprintf(stderr, "%s\n", coap_string_tls_support(buffer, sizeof(buffer)));
497c87c5fbaSopenharmony_ci  fprintf(stderr, "\n"
498c87c5fbaSopenharmony_ci          "Usage: %s [-a addr] [-b [num,]size] [-e text] [-f file] [-l loss]\n"
499c87c5fbaSopenharmony_ci          "\t\t[-m method] [-o file] [-p port] [-r] [-s duration] [-t type]\n"
500c87c5fbaSopenharmony_ci          "\t\t[-v num] [-w] [-A type] [-B seconds]\n"
501c87c5fbaSopenharmony_ci          "\t\t[-E oscore_conf_file[,seq_file]] [-G count] [-H hoplimit]\n"
502c87c5fbaSopenharmony_ci          "\t\t[-K interval] [-N] [-O num,text] [-P scheme://address[:port]\n"
503c87c5fbaSopenharmony_ci          "\t\t[-T token] [-U]  [-V num] [-X size]\n"
504c87c5fbaSopenharmony_ci          "\t\t[[-h match_hint_file] [-k key] [-u user]]\n"
505c87c5fbaSopenharmony_ci          "\t\t[[-c certfile] [-j keyfile] [-n] [-C cafile]\n"
506c87c5fbaSopenharmony_ci          "\t\t[-J pkcs11_pin] [-M raw_pk] [-R trust_casfile]\n"
507c87c5fbaSopenharmony_ci          "\t\t[-S match_pki_sni_file]] URI\n"
508c87c5fbaSopenharmony_ci          "\tURI can be an absolute URI or a URI prefixed with scheme and host\n\n"
509c87c5fbaSopenharmony_ci          "General Options\n"
510c87c5fbaSopenharmony_ci          "\t-a addr\t\tThe local interface address to use\n"
511c87c5fbaSopenharmony_ci          "\t-b [num,]size\tBlock size to be used in GET/PUT/POST requests\n"
512c87c5fbaSopenharmony_ci          "\t       \t\t(value must be a multiple of 16 not larger than 1024)\n"
513c87c5fbaSopenharmony_ci          "\t       \t\tIf num is present, the request chain will start at\n"
514c87c5fbaSopenharmony_ci          "\t       \t\tblock num\n"
515c87c5fbaSopenharmony_ci          "\t-e text\t\tInclude text as payload (use percent-encoding for\n"
516c87c5fbaSopenharmony_ci          "\t       \t\tnon-ASCII characters)\n"
517c87c5fbaSopenharmony_ci          "\t-f file\t\tFile to send with PUT/POST (use '-' for STDIN)\n"
518c87c5fbaSopenharmony_ci          "\t-l list\t\tFail to send some datagrams specified by a comma\n"
519c87c5fbaSopenharmony_ci          "\t       \t\tseparated list of numbers or number ranges\n"
520c87c5fbaSopenharmony_ci          "\t       \t\t(for debugging only)\n"
521c87c5fbaSopenharmony_ci          "\t-l loss%%\tRandomly fail to send datagrams with the specified\n"
522c87c5fbaSopenharmony_ci          "\t       \t\tprobability - 100%% all datagrams, 0%% no datagrams\n"
523c87c5fbaSopenharmony_ci          "\t-m method\tRequest method (get|put|post|delete|fetch|patch|ipatch),\n"
524c87c5fbaSopenharmony_ci          "\t       \t\tdefault is 'get'\n"
525c87c5fbaSopenharmony_ci          "\t-o file\t\tOutput received data to this file (use '-' for STDOUT)\n"
526c87c5fbaSopenharmony_ci          "\t-p port\t\tSend from the specified port\n"
527c87c5fbaSopenharmony_ci          "\t-r     \t\tUse reliable protocol (TCP or TLS); requires TCP support\n"
528c87c5fbaSopenharmony_ci          "\t-s duration\tSubscribe to / Observe resource for given duration\n"
529c87c5fbaSopenharmony_ci          "\t       \t\tin seconds\n"
530c87c5fbaSopenharmony_ci          "\t-t type\t\tContent format for given resource for PUT/POST\n"
531c87c5fbaSopenharmony_ci          "\t-v num \t\tVerbosity level (default 4, maximum is 8) for general\n"
532c87c5fbaSopenharmony_ci          "\t       \t\tCoAP logging\n"
533c87c5fbaSopenharmony_ci          "\t-w     \t\tAppend a newline to received data\n"
534c87c5fbaSopenharmony_ci          "\t-A type\t\tAccepted media type\n"
535c87c5fbaSopenharmony_ci          "\t-B seconds\tBreak operation after waiting given seconds\n"
536c87c5fbaSopenharmony_ci          "\t       \t\t(default is %d)\n"
537c87c5fbaSopenharmony_ci          "\t-E oscore_conf_file[,seq_file]\n"
538c87c5fbaSopenharmony_ci          "\t       \t\toscore_conf_file contains OSCORE configuration. See\n"
539c87c5fbaSopenharmony_ci          "\t       \t\tcoap-oscore-conf(5) for definitions.\n"
540c87c5fbaSopenharmony_ci          "\t       \t\tOptional seq_file is used to save the current transmit\n"
541c87c5fbaSopenharmony_ci          "\t       \t\tsequence number, so on restart sequence numbers continue\n"
542c87c5fbaSopenharmony_ci          "\t-G count\tRepeat the Request 'count' times with a second delay\n"
543c87c5fbaSopenharmony_ci          "\t       \t\tbetween each one. Must have a value between 1 and 255\n"
544c87c5fbaSopenharmony_ci          "\t       \t\tinclusive. Default is '1'\n"
545c87c5fbaSopenharmony_ci          "\t-H hoplimit\tSet the Hop Limit count to hoplimit for proxies. Must\n"
546c87c5fbaSopenharmony_ci          "\t       \t\thave a value between 1 and 255 inclusive.\n"
547c87c5fbaSopenharmony_ci          "\t       \t\tDefault is '16'\n"
548c87c5fbaSopenharmony_ci          "\t-K interval\tSend a ping after interval seconds of inactivity\n"
549c87c5fbaSopenharmony_ci          "\t-L value\tSum of one or more COAP_BLOCK_* flag valuess for block\n"
550c87c5fbaSopenharmony_ci          "\t       \t\thandling methods. Default is 1 (COAP_BLOCK_USE_LIBCOAP)\n"
551c87c5fbaSopenharmony_ci          "\t       \t\t(Sum of one or more of 1,2 and 16)\n"
552c87c5fbaSopenharmony_ci          "\t-N     \t\tSend NON-confirmable message\n"
553c87c5fbaSopenharmony_ci          "\t-O num,text\tAdd option num with contents text to request. If the\n"
554c87c5fbaSopenharmony_ci          "\t       \t\ttext begins with 0x, then the hex text (two [0-9a-f] per\n"
555c87c5fbaSopenharmony_ci          "\t       \t\tbyte) is converted to binary data\n"
556c87c5fbaSopenharmony_ci          "\t-P scheme://address[:port]\n"
557c87c5fbaSopenharmony_ci          "\t       \t\tScheme, address and optional port to define how to\n"
558c87c5fbaSopenharmony_ci          "\t       \t\tconnect to a CoAP proxy (automatically adds Proxy-Uri\n"
559c87c5fbaSopenharmony_ci          "\t       \t\toption to request) to forward the request to.\n"
560c87c5fbaSopenharmony_ci          "\t       \t\tScheme is one of coap, coaps, coap+tcp and coaps+tcp\n"
561c87c5fbaSopenharmony_ci          "\t-T token\tDefine the initial starting token (up to 24 characters)\n"
562c87c5fbaSopenharmony_ci          "\t-U     \t\tNever include Uri-Host or Uri-Port options\n"
563c87c5fbaSopenharmony_ci          "\t-V num \t\tVerbosity level (default 3, maximum is 7) for (D)TLS\n"
564c87c5fbaSopenharmony_ci          "\t       \t\tlibrary logging\n"
565c87c5fbaSopenharmony_ci          "\t-X size\t\tMaximum message size to use for TCP based connections\n"
566c87c5fbaSopenharmony_ci          "\t       \t\t(default is 8388864). Maximum value of 2^32 -1\n"
567c87c5fbaSopenharmony_ci          ,program, wait_seconds);
568c87c5fbaSopenharmony_ci  fprintf(stderr,
569c87c5fbaSopenharmony_ci          "PSK Options (if supported by underlying (D)TLS library)\n"
570c87c5fbaSopenharmony_ci          "\t-h match_hint_file\n"
571c87c5fbaSopenharmony_ci          "\t       \t\tThis is a file that contains one or more lines of\n"
572c87c5fbaSopenharmony_ci          "\t       \t\treceived Identity Hints to match to use different\n"
573c87c5fbaSopenharmony_ci          "\t       \t\tuser identity and associated pre-shared key (PSK) (comma\n"
574c87c5fbaSopenharmony_ci          "\t       \t\tseparated) instead of the '-k key' and '-u user'\n"
575c87c5fbaSopenharmony_ci          "\t       \t\toptions. E.g., per line\n"
576c87c5fbaSopenharmony_ci          "\t       \t\t hint_to_match,use_user,with_key\n"
577c87c5fbaSopenharmony_ci          "\t       \t\tNote: -k and -u still need to be defined for the default\n"
578c87c5fbaSopenharmony_ci          "\t       \t\tin case there is no match\n"
579c87c5fbaSopenharmony_ci          "\t-k key \t\tPre-shared key for the specified user identity\n"
580c87c5fbaSopenharmony_ci          "\t-u user\t\tUser identity to send for pre-shared key mode\n"
581c87c5fbaSopenharmony_ci          "PKI Options (if supported by underlying (D)TLS library)\n"
582c87c5fbaSopenharmony_ci          "\tNote: If any one of '-c certfile', '-j keyfile' or '-C cafile' is in\n"
583c87c5fbaSopenharmony_ci          "\tPKCS11 URI naming format (pkcs11: prefix), then any remaining non\n"
584c87c5fbaSopenharmony_ci          "\tPKCS11 URI file definitions have to be in DER, not PEM, format.\n"
585c87c5fbaSopenharmony_ci          "\tOtherwise all of '-c certfile', '-j keyfile' or '-C cafile' are in\n"
586c87c5fbaSopenharmony_ci          "\tPEM format.\n\n"
587c87c5fbaSopenharmony_ci          "\t-c certfile\tPEM file or PKCS11 URI for the certificate. The private\n"
588c87c5fbaSopenharmony_ci          "\t       \t\tkey can also be in the PEM file, or has the same PKCS11\n"
589c87c5fbaSopenharmony_ci          "\t       \t\tURI. If not, the private key is defined by '-j keyfile'\n"
590c87c5fbaSopenharmony_ci          "\t-j keyfile\tPEM file or PKCS11 URI for the private key for the\n"
591c87c5fbaSopenharmony_ci          "\t       \t\tcertificate in '-c certfile' if the parameter is\n"
592c87c5fbaSopenharmony_ci          "\t       \t\tdifferent from certfile in '-c certfile'\n"
593c87c5fbaSopenharmony_ci          "\t-n     \t\tDisable remote peer certificate checking\n"
594c87c5fbaSopenharmony_ci          "\t-C cafile\tPEM file or PKCS11 URI for the CA certificate that was\n"
595c87c5fbaSopenharmony_ci          "\t       \t\tused to sign the server certfile. Ideally the client\n"
596c87c5fbaSopenharmony_ci          "\t       \t\tcertificate should be signed by the same CA so that\n"
597c87c5fbaSopenharmony_ci          "\t       \t\tmutual authentication can take place. The contents of\n"
598c87c5fbaSopenharmony_ci          "\t       \t\tcafile are added to the trusted store of root CAs.\n"
599c87c5fbaSopenharmony_ci          "\t       \t\tUsing the -C or -R options will trigger the\n"
600c87c5fbaSopenharmony_ci          "\t       \t\tvalidation of the server certificate unless overridden\n"
601c87c5fbaSopenharmony_ci          "\t       \t\tby the -n option\n"
602c87c5fbaSopenharmony_ci          "\t-J pkcs11_pin\tThe user pin to unlock access to the PKCS11 token\n"
603c87c5fbaSopenharmony_ci          "\t-M rpk_file\tRaw Public Key (RPK) PEM file or PKCS11 URI that\n"
604c87c5fbaSopenharmony_ci          "\t       \t\tcontains both PUBLIC KEY and PRIVATE KEY or just\n"
605c87c5fbaSopenharmony_ci          "\t       \t\tEC PRIVATE KEY. (GnuTLS and TinyDTLS(PEM) support only).\n"
606c87c5fbaSopenharmony_ci          "\t       \t\t'-C cafile' or '-R trust_casfile' are not required\n"
607c87c5fbaSopenharmony_ci          "\t-R trust_casfile\n"
608c87c5fbaSopenharmony_ci          "\t       \t\tPEM file containing the set of trusted root CAs\n"
609c87c5fbaSopenharmony_ci          "\t       \t\tthat are to be used to validate the server certificate.\n"
610c87c5fbaSopenharmony_ci          "\t       \t\tAlternatively, this can point to a directory containing\n"
611c87c5fbaSopenharmony_ci          "\t       \t\ta set of CA PEM files.\n"
612c87c5fbaSopenharmony_ci          "\t       \t\tUsing '-R trust_casfile' disables common CA mutual\n"
613c87c5fbaSopenharmony_ci          "\t       \t\tauthentication which can only be done by using\n"
614c87c5fbaSopenharmony_ci          "\t       \t\t'-C cafile'.\n"
615c87c5fbaSopenharmony_ci          "\t       \t\tUsing the -C or -R options will will trigger the\n"
616c87c5fbaSopenharmony_ci          "\t       \t\tvalidation of the server certificate unless overridden\n"
617c87c5fbaSopenharmony_ci          "\t       \t\tby the -n option\n"
618c87c5fbaSopenharmony_ci         );
619c87c5fbaSopenharmony_ci  fprintf(stderr,
620c87c5fbaSopenharmony_ci          "Examples:\n"
621c87c5fbaSopenharmony_ci          "\tcoap-client -m get coap://[::1]/\n"
622c87c5fbaSopenharmony_ci          "\tcoap-client -m get coap://[::1]/.well-known/core\n"
623c87c5fbaSopenharmony_ci          "\tcoap-client -m get coap+tcp://[::1]/.well-known/core\n"
624c87c5fbaSopenharmony_ci          "\tcoap-client -m get coap://%%2Funix%%2Fdomain%%2Fpath%%2Fdgram/.well-known/core\n"
625c87c5fbaSopenharmony_ci          "\tcoap-client -m get coap+tcp://%%2Funix%%2Fdomain%%2Fpath%%2Fstream/.well-known/core\n"
626c87c5fbaSopenharmony_ci          "\tcoap-client -m get coaps://[::1]/.well-known/core\n"
627c87c5fbaSopenharmony_ci          "\tcoap-client -m get coaps+tcp://[::1]/.well-known/core\n"
628c87c5fbaSopenharmony_ci          "\tcoap-client -m get coaps://%%2Funix%%2Fdomain%%2Fpath%%2Fdtls/.well-known/core\n"
629c87c5fbaSopenharmony_ci          "\tcoap-client -m get coaps+tcp://%%2Funix%%2Fdomain%%2Fpath%%2Ftls/.well-known/core\n"
630c87c5fbaSopenharmony_ci          "\tcoap-client -m get -T cafe coap://[::1]/time\n"
631c87c5fbaSopenharmony_ci          "\techo -n 1000 | coap-client -m put -T cafe coap://[::1]/time -f -\n"
632c87c5fbaSopenharmony_ci         );
633c87c5fbaSopenharmony_ci}
634c87c5fbaSopenharmony_ci
635c87c5fbaSopenharmony_citypedef struct {
636c87c5fbaSopenharmony_ci  unsigned char code;
637c87c5fbaSopenharmony_ci  const char *media_type;
638c87c5fbaSopenharmony_ci} content_type_t;
639c87c5fbaSopenharmony_ci
640c87c5fbaSopenharmony_cistatic void
641c87c5fbaSopenharmony_cicmdline_content_type(char *arg, uint16_t key) {
642c87c5fbaSopenharmony_ci  static content_type_t content_types[] = {
643c87c5fbaSopenharmony_ci    {  0, "plain" },
644c87c5fbaSopenharmony_ci    {  0, "text/plain" },
645c87c5fbaSopenharmony_ci    { 40, "link" },
646c87c5fbaSopenharmony_ci    { 40, "link-format" },
647c87c5fbaSopenharmony_ci    { 40, "application/link-format" },
648c87c5fbaSopenharmony_ci    { 41, "xml" },
649c87c5fbaSopenharmony_ci    { 41, "application/xml" },
650c87c5fbaSopenharmony_ci    { 42, "binary" },
651c87c5fbaSopenharmony_ci    { 42, "octet-stream" },
652c87c5fbaSopenharmony_ci    { 42, "application/octet-stream" },
653c87c5fbaSopenharmony_ci    { 47, "exi" },
654c87c5fbaSopenharmony_ci    { 47, "application/exi" },
655c87c5fbaSopenharmony_ci    { 50, "json" },
656c87c5fbaSopenharmony_ci    { 50, "application/json" },
657c87c5fbaSopenharmony_ci    { 60, "cbor" },
658c87c5fbaSopenharmony_ci    { 60, "application/cbor" },
659c87c5fbaSopenharmony_ci    { 255, NULL }
660c87c5fbaSopenharmony_ci  };
661c87c5fbaSopenharmony_ci  coap_optlist_t *node;
662c87c5fbaSopenharmony_ci  unsigned char i;
663c87c5fbaSopenharmony_ci  uint16_t value;
664c87c5fbaSopenharmony_ci  uint8_t buf[4];
665c87c5fbaSopenharmony_ci
666c87c5fbaSopenharmony_ci  if (isdigit((int)arg[0])) {
667c87c5fbaSopenharmony_ci    value = atoi(arg);
668c87c5fbaSopenharmony_ci  } else {
669c87c5fbaSopenharmony_ci    for (i=0;
670c87c5fbaSopenharmony_ci         content_types[i].media_type &&
671c87c5fbaSopenharmony_ci         strncmp(arg, content_types[i].media_type, strlen(arg)) != 0 ;
672c87c5fbaSopenharmony_ci         ++i)
673c87c5fbaSopenharmony_ci      ;
674c87c5fbaSopenharmony_ci
675c87c5fbaSopenharmony_ci    if (content_types[i].media_type) {
676c87c5fbaSopenharmony_ci      value = content_types[i].code;
677c87c5fbaSopenharmony_ci    } else {
678c87c5fbaSopenharmony_ci      coap_log_warn("W: unknown content-format '%s'\n",arg);
679c87c5fbaSopenharmony_ci      return;
680c87c5fbaSopenharmony_ci    }
681c87c5fbaSopenharmony_ci  }
682c87c5fbaSopenharmony_ci
683c87c5fbaSopenharmony_ci  node = coap_new_optlist(key, coap_encode_var_safe(buf, sizeof(buf), value), buf);
684c87c5fbaSopenharmony_ci  if (node) {
685c87c5fbaSopenharmony_ci    coap_insert_optlist(&optlist, node);
686c87c5fbaSopenharmony_ci  }
687c87c5fbaSopenharmony_ci}
688c87c5fbaSopenharmony_ci
689c87c5fbaSopenharmony_cistatic int
690c87c5fbaSopenharmony_cicmdline_hop_limit(char *arg) {
691c87c5fbaSopenharmony_ci  coap_optlist_t *node;
692c87c5fbaSopenharmony_ci  uint32_t value;
693c87c5fbaSopenharmony_ci  uint8_t buf[4];
694c87c5fbaSopenharmony_ci
695c87c5fbaSopenharmony_ci  value = strtol(arg, NULL, 10);
696c87c5fbaSopenharmony_ci  if (value < 1 || value > 255) {
697c87c5fbaSopenharmony_ci    return 0;
698c87c5fbaSopenharmony_ci  }
699c87c5fbaSopenharmony_ci  node = coap_new_optlist(COAP_OPTION_HOP_LIMIT, coap_encode_var_safe(buf, sizeof(buf), value), buf);
700c87c5fbaSopenharmony_ci  if (node) {
701c87c5fbaSopenharmony_ci    coap_insert_optlist(&optlist, node);
702c87c5fbaSopenharmony_ci  }
703c87c5fbaSopenharmony_ci  return 1;
704c87c5fbaSopenharmony_ci}
705c87c5fbaSopenharmony_ci
706c87c5fbaSopenharmony_cistatic uint8_t *
707c87c5fbaSopenharmony_ciread_file_mem(const char *filename, size_t *length) {
708c87c5fbaSopenharmony_ci  FILE *f;
709c87c5fbaSopenharmony_ci  uint8_t *buf;
710c87c5fbaSopenharmony_ci  struct stat statbuf;
711c87c5fbaSopenharmony_ci
712c87c5fbaSopenharmony_ci  *length = 0;
713c87c5fbaSopenharmony_ci  if (!filename || !(f = fopen(filename, "r")))
714c87c5fbaSopenharmony_ci    return NULL;
715c87c5fbaSopenharmony_ci
716c87c5fbaSopenharmony_ci  if (fstat(fileno(f), &statbuf) == -1) {
717c87c5fbaSopenharmony_ci    fclose(f);
718c87c5fbaSopenharmony_ci    return NULL;
719c87c5fbaSopenharmony_ci  }
720c87c5fbaSopenharmony_ci
721c87c5fbaSopenharmony_ci  buf = coap_malloc(statbuf.st_size+1);
722c87c5fbaSopenharmony_ci  if (!buf) {
723c87c5fbaSopenharmony_ci    fclose(f);
724c87c5fbaSopenharmony_ci    return NULL;
725c87c5fbaSopenharmony_ci  }
726c87c5fbaSopenharmony_ci
727c87c5fbaSopenharmony_ci  if (fread(buf, 1, statbuf.st_size, f) != (size_t)statbuf.st_size) {
728c87c5fbaSopenharmony_ci    fclose(f);
729c87c5fbaSopenharmony_ci    coap_free(buf);
730c87c5fbaSopenharmony_ci    return NULL;
731c87c5fbaSopenharmony_ci  }
732c87c5fbaSopenharmony_ci  buf[statbuf.st_size] = '\000';
733c87c5fbaSopenharmony_ci  *length = (size_t)(statbuf.st_size + 1);
734c87c5fbaSopenharmony_ci  fclose(f);
735c87c5fbaSopenharmony_ci  return buf;
736c87c5fbaSopenharmony_ci}
737c87c5fbaSopenharmony_ci
738c87c5fbaSopenharmony_cistatic FILE *oscore_seq_num_fp = NULL;
739c87c5fbaSopenharmony_cistatic const char *oscore_conf_file = NULL;
740c87c5fbaSopenharmony_cistatic const char *oscore_seq_save_file = NULL;
741c87c5fbaSopenharmony_ci
742c87c5fbaSopenharmony_cistatic int
743c87c5fbaSopenharmony_cioscore_save_seq_num(uint64_t sender_seq_num, void *param COAP_UNUSED) {
744c87c5fbaSopenharmony_ci  if (oscore_seq_num_fp) {
745c87c5fbaSopenharmony_ci    rewind(oscore_seq_num_fp);
746c87c5fbaSopenharmony_ci    fprintf(oscore_seq_num_fp, "%" PRIu64 "\n", sender_seq_num);
747c87c5fbaSopenharmony_ci    fflush(oscore_seq_num_fp);
748c87c5fbaSopenharmony_ci  }
749c87c5fbaSopenharmony_ci  return 1;
750c87c5fbaSopenharmony_ci}
751c87c5fbaSopenharmony_ci
752c87c5fbaSopenharmony_cistatic coap_oscore_conf_t *
753c87c5fbaSopenharmony_ciget_oscore_conf(void) {
754c87c5fbaSopenharmony_ci  uint8_t *buf;
755c87c5fbaSopenharmony_ci  size_t length;
756c87c5fbaSopenharmony_ci  coap_str_const_t file_mem;
757c87c5fbaSopenharmony_ci  uint64_t start_seq_num = 0;
758c87c5fbaSopenharmony_ci
759c87c5fbaSopenharmony_ci  /* Need a rw var to free off later and file_mem.s is a const */
760c87c5fbaSopenharmony_ci  buf = read_file_mem(oscore_conf_file, &length);
761c87c5fbaSopenharmony_ci  if (buf == NULL) {
762c87c5fbaSopenharmony_ci    fprintf(stderr, "OSCORE configuration file error: %s\n", oscore_conf_file);
763c87c5fbaSopenharmony_ci    return NULL;
764c87c5fbaSopenharmony_ci  }
765c87c5fbaSopenharmony_ci  file_mem.s = buf;
766c87c5fbaSopenharmony_ci  file_mem.length = length;
767c87c5fbaSopenharmony_ci  if (oscore_seq_save_file) {
768c87c5fbaSopenharmony_ci    oscore_seq_num_fp = fopen(oscore_seq_save_file, "r+");
769c87c5fbaSopenharmony_ci    if (oscore_seq_num_fp == NULL) {
770c87c5fbaSopenharmony_ci      /* Try creating it */
771c87c5fbaSopenharmony_ci      oscore_seq_num_fp = fopen(oscore_seq_save_file, "w+");
772c87c5fbaSopenharmony_ci      if (oscore_seq_num_fp == NULL) {
773c87c5fbaSopenharmony_ci        fprintf(stderr, "OSCORE save restart info file error: %s\n",
774c87c5fbaSopenharmony_ci                oscore_seq_save_file);
775c87c5fbaSopenharmony_ci        return NULL;
776c87c5fbaSopenharmony_ci      }
777c87c5fbaSopenharmony_ci    }
778c87c5fbaSopenharmony_ci    if (fscanf(oscore_seq_num_fp, "%" PRIu64, &start_seq_num) != 1) {
779c87c5fbaSopenharmony_ci      /* Must be empty */
780c87c5fbaSopenharmony_ci      start_seq_num = 0;
781c87c5fbaSopenharmony_ci    }
782c87c5fbaSopenharmony_ci  }
783c87c5fbaSopenharmony_ci  oscore_conf = coap_new_oscore_conf(file_mem,
784c87c5fbaSopenharmony_ci                                     oscore_save_seq_num,
785c87c5fbaSopenharmony_ci                                     NULL, start_seq_num);
786c87c5fbaSopenharmony_ci  coap_free(buf);
787c87c5fbaSopenharmony_ci  if (oscore_conf == NULL) {
788c87c5fbaSopenharmony_ci    fprintf(stderr, "OSCORE configuration file error: %s\n", oscore_conf_file);
789c87c5fbaSopenharmony_ci    return NULL;
790c87c5fbaSopenharmony_ci  }
791c87c5fbaSopenharmony_ci  return oscore_conf;
792c87c5fbaSopenharmony_ci}
793c87c5fbaSopenharmony_ci
794c87c5fbaSopenharmony_cistatic int
795c87c5fbaSopenharmony_cicmdline_oscore(char *arg) {
796c87c5fbaSopenharmony_ci  if (coap_oscore_is_supported()) {
797c87c5fbaSopenharmony_ci    char *sep = strchr(arg, ',');
798c87c5fbaSopenharmony_ci
799c87c5fbaSopenharmony_ci    if (sep)
800c87c5fbaSopenharmony_ci      *sep = '\000';
801c87c5fbaSopenharmony_ci    oscore_conf_file = arg;
802c87c5fbaSopenharmony_ci
803c87c5fbaSopenharmony_ci    if (sep) {
804c87c5fbaSopenharmony_ci      sep++;
805c87c5fbaSopenharmony_ci      oscore_seq_save_file = sep;
806c87c5fbaSopenharmony_ci    }
807c87c5fbaSopenharmony_ci    return 1;
808c87c5fbaSopenharmony_ci  }
809c87c5fbaSopenharmony_ci  fprintf(stderr, "OSCORE support not enabled\n");
810c87c5fbaSopenharmony_ci  return 0;
811c87c5fbaSopenharmony_ci}
812c87c5fbaSopenharmony_ci
813c87c5fbaSopenharmony_ci/**
814c87c5fbaSopenharmony_ci * Sets global URI options according to the URI passed as @p arg.
815c87c5fbaSopenharmony_ci * This function returns 0 on success or -1 on error.
816c87c5fbaSopenharmony_ci *
817c87c5fbaSopenharmony_ci * @param arg             The URI string.
818c87c5fbaSopenharmony_ci * @param create_uri_opts Flags that indicate whether Uri-Host and
819c87c5fbaSopenharmony_ci *                        Uri-Port should be suppressed.
820c87c5fbaSopenharmony_ci * @return 0 on success, -1 otherwise
821c87c5fbaSopenharmony_ci */
822c87c5fbaSopenharmony_cistatic int
823c87c5fbaSopenharmony_cicmdline_uri(char *arg) {
824c87c5fbaSopenharmony_ci
825c87c5fbaSopenharmony_ci  if (!proxy_scheme_option && proxy.host.length) {
826c87c5fbaSopenharmony_ci    /* create Proxy-Uri from argument */
827c87c5fbaSopenharmony_ci    size_t len = strlen(arg);
828c87c5fbaSopenharmony_ci    if (len > 1034) {
829c87c5fbaSopenharmony_ci      coap_log_err("Absolute URI length must be <= 1034 bytes for a proxy\n");
830c87c5fbaSopenharmony_ci      return -1;
831c87c5fbaSopenharmony_ci    }
832c87c5fbaSopenharmony_ci
833c87c5fbaSopenharmony_ci    coap_insert_optlist(&optlist,
834c87c5fbaSopenharmony_ci                        coap_new_optlist(COAP_OPTION_PROXY_URI,
835c87c5fbaSopenharmony_ci                                         len,
836c87c5fbaSopenharmony_ci                                         (unsigned char *)arg));
837c87c5fbaSopenharmony_ci
838c87c5fbaSopenharmony_ci  } else {      /* split arg into Uri-* options */
839c87c5fbaSopenharmony_ci    if (coap_split_uri((unsigned char *)arg, strlen(arg), &uri) < 0) {
840c87c5fbaSopenharmony_ci      coap_log_err("invalid CoAP URI\n");
841c87c5fbaSopenharmony_ci      return -1;
842c87c5fbaSopenharmony_ci    }
843c87c5fbaSopenharmony_ci
844c87c5fbaSopenharmony_ci    /* Need to special case use of reliable */
845c87c5fbaSopenharmony_ci    if (uri.scheme == COAP_URI_SCHEME_COAPS && reliable) {
846c87c5fbaSopenharmony_ci      if (!coap_tls_is_supported()) {
847c87c5fbaSopenharmony_ci        coap_log_emerg("coaps+tcp URI scheme not supported in this version of libcoap\n");
848c87c5fbaSopenharmony_ci        return -1;
849c87c5fbaSopenharmony_ci      } else {
850c87c5fbaSopenharmony_ci        uri.scheme = COAP_URI_SCHEME_COAPS_TCP;
851c87c5fbaSopenharmony_ci      }
852c87c5fbaSopenharmony_ci    }
853c87c5fbaSopenharmony_ci
854c87c5fbaSopenharmony_ci    if (uri.scheme == COAP_URI_SCHEME_COAP && reliable) {
855c87c5fbaSopenharmony_ci      if (!coap_tcp_is_supported()) {
856c87c5fbaSopenharmony_ci        coap_log_emerg("coap+tcp URI scheme not supported in this version of libcoap\n");
857c87c5fbaSopenharmony_ci        return -1;
858c87c5fbaSopenharmony_ci      } else {
859c87c5fbaSopenharmony_ci        uri.scheme = COAP_URI_SCHEME_COAP_TCP;
860c87c5fbaSopenharmony_ci      }
861c87c5fbaSopenharmony_ci    }
862c87c5fbaSopenharmony_ci  }
863c87c5fbaSopenharmony_ci  return 0;
864c87c5fbaSopenharmony_ci}
865c87c5fbaSopenharmony_ci
866c87c5fbaSopenharmony_cistatic int
867c87c5fbaSopenharmony_cicmdline_blocksize(char *arg) {
868c87c5fbaSopenharmony_ci  uint16_t size;
869c87c5fbaSopenharmony_ci
870c87c5fbaSopenharmony_ciagain:
871c87c5fbaSopenharmony_ci  size = 0;
872c87c5fbaSopenharmony_ci  while (*arg && *arg != ',')
873c87c5fbaSopenharmony_ci    size = size * 10 + (*arg++ - '0');
874c87c5fbaSopenharmony_ci
875c87c5fbaSopenharmony_ci  if (*arg == ',') {
876c87c5fbaSopenharmony_ci    arg++;
877c87c5fbaSopenharmony_ci    block.num = size;
878c87c5fbaSopenharmony_ci    if (size != 0) {
879c87c5fbaSopenharmony_ci      /* Random access selection - only handle single response */
880c87c5fbaSopenharmony_ci      single_block_requested = 1;
881c87c5fbaSopenharmony_ci    }
882c87c5fbaSopenharmony_ci    goto again;
883c87c5fbaSopenharmony_ci  }
884c87c5fbaSopenharmony_ci
885c87c5fbaSopenharmony_ci  if (size < 16) {
886c87c5fbaSopenharmony_ci    coap_log_warn("Minimum block size is 16\n");
887c87c5fbaSopenharmony_ci    return 0;
888c87c5fbaSopenharmony_ci  } else if (size > 1024) {
889c87c5fbaSopenharmony_ci    coap_log_warn("Maximum block size is 1024\n");
890c87c5fbaSopenharmony_ci    return 0;
891c87c5fbaSopenharmony_ci  } else if ((size % 16) != 0) {
892c87c5fbaSopenharmony_ci    coap_log_warn("Block size %u is not a multiple of 16\n", size);
893c87c5fbaSopenharmony_ci    return 0;
894c87c5fbaSopenharmony_ci  }
895c87c5fbaSopenharmony_ci  if (size)
896c87c5fbaSopenharmony_ci    block.szx = (coap_fls(size >> 4) - 1) & 0x07;
897c87c5fbaSopenharmony_ci
898c87c5fbaSopenharmony_ci  flags |= FLAGS_BLOCK;
899c87c5fbaSopenharmony_ci  return 1;
900c87c5fbaSopenharmony_ci}
901c87c5fbaSopenharmony_ci
902c87c5fbaSopenharmony_ci/* Called after processing the options from the commandline to set
903c87c5fbaSopenharmony_ci * Block1, Block2, Q-Block1 or Q-Block2 depending on method. */
904c87c5fbaSopenharmony_cistatic void
905c87c5fbaSopenharmony_ciset_blocksize(void) {
906c87c5fbaSopenharmony_ci  static unsigned char buf[4];        /* hack: temporarily take encoded bytes */
907c87c5fbaSopenharmony_ci  uint16_t opt;
908c87c5fbaSopenharmony_ci  unsigned int opt_length;
909c87c5fbaSopenharmony_ci
910c87c5fbaSopenharmony_ci  if (method != COAP_REQUEST_DELETE) {
911c87c5fbaSopenharmony_ci    if (method == COAP_REQUEST_GET || method == COAP_REQUEST_FETCH) {
912c87c5fbaSopenharmony_ci      if (coap_q_block_is_supported() && block_mode & COAP_BLOCK_TRY_Q_BLOCK)
913c87c5fbaSopenharmony_ci        opt = COAP_OPTION_Q_BLOCK2;
914c87c5fbaSopenharmony_ci      else
915c87c5fbaSopenharmony_ci        opt = COAP_OPTION_BLOCK2;
916c87c5fbaSopenharmony_ci    } else {
917c87c5fbaSopenharmony_ci      if (coap_q_block_is_supported() && block_mode & COAP_BLOCK_TRY_Q_BLOCK)
918c87c5fbaSopenharmony_ci        opt = COAP_OPTION_Q_BLOCK1;
919c87c5fbaSopenharmony_ci      else
920c87c5fbaSopenharmony_ci        opt = COAP_OPTION_BLOCK1;
921c87c5fbaSopenharmony_ci    }
922c87c5fbaSopenharmony_ci
923c87c5fbaSopenharmony_ci    block.m = (opt == COAP_OPTION_BLOCK1 || opt == COAP_OPTION_Q_BLOCK1) &&
924c87c5fbaSopenharmony_ci              ((1ull << (block.szx + 4)) < payload.length);
925c87c5fbaSopenharmony_ci
926c87c5fbaSopenharmony_ci    opt_length = coap_encode_var_safe(buf, sizeof(buf),
927c87c5fbaSopenharmony_ci                                      (block.num << 4 | block.m << 3 | block.szx));
928c87c5fbaSopenharmony_ci
929c87c5fbaSopenharmony_ci    coap_insert_optlist(&optlist, coap_new_optlist(opt, opt_length, buf));
930c87c5fbaSopenharmony_ci  }
931c87c5fbaSopenharmony_ci}
932c87c5fbaSopenharmony_ci
933c87c5fbaSopenharmony_cistatic void
934c87c5fbaSopenharmony_cicmdline_subscribe(char *arg) {
935c87c5fbaSopenharmony_ci  uint8_t buf[4];
936c87c5fbaSopenharmony_ci
937c87c5fbaSopenharmony_ci  obs_seconds = atoi(arg);
938c87c5fbaSopenharmony_ci  coap_insert_optlist(&optlist,
939c87c5fbaSopenharmony_ci                      coap_new_optlist(COAP_OPTION_OBSERVE,
940c87c5fbaSopenharmony_ci                                       coap_encode_var_safe(buf, sizeof(buf),
941c87c5fbaSopenharmony_ci                                                            COAP_OBSERVE_ESTABLISH), buf)
942c87c5fbaSopenharmony_ci                     );
943c87c5fbaSopenharmony_ci  doing_observe = 1;
944c87c5fbaSopenharmony_ci}
945c87c5fbaSopenharmony_ci
946c87c5fbaSopenharmony_cistatic int
947c87c5fbaSopenharmony_cicmdline_proxy(char *arg) {
948c87c5fbaSopenharmony_ci  if (coap_split_uri((unsigned char *)arg, strlen(arg), &proxy) < 0 ||
949c87c5fbaSopenharmony_ci      proxy.path.length != 0 || proxy.query.length != 0) {
950c87c5fbaSopenharmony_ci    coap_log_err("invalid CoAP Proxy definition\n");
951c87c5fbaSopenharmony_ci    return 0;
952c87c5fbaSopenharmony_ci  }
953c87c5fbaSopenharmony_ci  return 1;
954c87c5fbaSopenharmony_ci}
955c87c5fbaSopenharmony_ci
956c87c5fbaSopenharmony_cistatic inline void
957c87c5fbaSopenharmony_cicmdline_token(char *arg) {
958c87c5fbaSopenharmony_ci  the_token.length = min(sizeof(_token_data), strlen(arg));
959c87c5fbaSopenharmony_ci  if (the_token.length > 0) {
960c87c5fbaSopenharmony_ci    memcpy((char *)the_token.s, arg, the_token.length);
961c87c5fbaSopenharmony_ci  }
962c87c5fbaSopenharmony_ci}
963c87c5fbaSopenharmony_ci
964c87c5fbaSopenharmony_ci/**
965c87c5fbaSopenharmony_ci * Utility function to convert a hex digit to its corresponding
966c87c5fbaSopenharmony_ci * numerical value.
967c87c5fbaSopenharmony_ci *
968c87c5fbaSopenharmony_ci * param c  The hex digit to convert. Must be in [0-9A-Fa-f].
969c87c5fbaSopenharmony_ci *
970c87c5fbaSopenharmony_ci * return The numerical representation of @p c.
971c87c5fbaSopenharmony_ci */
972c87c5fbaSopenharmony_cistatic uint8_t
973c87c5fbaSopenharmony_cihex2char(char c) {
974c87c5fbaSopenharmony_ci  assert(isxdigit(c));
975c87c5fbaSopenharmony_ci  if ('a' <= c && c <= 'f')
976c87c5fbaSopenharmony_ci    return c - 'a' + 10;
977c87c5fbaSopenharmony_ci  else if ('A' <= c && c <= 'F')
978c87c5fbaSopenharmony_ci    return c - 'A' + 10;
979c87c5fbaSopenharmony_ci  else
980c87c5fbaSopenharmony_ci    return c - '0';
981c87c5fbaSopenharmony_ci}
982c87c5fbaSopenharmony_ci
983c87c5fbaSopenharmony_ci/**
984c87c5fbaSopenharmony_ci * Converts the sequence of hex digits in src to a sequence of bytes.
985c87c5fbaSopenharmony_ci *
986c87c5fbaSopenharmony_ci * This function returns the number of bytes that have been written to
987c87c5fbaSopenharmony_ci * @p dst.
988c87c5fbaSopenharmony_ci *
989c87c5fbaSopenharmony_ci * param[in]  src  The null-terminated hex string to convert.
990c87c5fbaSopenharmony_ci * param[out] dst  Conversion result.
991c87c5fbaSopenharmony_ci *
992c87c5fbaSopenharmony_ci * return The length of @p dst.
993c87c5fbaSopenharmony_ci */
994c87c5fbaSopenharmony_cistatic size_t
995c87c5fbaSopenharmony_ciconvert_hex_string(const char *src, uint8_t *dst) {
996c87c5fbaSopenharmony_ci  uint8_t *p = dst;
997c87c5fbaSopenharmony_ci  while (isxdigit((int)src[0]) && isxdigit((int)src[1])) {
998c87c5fbaSopenharmony_ci    *p++ = (hex2char(src[0]) << 4) + hex2char(src[1]);
999c87c5fbaSopenharmony_ci    src += 2;
1000c87c5fbaSopenharmony_ci  }
1001c87c5fbaSopenharmony_ci  if (src[0] != '\0') { /* error in hex input */
1002c87c5fbaSopenharmony_ci    coap_log_warn("invalid hex string in option '%s'\n", src);
1003c87c5fbaSopenharmony_ci  }
1004c87c5fbaSopenharmony_ci  return p - dst;
1005c87c5fbaSopenharmony_ci}
1006c87c5fbaSopenharmony_ci
1007c87c5fbaSopenharmony_cistatic void
1008c87c5fbaSopenharmony_cicmdline_option(char *arg) {
1009c87c5fbaSopenharmony_ci  unsigned int num = 0;
1010c87c5fbaSopenharmony_ci
1011c87c5fbaSopenharmony_ci  while (*arg && *arg != ',') {
1012c87c5fbaSopenharmony_ci    num = num * 10 + (*arg - '0');
1013c87c5fbaSopenharmony_ci    ++arg;
1014c87c5fbaSopenharmony_ci  }
1015c87c5fbaSopenharmony_ci  if (*arg == ',')
1016c87c5fbaSopenharmony_ci    ++arg;
1017c87c5fbaSopenharmony_ci
1018c87c5fbaSopenharmony_ci  /* read hex string when arg starts with "0x" */
1019c87c5fbaSopenharmony_ci  if (arg[0] == '0' && arg[1] == 'x') {
1020c87c5fbaSopenharmony_ci    /* As the command line option is part of our environment we can do
1021c87c5fbaSopenharmony_ci     * the conversion in place. */
1022c87c5fbaSopenharmony_ci    size_t len = convert_hex_string(arg + 2, (uint8_t *)arg);
1023c87c5fbaSopenharmony_ci
1024c87c5fbaSopenharmony_ci    /* On success, 2 * len + 2 == strlen(arg) */
1025c87c5fbaSopenharmony_ci    coap_insert_optlist(&optlist,
1026c87c5fbaSopenharmony_ci                        coap_new_optlist(num, len, (unsigned char *)arg));
1027c87c5fbaSopenharmony_ci  } else { /* null-terminated character string */
1028c87c5fbaSopenharmony_ci    coap_insert_optlist(&optlist,
1029c87c5fbaSopenharmony_ci                        coap_new_optlist(num, strlen(arg), (unsigned char *)arg));
1030c87c5fbaSopenharmony_ci  }
1031c87c5fbaSopenharmony_ci  if (num == COAP_OPTION_PROXY_SCHEME) {
1032c87c5fbaSopenharmony_ci    proxy_scheme_option = 1;
1033c87c5fbaSopenharmony_ci    if (strcasecmp(arg, "coaps+tcp") == 0) {
1034c87c5fbaSopenharmony_ci      proxy.scheme = COAP_URI_SCHEME_COAPS_TCP;
1035c87c5fbaSopenharmony_ci      proxy.port = COAPS_DEFAULT_PORT;
1036c87c5fbaSopenharmony_ci    } else if (strcasecmp(arg, "coap+tcp") == 0) {
1037c87c5fbaSopenharmony_ci      proxy.scheme = COAP_URI_SCHEME_COAP_TCP;
1038c87c5fbaSopenharmony_ci      proxy.port = COAP_DEFAULT_PORT;
1039c87c5fbaSopenharmony_ci    } else if (strcasecmp(arg, "coaps") == 0) {
1040c87c5fbaSopenharmony_ci      proxy.scheme = COAP_URI_SCHEME_COAPS;
1041c87c5fbaSopenharmony_ci      proxy.port = COAPS_DEFAULT_PORT;
1042c87c5fbaSopenharmony_ci    } else if (strcasecmp(arg, "coap") == 0) {
1043c87c5fbaSopenharmony_ci      proxy.scheme = COAP_URI_SCHEME_COAP;
1044c87c5fbaSopenharmony_ci      proxy.port = COAP_DEFAULT_PORT;
1045c87c5fbaSopenharmony_ci    } else {
1046c87c5fbaSopenharmony_ci      coap_log_warn("%s is not a supported CoAP Proxy-Scheme\n", arg);
1047c87c5fbaSopenharmony_ci    }
1048c87c5fbaSopenharmony_ci  }
1049c87c5fbaSopenharmony_ci  if (num == COAP_OPTION_URI_HOST) {
1050c87c5fbaSopenharmony_ci    uri_host_option = 1;
1051c87c5fbaSopenharmony_ci  }
1052c87c5fbaSopenharmony_ci}
1053c87c5fbaSopenharmony_ci
1054c87c5fbaSopenharmony_ci/**
1055c87c5fbaSopenharmony_ci * Calculates decimal value from hexadecimal ASCII character given in
1056c87c5fbaSopenharmony_ci * @p c. The caller must ensure that @p c actually represents a valid
1057c87c5fbaSopenharmony_ci * heaxdecimal character, e.g. with isxdigit(3).
1058c87c5fbaSopenharmony_ci *
1059c87c5fbaSopenharmony_ci * @hideinitializer
1060c87c5fbaSopenharmony_ci */
1061c87c5fbaSopenharmony_ci#define hexchar_to_dec(c) ((c) & 0x40 ? ((c) & 0x0F) + 9 : ((c) & 0x0F))
1062c87c5fbaSopenharmony_ci
1063c87c5fbaSopenharmony_ci/**
1064c87c5fbaSopenharmony_ci * Decodes percent-encoded characters while copying the string @p seg
1065c87c5fbaSopenharmony_ci * of size @p length to @p buf. The caller of this function must
1066c87c5fbaSopenharmony_ci * ensure that the percent-encodings are correct (i.e. the character
1067c87c5fbaSopenharmony_ci * '%' is always followed by two hex digits. and that @p buf provides
1068c87c5fbaSopenharmony_ci * sufficient space to hold the result. This function is supposed to
1069c87c5fbaSopenharmony_ci * be called by make_decoded_option() only.
1070c87c5fbaSopenharmony_ci *
1071c87c5fbaSopenharmony_ci * @param seg     The segment to decode and copy.
1072c87c5fbaSopenharmony_ci * @param length  Length of @p seg.
1073c87c5fbaSopenharmony_ci * @param buf     The result buffer.
1074c87c5fbaSopenharmony_ci */
1075c87c5fbaSopenharmony_cistatic void
1076c87c5fbaSopenharmony_cidecode_segment(const uint8_t *seg, size_t length, unsigned char *buf) {
1077c87c5fbaSopenharmony_ci
1078c87c5fbaSopenharmony_ci  while (length--) {
1079c87c5fbaSopenharmony_ci
1080c87c5fbaSopenharmony_ci    if (*seg == '%') {
1081c87c5fbaSopenharmony_ci      *buf = (hexchar_to_dec(seg[1]) << 4) + hexchar_to_dec(seg[2]);
1082c87c5fbaSopenharmony_ci
1083c87c5fbaSopenharmony_ci      seg += 2;
1084c87c5fbaSopenharmony_ci      length -= 2;
1085c87c5fbaSopenharmony_ci    } else {
1086c87c5fbaSopenharmony_ci      *buf = *seg;
1087c87c5fbaSopenharmony_ci    }
1088c87c5fbaSopenharmony_ci
1089c87c5fbaSopenharmony_ci    ++buf;
1090c87c5fbaSopenharmony_ci    ++seg;
1091c87c5fbaSopenharmony_ci  }
1092c87c5fbaSopenharmony_ci}
1093c87c5fbaSopenharmony_ci
1094c87c5fbaSopenharmony_ci/**
1095c87c5fbaSopenharmony_ci * Runs through the given path (or query) segment and checks if
1096c87c5fbaSopenharmony_ci * percent-encodings are correct. This function returns @c -1 on error
1097c87c5fbaSopenharmony_ci * or the length of @p s when decoded.
1098c87c5fbaSopenharmony_ci */
1099c87c5fbaSopenharmony_cistatic int
1100c87c5fbaSopenharmony_cicheck_segment(const uint8_t *s, size_t length) {
1101c87c5fbaSopenharmony_ci
1102c87c5fbaSopenharmony_ci  int n = 0;
1103c87c5fbaSopenharmony_ci
1104c87c5fbaSopenharmony_ci  while (length) {
1105c87c5fbaSopenharmony_ci    if (*s == '%') {
1106c87c5fbaSopenharmony_ci      if (length < 2 || !(isxdigit(s[1]) && isxdigit(s[2])))
1107c87c5fbaSopenharmony_ci        return -1;
1108c87c5fbaSopenharmony_ci
1109c87c5fbaSopenharmony_ci      s += 2;
1110c87c5fbaSopenharmony_ci      length -= 2;
1111c87c5fbaSopenharmony_ci    }
1112c87c5fbaSopenharmony_ci
1113c87c5fbaSopenharmony_ci    ++s;
1114c87c5fbaSopenharmony_ci    ++n;
1115c87c5fbaSopenharmony_ci    --length;
1116c87c5fbaSopenharmony_ci  }
1117c87c5fbaSopenharmony_ci
1118c87c5fbaSopenharmony_ci  return n;
1119c87c5fbaSopenharmony_ci}
1120c87c5fbaSopenharmony_ci
1121c87c5fbaSopenharmony_cistatic int
1122c87c5fbaSopenharmony_cicmdline_input(char *text, coap_string_t *buf) {
1123c87c5fbaSopenharmony_ci  int len;
1124c87c5fbaSopenharmony_ci  len = check_segment((unsigned char *)text, strlen(text));
1125c87c5fbaSopenharmony_ci
1126c87c5fbaSopenharmony_ci  if (len < 0)
1127c87c5fbaSopenharmony_ci    return 0;
1128c87c5fbaSopenharmony_ci
1129c87c5fbaSopenharmony_ci  buf->s = (unsigned char *)coap_malloc(len);
1130c87c5fbaSopenharmony_ci  if (!buf->s)
1131c87c5fbaSopenharmony_ci    return 0;
1132c87c5fbaSopenharmony_ci
1133c87c5fbaSopenharmony_ci  buf->length = len;
1134c87c5fbaSopenharmony_ci  decode_segment((unsigned char *)text, strlen(text), buf->s);
1135c87c5fbaSopenharmony_ci  return 1;
1136c87c5fbaSopenharmony_ci}
1137c87c5fbaSopenharmony_ci
1138c87c5fbaSopenharmony_cistatic int
1139c87c5fbaSopenharmony_cicmdline_input_from_file(char *filename, coap_string_t *buf) {
1140c87c5fbaSopenharmony_ci  FILE *inputfile = NULL;
1141c87c5fbaSopenharmony_ci  ssize_t len;
1142c87c5fbaSopenharmony_ci  int result = 1;
1143c87c5fbaSopenharmony_ci  struct stat statbuf;
1144c87c5fbaSopenharmony_ci
1145c87c5fbaSopenharmony_ci  if (!filename || !buf)
1146c87c5fbaSopenharmony_ci    return 0;
1147c87c5fbaSopenharmony_ci
1148c87c5fbaSopenharmony_ci  if (filename[0] == '-' && !filename[1]) { /* read from stdin */
1149c87c5fbaSopenharmony_ci    buf->length = 20000;
1150c87c5fbaSopenharmony_ci    buf->s = (unsigned char *)coap_malloc(buf->length);
1151c87c5fbaSopenharmony_ci    if (!buf->s)
1152c87c5fbaSopenharmony_ci      return 0;
1153c87c5fbaSopenharmony_ci
1154c87c5fbaSopenharmony_ci    inputfile = stdin;
1155c87c5fbaSopenharmony_ci  } else {
1156c87c5fbaSopenharmony_ci    /* read from specified input file */
1157c87c5fbaSopenharmony_ci    inputfile = fopen(filename, "r");
1158c87c5fbaSopenharmony_ci    if (!inputfile) {
1159c87c5fbaSopenharmony_ci      perror("cmdline_input_from_file: fopen");
1160c87c5fbaSopenharmony_ci      return 0;
1161c87c5fbaSopenharmony_ci    }
1162c87c5fbaSopenharmony_ci
1163c87c5fbaSopenharmony_ci    if (fstat(fileno(inputfile), &statbuf) < 0) {
1164c87c5fbaSopenharmony_ci      perror("cmdline_input_from_file: stat");
1165c87c5fbaSopenharmony_ci      fclose(inputfile);
1166c87c5fbaSopenharmony_ci      return 0;
1167c87c5fbaSopenharmony_ci    }
1168c87c5fbaSopenharmony_ci
1169c87c5fbaSopenharmony_ci    buf->length = statbuf.st_size;
1170c87c5fbaSopenharmony_ci    buf->s = (unsigned char *)coap_malloc(buf->length);
1171c87c5fbaSopenharmony_ci    if (!buf->s) {
1172c87c5fbaSopenharmony_ci      fclose(inputfile);
1173c87c5fbaSopenharmony_ci      return 0;
1174c87c5fbaSopenharmony_ci    }
1175c87c5fbaSopenharmony_ci  }
1176c87c5fbaSopenharmony_ci
1177c87c5fbaSopenharmony_ci  len = fread(buf->s, 1, buf->length, inputfile);
1178c87c5fbaSopenharmony_ci
1179c87c5fbaSopenharmony_ci  if (len < 0 || ((size_t)len < buf->length)) {
1180c87c5fbaSopenharmony_ci    if (ferror(inputfile) != 0) {
1181c87c5fbaSopenharmony_ci      perror("cmdline_input_from_file: fread");
1182c87c5fbaSopenharmony_ci      coap_free(buf->s);
1183c87c5fbaSopenharmony_ci      buf->length = 0;
1184c87c5fbaSopenharmony_ci      buf->s = NULL;
1185c87c5fbaSopenharmony_ci      result = 0;
1186c87c5fbaSopenharmony_ci    } else {
1187c87c5fbaSopenharmony_ci      buf->length = len;
1188c87c5fbaSopenharmony_ci    }
1189c87c5fbaSopenharmony_ci  }
1190c87c5fbaSopenharmony_ci
1191c87c5fbaSopenharmony_ci  if (inputfile != stdin)
1192c87c5fbaSopenharmony_ci    fclose(inputfile);
1193c87c5fbaSopenharmony_ci
1194c87c5fbaSopenharmony_ci  return result;
1195c87c5fbaSopenharmony_ci}
1196c87c5fbaSopenharmony_ci
1197c87c5fbaSopenharmony_cistatic method_t
1198c87c5fbaSopenharmony_cicmdline_method(char *arg) {
1199c87c5fbaSopenharmony_ci  static const char *methods[] =
1200c87c5fbaSopenharmony_ci  { 0, "get", "post", "put", "delete", "fetch", "patch", "ipatch", 0};
1201c87c5fbaSopenharmony_ci  unsigned char i;
1202c87c5fbaSopenharmony_ci
1203c87c5fbaSopenharmony_ci  for (i=1; methods[i] && strcasecmp(arg,methods[i]) != 0 ; ++i)
1204c87c5fbaSopenharmony_ci    ;
1205c87c5fbaSopenharmony_ci
1206c87c5fbaSopenharmony_ci  return i;     /* note that we do not prevent illegal methods */
1207c87c5fbaSopenharmony_ci}
1208c87c5fbaSopenharmony_ci
1209c87c5fbaSopenharmony_cistatic ssize_t
1210c87c5fbaSopenharmony_cicmdline_read_user(char *arg, unsigned char **buf, size_t maxlen) {
1211c87c5fbaSopenharmony_ci  size_t len = strnlen(arg, maxlen);
1212c87c5fbaSopenharmony_ci  if (len) {
1213c87c5fbaSopenharmony_ci    *buf = (unsigned char *)arg;
1214c87c5fbaSopenharmony_ci    /* len is the size or less, so 0 terminate to maxlen */
1215c87c5fbaSopenharmony_ci    (*buf)[len] = '\000';
1216c87c5fbaSopenharmony_ci  }
1217c87c5fbaSopenharmony_ci  /* 0 length Identity is valid */
1218c87c5fbaSopenharmony_ci  return len;
1219c87c5fbaSopenharmony_ci}
1220c87c5fbaSopenharmony_ci
1221c87c5fbaSopenharmony_cistatic ssize_t
1222c87c5fbaSopenharmony_cicmdline_read_key(char *arg, unsigned char **buf, size_t maxlen) {
1223c87c5fbaSopenharmony_ci  size_t len = strnlen(arg, maxlen);
1224c87c5fbaSopenharmony_ci  if (len) {
1225c87c5fbaSopenharmony_ci    *buf = (unsigned char *)arg;
1226c87c5fbaSopenharmony_ci    return len;
1227c87c5fbaSopenharmony_ci  }
1228c87c5fbaSopenharmony_ci  /* Need at least one byte for the pre-shared key */
1229c87c5fbaSopenharmony_ci  coap_log_crit("Invalid Pre-Shared Key specified\n");
1230c87c5fbaSopenharmony_ci  return -1;
1231c87c5fbaSopenharmony_ci}
1232c87c5fbaSopenharmony_ci
1233c87c5fbaSopenharmony_cistatic int
1234c87c5fbaSopenharmony_cicmdline_read_hint_check(const char *arg) {
1235c87c5fbaSopenharmony_ci  FILE *fp = fopen(arg, "r");
1236c87c5fbaSopenharmony_ci  static char tmpbuf[256];
1237c87c5fbaSopenharmony_ci  if (fp == NULL) {
1238c87c5fbaSopenharmony_ci    coap_log_err("Hint file: %s: Unable to open\n", arg);
1239c87c5fbaSopenharmony_ci    return 0;
1240c87c5fbaSopenharmony_ci  }
1241c87c5fbaSopenharmony_ci  while (fgets(tmpbuf, sizeof(tmpbuf), fp) != NULL) {
1242c87c5fbaSopenharmony_ci    char *cp = tmpbuf;
1243c87c5fbaSopenharmony_ci    char *tcp = strchr(cp, '\n');
1244c87c5fbaSopenharmony_ci
1245c87c5fbaSopenharmony_ci    if (tmpbuf[0] == '#')
1246c87c5fbaSopenharmony_ci      continue;
1247c87c5fbaSopenharmony_ci    if (tcp)
1248c87c5fbaSopenharmony_ci      *tcp = '\000';
1249c87c5fbaSopenharmony_ci
1250c87c5fbaSopenharmony_ci    tcp = strchr(cp, ',');
1251c87c5fbaSopenharmony_ci    if (tcp) {
1252c87c5fbaSopenharmony_ci      ih_def_t *new_ih_list;
1253c87c5fbaSopenharmony_ci      new_ih_list = realloc(valid_ihs.ih_list,
1254c87c5fbaSopenharmony_ci                            (valid_ihs.count + 1)*sizeof(valid_ihs.ih_list[0]));
1255c87c5fbaSopenharmony_ci      if (new_ih_list == NULL) {
1256c87c5fbaSopenharmony_ci        break;
1257c87c5fbaSopenharmony_ci      }
1258c87c5fbaSopenharmony_ci      valid_ihs.ih_list = new_ih_list;
1259c87c5fbaSopenharmony_ci      valid_ihs.ih_list[valid_ihs.count].hint_match = strndup(cp, tcp-cp);
1260c87c5fbaSopenharmony_ci      cp = tcp+1;
1261c87c5fbaSopenharmony_ci      tcp = strchr(cp, ',');
1262c87c5fbaSopenharmony_ci      if (tcp) {
1263c87c5fbaSopenharmony_ci        valid_ihs.ih_list[valid_ihs.count].new_identity =
1264c87c5fbaSopenharmony_ci            coap_new_bin_const((const uint8_t *)cp, tcp-cp);
1265c87c5fbaSopenharmony_ci        cp = tcp+1;
1266c87c5fbaSopenharmony_ci        valid_ihs.ih_list[valid_ihs.count].new_key =
1267c87c5fbaSopenharmony_ci            coap_new_bin_const((const uint8_t *)cp, strlen(cp));
1268c87c5fbaSopenharmony_ci        valid_ihs.count++;
1269c87c5fbaSopenharmony_ci      } else {
1270c87c5fbaSopenharmony_ci        /* Badly formatted */
1271c87c5fbaSopenharmony_ci        free(valid_ihs.ih_list[valid_ihs.count].hint_match);
1272c87c5fbaSopenharmony_ci      }
1273c87c5fbaSopenharmony_ci    }
1274c87c5fbaSopenharmony_ci  }
1275c87c5fbaSopenharmony_ci  fclose(fp);
1276c87c5fbaSopenharmony_ci  return valid_ihs.count > 0;
1277c87c5fbaSopenharmony_ci}
1278c87c5fbaSopenharmony_ci
1279c87c5fbaSopenharmony_cistatic int
1280c87c5fbaSopenharmony_civerify_cn_callback(const char *cn,
1281c87c5fbaSopenharmony_ci                   const uint8_t *asn1_public_cert COAP_UNUSED,
1282c87c5fbaSopenharmony_ci                   size_t asn1_length COAP_UNUSED,
1283c87c5fbaSopenharmony_ci                   coap_session_t *session COAP_UNUSED,
1284c87c5fbaSopenharmony_ci                   unsigned depth,
1285c87c5fbaSopenharmony_ci                   int validated COAP_UNUSED,
1286c87c5fbaSopenharmony_ci                   void *arg COAP_UNUSED) {
1287c87c5fbaSopenharmony_ci  coap_log_info("CN '%s' presented by server (%s)\n",
1288c87c5fbaSopenharmony_ci                cn, depth ? "CA" : "Certificate");
1289c87c5fbaSopenharmony_ci  return 1;
1290c87c5fbaSopenharmony_ci}
1291c87c5fbaSopenharmony_ci
1292c87c5fbaSopenharmony_cistatic const coap_dtls_cpsk_info_t *
1293c87c5fbaSopenharmony_civerify_ih_callback(coap_str_const_t *hint,
1294c87c5fbaSopenharmony_ci                   coap_session_t *c_session COAP_UNUSED,
1295c87c5fbaSopenharmony_ci                   void *arg) {
1296c87c5fbaSopenharmony_ci  coap_dtls_cpsk_info_t *psk_info = (coap_dtls_cpsk_info_t *)arg;
1297c87c5fbaSopenharmony_ci  char lhint[COAP_DTLS_HINT_LENGTH];
1298c87c5fbaSopenharmony_ci  static coap_dtls_cpsk_info_t psk_identity_info;
1299c87c5fbaSopenharmony_ci  size_t i;
1300c87c5fbaSopenharmony_ci
1301c87c5fbaSopenharmony_ci  snprintf(lhint, sizeof(lhint), "%.*s", (int)hint->length, hint->s);
1302c87c5fbaSopenharmony_ci  coap_log_info("Identity Hint '%s' provided\n", lhint);
1303c87c5fbaSopenharmony_ci
1304c87c5fbaSopenharmony_ci  /* Test for hint to possibly change identity + key */
1305c87c5fbaSopenharmony_ci  for (i = 0; i < valid_ihs.count; i++) {
1306c87c5fbaSopenharmony_ci    if (strcmp(lhint, valid_ihs.ih_list[i].hint_match) == 0) {
1307c87c5fbaSopenharmony_ci      /* Preset */
1308c87c5fbaSopenharmony_ci      psk_identity_info = *psk_info;
1309c87c5fbaSopenharmony_ci      if (valid_ihs.ih_list[i].new_key) {
1310c87c5fbaSopenharmony_ci        psk_identity_info.key = *valid_ihs.ih_list[i].new_key;
1311c87c5fbaSopenharmony_ci      }
1312c87c5fbaSopenharmony_ci      if (valid_ihs.ih_list[i].new_identity) {
1313c87c5fbaSopenharmony_ci        psk_identity_info.identity = *valid_ihs.ih_list[i].new_identity;
1314c87c5fbaSopenharmony_ci      }
1315c87c5fbaSopenharmony_ci      coap_log_info("Switching to using '%s' identity + '%s' key\n",
1316c87c5fbaSopenharmony_ci                    psk_identity_info.identity.s, psk_identity_info.key.s);
1317c87c5fbaSopenharmony_ci      return &psk_identity_info;
1318c87c5fbaSopenharmony_ci    }
1319c87c5fbaSopenharmony_ci  }
1320c87c5fbaSopenharmony_ci  /* Just use the defined key for now as passed in by arg */
1321c87c5fbaSopenharmony_ci  return psk_info;
1322c87c5fbaSopenharmony_ci}
1323c87c5fbaSopenharmony_ci
1324c87c5fbaSopenharmony_cistatic coap_dtls_pki_t *
1325c87c5fbaSopenharmony_cisetup_pki(coap_context_t *ctx) {
1326c87c5fbaSopenharmony_ci  static coap_dtls_pki_t dtls_pki;
1327c87c5fbaSopenharmony_ci  static char client_sni[256];
1328c87c5fbaSopenharmony_ci
1329c87c5fbaSopenharmony_ci  /* If general root CAs are defined */
1330c87c5fbaSopenharmony_ci  if (root_ca_file) {
1331c87c5fbaSopenharmony_ci    struct stat stbuf;
1332c87c5fbaSopenharmony_ci    if ((stat(root_ca_file, &stbuf) == 0) && S_ISDIR(stbuf.st_mode)) {
1333c87c5fbaSopenharmony_ci      coap_context_set_pki_root_cas(ctx, NULL, root_ca_file);
1334c87c5fbaSopenharmony_ci    } else {
1335c87c5fbaSopenharmony_ci      coap_context_set_pki_root_cas(ctx, root_ca_file, NULL);
1336c87c5fbaSopenharmony_ci    }
1337c87c5fbaSopenharmony_ci  }
1338c87c5fbaSopenharmony_ci
1339c87c5fbaSopenharmony_ci  memset(client_sni, 0, sizeof(client_sni));
1340c87c5fbaSopenharmony_ci  memset(&dtls_pki, 0, sizeof(dtls_pki));
1341c87c5fbaSopenharmony_ci  dtls_pki.version = COAP_DTLS_PKI_SETUP_VERSION;
1342c87c5fbaSopenharmony_ci  if (ca_file || root_ca_file) {
1343c87c5fbaSopenharmony_ci    /*
1344c87c5fbaSopenharmony_ci     * Add in additional certificate checking.
1345c87c5fbaSopenharmony_ci     * This list of enabled can be tuned for the specific
1346c87c5fbaSopenharmony_ci     * requirements - see 'man coap_encryption'.
1347c87c5fbaSopenharmony_ci     *
1348c87c5fbaSopenharmony_ci     * Note: root_ca_file is setup separately using
1349c87c5fbaSopenharmony_ci     * coap_context_set_pki_root_cas(), but this is used to define what
1350c87c5fbaSopenharmony_ci     * checking actually takes place.
1351c87c5fbaSopenharmony_ci     */
1352c87c5fbaSopenharmony_ci    dtls_pki.verify_peer_cert        = verify_peer_cert;
1353c87c5fbaSopenharmony_ci    dtls_pki.check_common_ca         = !root_ca_file;
1354c87c5fbaSopenharmony_ci    dtls_pki.allow_self_signed       = 1;
1355c87c5fbaSopenharmony_ci    dtls_pki.allow_expired_certs     = 1;
1356c87c5fbaSopenharmony_ci    dtls_pki.cert_chain_validation   = 1;
1357c87c5fbaSopenharmony_ci    dtls_pki.cert_chain_verify_depth = 2;
1358c87c5fbaSopenharmony_ci    dtls_pki.check_cert_revocation   = 1;
1359c87c5fbaSopenharmony_ci    dtls_pki.allow_no_crl            = 1;
1360c87c5fbaSopenharmony_ci    dtls_pki.allow_expired_crl       = 1;
1361c87c5fbaSopenharmony_ci  } else if (is_rpk_not_cert) {
1362c87c5fbaSopenharmony_ci    dtls_pki.verify_peer_cert        = verify_peer_cert;
1363c87c5fbaSopenharmony_ci  }
1364c87c5fbaSopenharmony_ci  dtls_pki.is_rpk_not_cert = is_rpk_not_cert;
1365c87c5fbaSopenharmony_ci  dtls_pki.validate_cn_call_back = verify_cn_callback;
1366c87c5fbaSopenharmony_ci  if ((uri.host.length == 3 && memcmp(uri.host.s, "::1", 3) != 0) ||
1367c87c5fbaSopenharmony_ci      (uri.host.length == 9 && memcmp(uri.host.s, "127.0.0.1", 9) != 0))
1368c87c5fbaSopenharmony_ci    memcpy(client_sni, uri.host.s, min(uri.host.length, sizeof(client_sni)-1));
1369c87c5fbaSopenharmony_ci  else
1370c87c5fbaSopenharmony_ci    memcpy(client_sni, "localhost", 9);
1371c87c5fbaSopenharmony_ci
1372c87c5fbaSopenharmony_ci  dtls_pki.client_sni = client_sni;
1373c87c5fbaSopenharmony_ci  if ((key_file && strncasecmp(key_file, "pkcs11:", 7) == 0) ||
1374c87c5fbaSopenharmony_ci      (cert_file && strncasecmp(cert_file, "pkcs11:", 7) == 0) ||
1375c87c5fbaSopenharmony_ci      (ca_file && strncasecmp(ca_file, "pkcs11:", 7) == 0)) {
1376c87c5fbaSopenharmony_ci    dtls_pki.pki_key.key_type = COAP_PKI_KEY_PKCS11;
1377c87c5fbaSopenharmony_ci    dtls_pki.pki_key.key.pkcs11.public_cert = cert_file;
1378c87c5fbaSopenharmony_ci    dtls_pki.pki_key.key.pkcs11.private_key = key_file ?
1379c87c5fbaSopenharmony_ci                                              key_file : cert_file;
1380c87c5fbaSopenharmony_ci    dtls_pki.pki_key.key.pkcs11.ca = ca_file;
1381c87c5fbaSopenharmony_ci    dtls_pki.pki_key.key.pkcs11.user_pin = pkcs11_pin;
1382c87c5fbaSopenharmony_ci  } else if (!is_rpk_not_cert) {
1383c87c5fbaSopenharmony_ci    dtls_pki.pki_key.key_type = COAP_PKI_KEY_PEM;
1384c87c5fbaSopenharmony_ci    dtls_pki.pki_key.key.pem.public_cert = cert_file;
1385c87c5fbaSopenharmony_ci    dtls_pki.pki_key.key.pem.private_key = key_file ? key_file : cert_file;
1386c87c5fbaSopenharmony_ci    dtls_pki.pki_key.key.pem.ca_file = ca_file;
1387c87c5fbaSopenharmony_ci  } else {
1388c87c5fbaSopenharmony_ci    /* Map file into memory */
1389c87c5fbaSopenharmony_ci    if (ca_mem == 0 && cert_mem == 0 && key_mem == 0) {
1390c87c5fbaSopenharmony_ci      ca_mem = read_file_mem(ca_file, &ca_mem_len);
1391c87c5fbaSopenharmony_ci      cert_mem = read_file_mem(cert_file, &cert_mem_len);
1392c87c5fbaSopenharmony_ci      key_mem = read_file_mem(key_file, &key_mem_len);
1393c87c5fbaSopenharmony_ci    }
1394c87c5fbaSopenharmony_ci    dtls_pki.pki_key.key_type = COAP_PKI_KEY_PEM_BUF;
1395c87c5fbaSopenharmony_ci    dtls_pki.pki_key.key.pem_buf.ca_cert = ca_mem;
1396c87c5fbaSopenharmony_ci    dtls_pki.pki_key.key.pem_buf.public_cert = cert_mem;
1397c87c5fbaSopenharmony_ci    dtls_pki.pki_key.key.pem_buf.private_key = key_mem ? key_mem : cert_mem;
1398c87c5fbaSopenharmony_ci    dtls_pki.pki_key.key.pem_buf.ca_cert_len = ca_mem_len;
1399c87c5fbaSopenharmony_ci    dtls_pki.pki_key.key.pem_buf.public_cert_len = cert_mem_len;
1400c87c5fbaSopenharmony_ci    dtls_pki.pki_key.key.pem_buf.private_key_len = key_mem ?
1401c87c5fbaSopenharmony_ci                                                   key_mem_len : cert_mem_len;
1402c87c5fbaSopenharmony_ci  }
1403c87c5fbaSopenharmony_ci  return &dtls_pki;
1404c87c5fbaSopenharmony_ci}
1405c87c5fbaSopenharmony_ci
1406c87c5fbaSopenharmony_cistatic coap_dtls_cpsk_t *
1407c87c5fbaSopenharmony_cisetup_psk(const uint8_t *identity,
1408c87c5fbaSopenharmony_ci          size_t identity_len,
1409c87c5fbaSopenharmony_ci          const uint8_t *key,
1410c87c5fbaSopenharmony_ci          size_t key_len) {
1411c87c5fbaSopenharmony_ci  static coap_dtls_cpsk_t dtls_psk;
1412c87c5fbaSopenharmony_ci  static char client_sni[256];
1413c87c5fbaSopenharmony_ci
1414c87c5fbaSopenharmony_ci  memset(client_sni, 0, sizeof(client_sni));
1415c87c5fbaSopenharmony_ci  memset(&dtls_psk, 0, sizeof(dtls_psk));
1416c87c5fbaSopenharmony_ci  dtls_psk.version = COAP_DTLS_CPSK_SETUP_VERSION;
1417c87c5fbaSopenharmony_ci  dtls_psk.validate_ih_call_back = verify_ih_callback;
1418c87c5fbaSopenharmony_ci  dtls_psk.ih_call_back_arg = &dtls_psk.psk_info;
1419c87c5fbaSopenharmony_ci  if (uri.host.length)
1420c87c5fbaSopenharmony_ci    memcpy(client_sni, uri.host.s,
1421c87c5fbaSopenharmony_ci           min(uri.host.length, sizeof(client_sni) - 1));
1422c87c5fbaSopenharmony_ci  else
1423c87c5fbaSopenharmony_ci    memcpy(client_sni, "localhost", 9);
1424c87c5fbaSopenharmony_ci  dtls_psk.client_sni = client_sni;
1425c87c5fbaSopenharmony_ci  dtls_psk.psk_info.identity.s = identity;
1426c87c5fbaSopenharmony_ci  dtls_psk.psk_info.identity.length = identity_len;
1427c87c5fbaSopenharmony_ci  dtls_psk.psk_info.key.s = key;
1428c87c5fbaSopenharmony_ci  dtls_psk.psk_info.key.length = key_len;
1429c87c5fbaSopenharmony_ci  return &dtls_psk;
1430c87c5fbaSopenharmony_ci}
1431c87c5fbaSopenharmony_ci
1432c87c5fbaSopenharmony_cistatic coap_session_t *
1433c87c5fbaSopenharmony_ciopen_session(coap_context_t *ctx,
1434c87c5fbaSopenharmony_ci             coap_proto_t proto,
1435c87c5fbaSopenharmony_ci             coap_address_t *bind_addr,
1436c87c5fbaSopenharmony_ci             coap_address_t *dst,
1437c87c5fbaSopenharmony_ci             const uint8_t *identity,
1438c87c5fbaSopenharmony_ci             size_t identity_len,
1439c87c5fbaSopenharmony_ci             const uint8_t *key,
1440c87c5fbaSopenharmony_ci             size_t key_len) {
1441c87c5fbaSopenharmony_ci  coap_session_t *session;
1442c87c5fbaSopenharmony_ci
1443c87c5fbaSopenharmony_ci  if (proto == COAP_PROTO_DTLS || proto == COAP_PROTO_TLS ||
1444c87c5fbaSopenharmony_ci      proto == COAP_PROTO_WSS) {
1445c87c5fbaSopenharmony_ci    /* Encrypted session */
1446c87c5fbaSopenharmony_ci    if (root_ca_file || ca_file || cert_file) {
1447c87c5fbaSopenharmony_ci      /* Setup PKI session */
1448c87c5fbaSopenharmony_ci      coap_dtls_pki_t *dtls_pki = setup_pki(ctx);
1449c87c5fbaSopenharmony_ci      if (doing_oscore) {
1450c87c5fbaSopenharmony_ci        session = coap_new_client_session_oscore_pki(ctx, bind_addr, dst,
1451c87c5fbaSopenharmony_ci                                                     proto, dtls_pki,
1452c87c5fbaSopenharmony_ci                                                     oscore_conf);
1453c87c5fbaSopenharmony_ci      } else
1454c87c5fbaSopenharmony_ci        session = coap_new_client_session_pki(ctx, bind_addr, dst, proto,
1455c87c5fbaSopenharmony_ci                                              dtls_pki);
1456c87c5fbaSopenharmony_ci    } else if (identity || key) {
1457c87c5fbaSopenharmony_ci      /* Setup PSK session */
1458c87c5fbaSopenharmony_ci      coap_dtls_cpsk_t *dtls_psk = setup_psk(identity, identity_len,
1459c87c5fbaSopenharmony_ci                                             key, key_len);
1460c87c5fbaSopenharmony_ci      if (doing_oscore) {
1461c87c5fbaSopenharmony_ci        session = coap_new_client_session_oscore_psk(ctx, bind_addr, dst,
1462c87c5fbaSopenharmony_ci                                                     proto, dtls_psk,
1463c87c5fbaSopenharmony_ci                                                     oscore_conf);
1464c87c5fbaSopenharmony_ci      } else
1465c87c5fbaSopenharmony_ci        session = coap_new_client_session_psk2(ctx, bind_addr, dst, proto,
1466c87c5fbaSopenharmony_ci                                               dtls_psk);
1467c87c5fbaSopenharmony_ci    } else {
1468c87c5fbaSopenharmony_ci      /* No PKI or PSK defined, as encrypted, use PKI */
1469c87c5fbaSopenharmony_ci      coap_dtls_pki_t *dtls_pki = setup_pki(ctx);
1470c87c5fbaSopenharmony_ci      if (doing_oscore) {
1471c87c5fbaSopenharmony_ci        session = coap_new_client_session_oscore_pki(ctx, bind_addr, dst,
1472c87c5fbaSopenharmony_ci                                                     proto, dtls_pki,
1473c87c5fbaSopenharmony_ci                                                     oscore_conf);
1474c87c5fbaSopenharmony_ci      } else
1475c87c5fbaSopenharmony_ci        session = coap_new_client_session_pki(ctx, bind_addr, dst, proto,
1476c87c5fbaSopenharmony_ci                                              dtls_pki);
1477c87c5fbaSopenharmony_ci    }
1478c87c5fbaSopenharmony_ci  } else {
1479c87c5fbaSopenharmony_ci    /* Non-encrypted session */
1480c87c5fbaSopenharmony_ci    if (doing_oscore) {
1481c87c5fbaSopenharmony_ci      session = coap_new_client_session_oscore(ctx, bind_addr, dst, proto,
1482c87c5fbaSopenharmony_ci                                               oscore_conf);
1483c87c5fbaSopenharmony_ci    } else
1484c87c5fbaSopenharmony_ci      session = coap_new_client_session(ctx, bind_addr, dst, proto);
1485c87c5fbaSopenharmony_ci  }
1486c87c5fbaSopenharmony_ci  if (session && (proto == COAP_PROTO_WS || proto == COAP_PROTO_WSS)) {
1487c87c5fbaSopenharmony_ci    coap_ws_set_host_request(session, &uri.host);
1488c87c5fbaSopenharmony_ci  }
1489c87c5fbaSopenharmony_ci  return session;
1490c87c5fbaSopenharmony_ci}
1491c87c5fbaSopenharmony_ci
1492c87c5fbaSopenharmony_cistatic coap_session_t *
1493c87c5fbaSopenharmony_ciget_session(coap_context_t *ctx,
1494c87c5fbaSopenharmony_ci            const char *local_addr,
1495c87c5fbaSopenharmony_ci            const char *local_port,
1496c87c5fbaSopenharmony_ci            coap_uri_scheme_t scheme,
1497c87c5fbaSopenharmony_ci            coap_proto_t proto,
1498c87c5fbaSopenharmony_ci            coap_address_t *dst,
1499c87c5fbaSopenharmony_ci            const uint8_t *identity,
1500c87c5fbaSopenharmony_ci            size_t identity_len,
1501c87c5fbaSopenharmony_ci            const uint8_t *key,
1502c87c5fbaSopenharmony_ci            size_t key_len) {
1503c87c5fbaSopenharmony_ci  coap_session_t *session = NULL;
1504c87c5fbaSopenharmony_ci
1505c87c5fbaSopenharmony_ci  is_mcast = coap_is_mcast(dst);
1506c87c5fbaSopenharmony_ci  if (local_addr || coap_is_af_unix(dst)) {
1507c87c5fbaSopenharmony_ci    if (coap_is_af_unix(dst)) {
1508c87c5fbaSopenharmony_ci      coap_address_t bind_addr;
1509c87c5fbaSopenharmony_ci
1510c87c5fbaSopenharmony_ci      if (local_addr) {
1511c87c5fbaSopenharmony_ci        if (!coap_address_set_unix_domain(&bind_addr,
1512c87c5fbaSopenharmony_ci                                          (const uint8_t *)local_addr,
1513c87c5fbaSopenharmony_ci                                          strlen(local_addr))) {
1514c87c5fbaSopenharmony_ci          fprintf(stderr, "coap_address_set_unix_domain: %s: failed\n",
1515c87c5fbaSopenharmony_ci                  local_addr);
1516c87c5fbaSopenharmony_ci          return NULL;
1517c87c5fbaSopenharmony_ci        }
1518c87c5fbaSopenharmony_ci      } else {
1519c87c5fbaSopenharmony_ci        char buf[COAP_UNIX_PATH_MAX];
1520c87c5fbaSopenharmony_ci
1521c87c5fbaSopenharmony_ci        /* Need a unique address */
1522c87c5fbaSopenharmony_ci        snprintf(buf, COAP_UNIX_PATH_MAX,
1523c87c5fbaSopenharmony_ci                 "/tmp/coap-client.%d", (int)getpid());
1524c87c5fbaSopenharmony_ci        if (!coap_address_set_unix_domain(&bind_addr, (const uint8_t *)buf,
1525c87c5fbaSopenharmony_ci                                          strlen(buf))) {
1526c87c5fbaSopenharmony_ci          fprintf(stderr, "coap_address_set_unix_domain: %s: failed\n",
1527c87c5fbaSopenharmony_ci                  buf);
1528c87c5fbaSopenharmony_ci          remove(buf);
1529c87c5fbaSopenharmony_ci          return NULL;
1530c87c5fbaSopenharmony_ci        }
1531c87c5fbaSopenharmony_ci        (void)remove(buf);
1532c87c5fbaSopenharmony_ci      }
1533c87c5fbaSopenharmony_ci      session = open_session(ctx, proto, &bind_addr, dst,
1534c87c5fbaSopenharmony_ci                             identity, identity_len, key, key_len);
1535c87c5fbaSopenharmony_ci    } else {
1536c87c5fbaSopenharmony_ci      coap_addr_info_t *info_list = NULL;
1537c87c5fbaSopenharmony_ci      coap_addr_info_t *info;
1538c87c5fbaSopenharmony_ci      coap_str_const_t local;
1539c87c5fbaSopenharmony_ci      uint16_t port = local_port ? atoi(local_port) : 0;
1540c87c5fbaSopenharmony_ci
1541c87c5fbaSopenharmony_ci      local.s = (const uint8_t *)local_addr;
1542c87c5fbaSopenharmony_ci      local.length = strlen(local_addr);
1543c87c5fbaSopenharmony_ci      /* resolve local address where data should be sent from */
1544c87c5fbaSopenharmony_ci      info_list = coap_resolve_address_info(&local, port, port, port, port,
1545c87c5fbaSopenharmony_ci                                            AI_PASSIVE | AI_NUMERICHOST | AI_NUMERICSERV | AI_ALL,
1546c87c5fbaSopenharmony_ci                                            1 << scheme,
1547c87c5fbaSopenharmony_ci                                            COAP_RESOLVE_TYPE_LOCAL);
1548c87c5fbaSopenharmony_ci      if (!info_list) {
1549c87c5fbaSopenharmony_ci        fprintf(stderr, "coap_resolve_address_info: %s: failed\n", local_addr);
1550c87c5fbaSopenharmony_ci        return NULL;
1551c87c5fbaSopenharmony_ci      }
1552c87c5fbaSopenharmony_ci
1553c87c5fbaSopenharmony_ci      /* iterate through results until success */
1554c87c5fbaSopenharmony_ci      for (info = info_list; info != NULL; info = info->next) {
1555c87c5fbaSopenharmony_ci        session = open_session(ctx, proto, &info->addr, dst,
1556c87c5fbaSopenharmony_ci                               identity, identity_len, key, key_len);
1557c87c5fbaSopenharmony_ci        if (session)
1558c87c5fbaSopenharmony_ci          break;
1559c87c5fbaSopenharmony_ci      }
1560c87c5fbaSopenharmony_ci      coap_free_address_info(info_list);
1561c87c5fbaSopenharmony_ci    }
1562c87c5fbaSopenharmony_ci  } else if (local_port) {
1563c87c5fbaSopenharmony_ci    coap_address_t bind_addr;
1564c87c5fbaSopenharmony_ci
1565c87c5fbaSopenharmony_ci    coap_address_init(&bind_addr);
1566c87c5fbaSopenharmony_ci    bind_addr.size = dst->size;
1567c87c5fbaSopenharmony_ci    bind_addr.addr.sa.sa_family = dst->addr.sa.sa_family;
1568c87c5fbaSopenharmony_ci    coap_address_set_port(&bind_addr, atoi(local_port));
1569c87c5fbaSopenharmony_ci    session = open_session(ctx, proto, &bind_addr, dst,
1570c87c5fbaSopenharmony_ci                           identity, identity_len, key, key_len);
1571c87c5fbaSopenharmony_ci  } else {
1572c87c5fbaSopenharmony_ci    session = open_session(ctx, proto, NULL, dst,
1573c87c5fbaSopenharmony_ci                           identity, identity_len, key, key_len);
1574c87c5fbaSopenharmony_ci  }
1575c87c5fbaSopenharmony_ci  return session;
1576c87c5fbaSopenharmony_ci}
1577c87c5fbaSopenharmony_ci
1578c87c5fbaSopenharmony_ciint
1579c87c5fbaSopenharmony_cimain(int argc, char **argv) {
1580c87c5fbaSopenharmony_ci  coap_context_t  *ctx = NULL;
1581c87c5fbaSopenharmony_ci  coap_session_t *session = NULL;
1582c87c5fbaSopenharmony_ci  coap_address_t dst;
1583c87c5fbaSopenharmony_ci  int result = -1;
1584c87c5fbaSopenharmony_ci  int exit_code = 0;
1585c87c5fbaSopenharmony_ci  coap_pdu_t  *pdu;
1586c87c5fbaSopenharmony_ci  static coap_str_const_t server;
1587c87c5fbaSopenharmony_ci  uint16_t port = COAP_DEFAULT_PORT;
1588c87c5fbaSopenharmony_ci  char port_str[NI_MAXSERV] = "";
1589c87c5fbaSopenharmony_ci  char node_str[NI_MAXHOST] = "";
1590c87c5fbaSopenharmony_ci  int opt;
1591c87c5fbaSopenharmony_ci  coap_log_t log_level = COAP_LOG_WARN;
1592c87c5fbaSopenharmony_ci  coap_log_t dtls_log_level = COAP_LOG_ERR;
1593c87c5fbaSopenharmony_ci  unsigned char *user = NULL, *key = NULL;
1594c87c5fbaSopenharmony_ci  ssize_t user_length = -1, key_length = 0;
1595c87c5fbaSopenharmony_ci  int create_uri_opts = 1;
1596c87c5fbaSopenharmony_ci  size_t i;
1597c87c5fbaSopenharmony_ci  coap_uri_scheme_t scheme;
1598c87c5fbaSopenharmony_ci  coap_proto_t proto;
1599c87c5fbaSopenharmony_ci  uint32_t repeat_ms = REPEAT_DELAY_MS;
1600c87c5fbaSopenharmony_ci  uint8_t *data = NULL;
1601c87c5fbaSopenharmony_ci  size_t data_len = 0;
1602c87c5fbaSopenharmony_ci  coap_addr_info_t *info_list = NULL;
1603c87c5fbaSopenharmony_ci#define BUFSIZE 100
1604c87c5fbaSopenharmony_ci  static unsigned char buf[BUFSIZE];
1605c87c5fbaSopenharmony_ci#ifndef _WIN32
1606c87c5fbaSopenharmony_ci  struct sigaction sa;
1607c87c5fbaSopenharmony_ci#endif
1608c87c5fbaSopenharmony_ci
1609c87c5fbaSopenharmony_ci  /* Initialize libcoap library */
1610c87c5fbaSopenharmony_ci  coap_startup();
1611c87c5fbaSopenharmony_ci
1612c87c5fbaSopenharmony_ci  while ((opt = getopt(argc, argv,
1613c87c5fbaSopenharmony_ci                       "a:b:c:e:f:h:j:k:l:m:no:p:rs:t:u:v:wA:B:C:E:G:H:J:K:L:M:NO:P:R:T:UV:X:")) != -1) {
1614c87c5fbaSopenharmony_ci    switch (opt) {
1615c87c5fbaSopenharmony_ci    case 'a':
1616c87c5fbaSopenharmony_ci      strncpy(node_str, optarg, NI_MAXHOST - 1);
1617c87c5fbaSopenharmony_ci      node_str[NI_MAXHOST - 1] = '\0';
1618c87c5fbaSopenharmony_ci      break;
1619c87c5fbaSopenharmony_ci    case 'b':
1620c87c5fbaSopenharmony_ci      cmdline_blocksize(optarg);
1621c87c5fbaSopenharmony_ci      break;
1622c87c5fbaSopenharmony_ci    case 'B':
1623c87c5fbaSopenharmony_ci      wait_seconds = atoi(optarg);
1624c87c5fbaSopenharmony_ci      break;
1625c87c5fbaSopenharmony_ci    case 'c':
1626c87c5fbaSopenharmony_ci      cert_file = optarg;
1627c87c5fbaSopenharmony_ci      break;
1628c87c5fbaSopenharmony_ci    case 'C':
1629c87c5fbaSopenharmony_ci      ca_file = optarg;
1630c87c5fbaSopenharmony_ci      break;
1631c87c5fbaSopenharmony_ci    case 'R':
1632c87c5fbaSopenharmony_ci      root_ca_file = optarg;
1633c87c5fbaSopenharmony_ci      break;
1634c87c5fbaSopenharmony_ci    case 'e':
1635c87c5fbaSopenharmony_ci      if (!cmdline_input(optarg, &payload))
1636c87c5fbaSopenharmony_ci        payload.length = 0;
1637c87c5fbaSopenharmony_ci      break;
1638c87c5fbaSopenharmony_ci    case 'f':
1639c87c5fbaSopenharmony_ci      if (!cmdline_input_from_file(optarg, &payload))
1640c87c5fbaSopenharmony_ci        payload.length = 0;
1641c87c5fbaSopenharmony_ci      break;
1642c87c5fbaSopenharmony_ci    case 'j' :
1643c87c5fbaSopenharmony_ci      key_file = optarg;
1644c87c5fbaSopenharmony_ci      break;
1645c87c5fbaSopenharmony_ci    case 'J' :
1646c87c5fbaSopenharmony_ci      pkcs11_pin = optarg;
1647c87c5fbaSopenharmony_ci      break;
1648c87c5fbaSopenharmony_ci    case 'k':
1649c87c5fbaSopenharmony_ci      key_length = cmdline_read_key(optarg, &key, MAX_KEY);
1650c87c5fbaSopenharmony_ci      break;
1651c87c5fbaSopenharmony_ci    case 'L':
1652c87c5fbaSopenharmony_ci      block_mode = strtoul(optarg, NULL, 0);
1653c87c5fbaSopenharmony_ci      if (!(block_mode & COAP_BLOCK_USE_LIBCOAP)) {
1654c87c5fbaSopenharmony_ci        fprintf(stderr, "Block mode must include COAP_BLOCK_USE_LIBCOAP (1)\n");
1655c87c5fbaSopenharmony_ci        goto failed;
1656c87c5fbaSopenharmony_ci      }
1657c87c5fbaSopenharmony_ci      break;
1658c87c5fbaSopenharmony_ci    case 'p':
1659c87c5fbaSopenharmony_ci      strncpy(port_str, optarg, NI_MAXSERV - 1);
1660c87c5fbaSopenharmony_ci      port_str[NI_MAXSERV - 1] = '\0';
1661c87c5fbaSopenharmony_ci      break;
1662c87c5fbaSopenharmony_ci    case 'm':
1663c87c5fbaSopenharmony_ci      method = cmdline_method(optarg);
1664c87c5fbaSopenharmony_ci      break;
1665c87c5fbaSopenharmony_ci    case 'w':
1666c87c5fbaSopenharmony_ci      add_nl = 1;
1667c87c5fbaSopenharmony_ci      break;
1668c87c5fbaSopenharmony_ci    case 'N':
1669c87c5fbaSopenharmony_ci      msgtype = COAP_MESSAGE_NON;
1670c87c5fbaSopenharmony_ci      break;
1671c87c5fbaSopenharmony_ci    case 's':
1672c87c5fbaSopenharmony_ci      cmdline_subscribe(optarg);
1673c87c5fbaSopenharmony_ci      break;
1674c87c5fbaSopenharmony_ci    case 'o':
1675c87c5fbaSopenharmony_ci      output_file.length = strlen(optarg);
1676c87c5fbaSopenharmony_ci      output_file.s = (unsigned char *)coap_malloc(output_file.length + 1);
1677c87c5fbaSopenharmony_ci
1678c87c5fbaSopenharmony_ci      if (!output_file.s) {
1679c87c5fbaSopenharmony_ci        fprintf(stderr, "cannot set output file: insufficient memory\n");
1680c87c5fbaSopenharmony_ci        goto failed;
1681c87c5fbaSopenharmony_ci      } else {
1682c87c5fbaSopenharmony_ci        /* copy filename including trailing zero */
1683c87c5fbaSopenharmony_ci        memcpy(output_file.s, optarg, output_file.length + 1);
1684c87c5fbaSopenharmony_ci      }
1685c87c5fbaSopenharmony_ci      break;
1686c87c5fbaSopenharmony_ci    case 'A':
1687c87c5fbaSopenharmony_ci      cmdline_content_type(optarg, COAP_OPTION_ACCEPT);
1688c87c5fbaSopenharmony_ci      break;
1689c87c5fbaSopenharmony_ci    case 't':
1690c87c5fbaSopenharmony_ci      cmdline_content_type(optarg, COAP_OPTION_CONTENT_TYPE);
1691c87c5fbaSopenharmony_ci      break;
1692c87c5fbaSopenharmony_ci    case 'M':
1693c87c5fbaSopenharmony_ci      cert_file = optarg;
1694c87c5fbaSopenharmony_ci      is_rpk_not_cert = 1;
1695c87c5fbaSopenharmony_ci      break;
1696c87c5fbaSopenharmony_ci    case 'O':
1697c87c5fbaSopenharmony_ci      cmdline_option(optarg);
1698c87c5fbaSopenharmony_ci      break;
1699c87c5fbaSopenharmony_ci    case 'P':
1700c87c5fbaSopenharmony_ci      if (!cmdline_proxy(optarg)) {
1701c87c5fbaSopenharmony_ci        fprintf(stderr, "error specifying proxy address\n");
1702c87c5fbaSopenharmony_ci        goto failed;
1703c87c5fbaSopenharmony_ci      }
1704c87c5fbaSopenharmony_ci      break;
1705c87c5fbaSopenharmony_ci    case 'T':
1706c87c5fbaSopenharmony_ci      cmdline_token(optarg);
1707c87c5fbaSopenharmony_ci      break;
1708c87c5fbaSopenharmony_ci    case 'u':
1709c87c5fbaSopenharmony_ci      user_length = cmdline_read_user(optarg, &user, MAX_USER);
1710c87c5fbaSopenharmony_ci      break;
1711c87c5fbaSopenharmony_ci    case 'U':
1712c87c5fbaSopenharmony_ci      create_uri_opts = 0;
1713c87c5fbaSopenharmony_ci      break;
1714c87c5fbaSopenharmony_ci    case 'v':
1715c87c5fbaSopenharmony_ci      log_level = strtol(optarg, NULL, 10);
1716c87c5fbaSopenharmony_ci      break;
1717c87c5fbaSopenharmony_ci    case 'V':
1718c87c5fbaSopenharmony_ci      dtls_log_level = strtol(optarg, NULL, 10);
1719c87c5fbaSopenharmony_ci      break;
1720c87c5fbaSopenharmony_ci    case 'l':
1721c87c5fbaSopenharmony_ci      if (!coap_debug_set_packet_loss(optarg)) {
1722c87c5fbaSopenharmony_ci        usage(argv[0], LIBCOAP_PACKAGE_VERSION);
1723c87c5fbaSopenharmony_ci        goto failed;
1724c87c5fbaSopenharmony_ci      }
1725c87c5fbaSopenharmony_ci      break;
1726c87c5fbaSopenharmony_ci    case 'r':
1727c87c5fbaSopenharmony_ci      reliable = coap_tcp_is_supported();
1728c87c5fbaSopenharmony_ci      break;
1729c87c5fbaSopenharmony_ci    case 'K':
1730c87c5fbaSopenharmony_ci      ping_seconds = atoi(optarg);
1731c87c5fbaSopenharmony_ci      break;
1732c87c5fbaSopenharmony_ci    case 'h':
1733c87c5fbaSopenharmony_ci      if (!cmdline_read_hint_check(optarg)) {
1734c87c5fbaSopenharmony_ci        usage(argv[0], LIBCOAP_PACKAGE_VERSION);
1735c87c5fbaSopenharmony_ci        goto failed;
1736c87c5fbaSopenharmony_ci      }
1737c87c5fbaSopenharmony_ci      break;
1738c87c5fbaSopenharmony_ci    case 'H':
1739c87c5fbaSopenharmony_ci      if (!cmdline_hop_limit(optarg))
1740c87c5fbaSopenharmony_ci        fprintf(stderr, "Hop Limit has to be > 0 and < 256\n");
1741c87c5fbaSopenharmony_ci      break;
1742c87c5fbaSopenharmony_ci    case 'n':
1743c87c5fbaSopenharmony_ci      verify_peer_cert = 0;
1744c87c5fbaSopenharmony_ci      break;
1745c87c5fbaSopenharmony_ci    case 'G':
1746c87c5fbaSopenharmony_ci      repeat_count = atoi(optarg);
1747c87c5fbaSopenharmony_ci      if (!repeat_count || repeat_count > 255) {
1748c87c5fbaSopenharmony_ci        fprintf(stderr, "'-G count' has to be > 0 and < 256\n");
1749c87c5fbaSopenharmony_ci        repeat_count = 1;
1750c87c5fbaSopenharmony_ci      }
1751c87c5fbaSopenharmony_ci      break;
1752c87c5fbaSopenharmony_ci    case 'X':
1753c87c5fbaSopenharmony_ci      csm_max_message_size = strtol(optarg, NULL, 10);
1754c87c5fbaSopenharmony_ci      break;
1755c87c5fbaSopenharmony_ci    case 'E':
1756c87c5fbaSopenharmony_ci      doing_oscore = cmdline_oscore(optarg);
1757c87c5fbaSopenharmony_ci      if (!doing_oscore) {
1758c87c5fbaSopenharmony_ci        goto failed;
1759c87c5fbaSopenharmony_ci      }
1760c87c5fbaSopenharmony_ci      break;
1761c87c5fbaSopenharmony_ci    default:
1762c87c5fbaSopenharmony_ci      usage(argv[0], LIBCOAP_PACKAGE_VERSION);
1763c87c5fbaSopenharmony_ci      goto failed;
1764c87c5fbaSopenharmony_ci    }
1765c87c5fbaSopenharmony_ci  }
1766c87c5fbaSopenharmony_ci
1767c87c5fbaSopenharmony_ci#ifdef _WIN32
1768c87c5fbaSopenharmony_ci  signal(SIGINT, handle_sigint);
1769c87c5fbaSopenharmony_ci#else
1770c87c5fbaSopenharmony_ci  memset(&sa, 0, sizeof(sa));
1771c87c5fbaSopenharmony_ci  sigemptyset(&sa.sa_mask);
1772c87c5fbaSopenharmony_ci  sa.sa_handler = handle_sigint;
1773c87c5fbaSopenharmony_ci  sa.sa_flags = 0;
1774c87c5fbaSopenharmony_ci  sigaction(SIGINT, &sa, NULL);
1775c87c5fbaSopenharmony_ci  sigaction(SIGTERM, &sa, NULL);
1776c87c5fbaSopenharmony_ci  /* So we do not exit on a SIGPIPE */
1777c87c5fbaSopenharmony_ci  sa.sa_handler = SIG_IGN;
1778c87c5fbaSopenharmony_ci  sigaction(SIGPIPE, &sa, NULL);
1779c87c5fbaSopenharmony_ci#endif
1780c87c5fbaSopenharmony_ci
1781c87c5fbaSopenharmony_ci  coap_set_log_level(log_level);
1782c87c5fbaSopenharmony_ci  coap_dtls_set_log_level(dtls_log_level);
1783c87c5fbaSopenharmony_ci
1784c87c5fbaSopenharmony_ci  if (optind < argc) {
1785c87c5fbaSopenharmony_ci    if (cmdline_uri(argv[optind]) < 0) {
1786c87c5fbaSopenharmony_ci      goto failed;
1787c87c5fbaSopenharmony_ci    }
1788c87c5fbaSopenharmony_ci  } else {
1789c87c5fbaSopenharmony_ci    usage(argv[0], LIBCOAP_PACKAGE_VERSION);
1790c87c5fbaSopenharmony_ci    goto failed;
1791c87c5fbaSopenharmony_ci  }
1792c87c5fbaSopenharmony_ci
1793c87c5fbaSopenharmony_ci  if (key_length < 0) {
1794c87c5fbaSopenharmony_ci    coap_log_crit("Invalid pre-shared key specified\n");
1795c87c5fbaSopenharmony_ci    goto failed;
1796c87c5fbaSopenharmony_ci  }
1797c87c5fbaSopenharmony_ci
1798c87c5fbaSopenharmony_ci  if (proxy.host.length) {
1799c87c5fbaSopenharmony_ci    server = proxy.host;
1800c87c5fbaSopenharmony_ci    port = proxy.port;
1801c87c5fbaSopenharmony_ci    scheme = proxy.scheme;
1802c87c5fbaSopenharmony_ci  } else {
1803c87c5fbaSopenharmony_ci    server = uri.host;
1804c87c5fbaSopenharmony_ci    port = proxy_scheme_option ? proxy.port : uri.port;
1805c87c5fbaSopenharmony_ci    scheme = proxy_scheme_option ? proxy.scheme : uri.scheme;
1806c87c5fbaSopenharmony_ci  }
1807c87c5fbaSopenharmony_ci
1808c87c5fbaSopenharmony_ci  /* resolve destination address where data should be sent */
1809c87c5fbaSopenharmony_ci  info_list = coap_resolve_address_info(&server, port, port, port, port,
1810c87c5fbaSopenharmony_ci                                        0,
1811c87c5fbaSopenharmony_ci                                        1 << scheme,
1812c87c5fbaSopenharmony_ci                                        COAP_RESOLVE_TYPE_REMOTE);
1813c87c5fbaSopenharmony_ci
1814c87c5fbaSopenharmony_ci  if (info_list == NULL) {
1815c87c5fbaSopenharmony_ci    coap_log_err("failed to resolve address\n");
1816c87c5fbaSopenharmony_ci    goto failed;
1817c87c5fbaSopenharmony_ci  }
1818c87c5fbaSopenharmony_ci  proto = info_list->proto;
1819c87c5fbaSopenharmony_ci  memcpy(&dst, &info_list->addr, sizeof(dst));
1820c87c5fbaSopenharmony_ci  coap_free_address_info(info_list);
1821c87c5fbaSopenharmony_ci
1822c87c5fbaSopenharmony_ci  ctx = coap_new_context(NULL);
1823c87c5fbaSopenharmony_ci  if (!ctx) {
1824c87c5fbaSopenharmony_ci    coap_log_emerg("cannot create context\n");
1825c87c5fbaSopenharmony_ci    goto failed;
1826c87c5fbaSopenharmony_ci  }
1827c87c5fbaSopenharmony_ci
1828c87c5fbaSopenharmony_ci  if (doing_oscore) {
1829c87c5fbaSopenharmony_ci    if (get_oscore_conf() == NULL)
1830c87c5fbaSopenharmony_ci      goto failed;
1831c87c5fbaSopenharmony_ci  }
1832c87c5fbaSopenharmony_ci
1833c87c5fbaSopenharmony_ci  coap_context_set_keepalive(ctx, ping_seconds);
1834c87c5fbaSopenharmony_ci  coap_context_set_block_mode(ctx, block_mode);
1835c87c5fbaSopenharmony_ci  if (csm_max_message_size)
1836c87c5fbaSopenharmony_ci    coap_context_set_csm_max_message_size(ctx, csm_max_message_size);
1837c87c5fbaSopenharmony_ci  coap_register_response_handler(ctx, message_handler);
1838c87c5fbaSopenharmony_ci  coap_register_event_handler(ctx, event_handler);
1839c87c5fbaSopenharmony_ci  coap_register_nack_handler(ctx, nack_handler);
1840c87c5fbaSopenharmony_ci  if (the_token.length > COAP_TOKEN_DEFAULT_MAX)
1841c87c5fbaSopenharmony_ci    coap_context_set_max_token_size(ctx, the_token.length);
1842c87c5fbaSopenharmony_ci
1843c87c5fbaSopenharmony_ci  session = get_session(ctx,
1844c87c5fbaSopenharmony_ci                        node_str[0] ? node_str : NULL,
1845c87c5fbaSopenharmony_ci                        port_str[0] ? port_str : NULL,
1846c87c5fbaSopenharmony_ci                        scheme,
1847c87c5fbaSopenharmony_ci                        proto,
1848c87c5fbaSopenharmony_ci                        &dst,
1849c87c5fbaSopenharmony_ci                        user_length >= 0 ? user : NULL,
1850c87c5fbaSopenharmony_ci                        user_length >= 0 ? user_length : 0,
1851c87c5fbaSopenharmony_ci                        key_length > 0 ? key : NULL,
1852c87c5fbaSopenharmony_ci                        key_length > 0 ? key_length : 0
1853c87c5fbaSopenharmony_ci                       );
1854c87c5fbaSopenharmony_ci
1855c87c5fbaSopenharmony_ci  if (!session) {
1856c87c5fbaSopenharmony_ci    coap_log_err("cannot create client session\n");
1857c87c5fbaSopenharmony_ci    goto failed;
1858c87c5fbaSopenharmony_ci  }
1859c87c5fbaSopenharmony_ci  /*
1860c87c5fbaSopenharmony_ci   * Prime the base token value, which coap_session_new_token() will increment
1861c87c5fbaSopenharmony_ci   * every time it is called to get an unique token.
1862c87c5fbaSopenharmony_ci   * [Option '-T token' is used to seed a different value]
1863c87c5fbaSopenharmony_ci   * Note that only the first 8 bytes of the token are used as the prime.
1864c87c5fbaSopenharmony_ci   */
1865c87c5fbaSopenharmony_ci  coap_session_init_token(session, the_token.length, the_token.s);
1866c87c5fbaSopenharmony_ci
1867c87c5fbaSopenharmony_ci  /* Convert provided uri into CoAP options */
1868c87c5fbaSopenharmony_ci  if (coap_uri_into_options(&uri, !uri_host_option && !proxy.host.length ?
1869c87c5fbaSopenharmony_ci                            &dst : NULL,
1870c87c5fbaSopenharmony_ci                            &optlist, create_uri_opts,
1871c87c5fbaSopenharmony_ci                            buf, sizeof(buf)) < 0) {
1872c87c5fbaSopenharmony_ci    coap_log_err("Failed to create options for URI\n");
1873c87c5fbaSopenharmony_ci    goto failed;
1874c87c5fbaSopenharmony_ci  }
1875c87c5fbaSopenharmony_ci
1876c87c5fbaSopenharmony_ci  /* set block option if requested at commandline */
1877c87c5fbaSopenharmony_ci  if (flags & FLAGS_BLOCK)
1878c87c5fbaSopenharmony_ci    set_blocksize();
1879c87c5fbaSopenharmony_ci
1880c87c5fbaSopenharmony_ci  /* Send the first (and may be only PDU) */
1881c87c5fbaSopenharmony_ci  if (payload.length) {
1882c87c5fbaSopenharmony_ci    /* Create some new data to use for this iteration */
1883c87c5fbaSopenharmony_ci    data = coap_malloc(payload.length);
1884c87c5fbaSopenharmony_ci    if (data == NULL)
1885c87c5fbaSopenharmony_ci      goto failed;
1886c87c5fbaSopenharmony_ci    memcpy(data, payload.s, payload.length);
1887c87c5fbaSopenharmony_ci    data_len = payload.length;
1888c87c5fbaSopenharmony_ci  }
1889c87c5fbaSopenharmony_ci  if (!(pdu = coap_new_request(ctx, session, method, &optlist, data,
1890c87c5fbaSopenharmony_ci                               data_len))) {
1891c87c5fbaSopenharmony_ci    goto failed;
1892c87c5fbaSopenharmony_ci  }
1893c87c5fbaSopenharmony_ci
1894c87c5fbaSopenharmony_ci  if (is_mcast && wait_seconds == DEFAULT_WAIT_TIME)
1895c87c5fbaSopenharmony_ci    /* Allow for other servers to respond within DEFAULT_LEISURE RFC7252 8.2 */
1896c87c5fbaSopenharmony_ci    wait_seconds = coap_session_get_default_leisure(session).integer_part + 1;
1897c87c5fbaSopenharmony_ci
1898c87c5fbaSopenharmony_ci  wait_ms = wait_seconds * 1000;
1899c87c5fbaSopenharmony_ci  coap_log_debug("timeout is set to %u seconds\n", wait_seconds);
1900c87c5fbaSopenharmony_ci
1901c87c5fbaSopenharmony_ci  coap_log_debug("sending CoAP request:\n");
1902c87c5fbaSopenharmony_ci  if (coap_get_log_level() < COAP_LOG_DEBUG)
1903c87c5fbaSopenharmony_ci    coap_show_pdu(COAP_LOG_INFO, pdu);
1904c87c5fbaSopenharmony_ci
1905c87c5fbaSopenharmony_ci  if (coap_send(session, pdu) == COAP_INVALID_MID) {
1906c87c5fbaSopenharmony_ci    coap_log_err("cannot send CoAP pdu\n");
1907c87c5fbaSopenharmony_ci    quit = 1;
1908c87c5fbaSopenharmony_ci  }
1909c87c5fbaSopenharmony_ci  repeat_count--;
1910c87c5fbaSopenharmony_ci
1911c87c5fbaSopenharmony_ci  while (!quit &&                /* immediate quit not required .. and .. */
1912c87c5fbaSopenharmony_ci         (tracked_tokens_count || /* token not responded to or still observe */
1913c87c5fbaSopenharmony_ci          is_mcast ||             /* mcast active */
1914c87c5fbaSopenharmony_ci          repeat_count ||         /* more repeat transmissions to go */
1915c87c5fbaSopenharmony_ci          coap_io_pending(ctx))) { /* i/o not yet complete */
1916c87c5fbaSopenharmony_ci    uint32_t timeout_ms;
1917c87c5fbaSopenharmony_ci    /*
1918c87c5fbaSopenharmony_ci     * 3 factors determine how long to wait in coap_io_process()
1919c87c5fbaSopenharmony_ci     *   Remaining overall wait time (wait_ms)
1920c87c5fbaSopenharmony_ci     *   Remaining overall observe unsolicited response time (obs_ms)
1921c87c5fbaSopenharmony_ci     *   Delay of up to one second before sending off the next request
1922c87c5fbaSopenharmony_ci     */
1923c87c5fbaSopenharmony_ci    if (obs_ms) {
1924c87c5fbaSopenharmony_ci      timeout_ms = min(wait_ms, obs_ms);
1925c87c5fbaSopenharmony_ci    } else {
1926c87c5fbaSopenharmony_ci      timeout_ms = wait_ms;
1927c87c5fbaSopenharmony_ci    }
1928c87c5fbaSopenharmony_ci    if (repeat_count) {
1929c87c5fbaSopenharmony_ci      timeout_ms = min(timeout_ms, repeat_ms);
1930c87c5fbaSopenharmony_ci    }
1931c87c5fbaSopenharmony_ci
1932c87c5fbaSopenharmony_ci    result = coap_io_process(ctx, timeout_ms);
1933c87c5fbaSopenharmony_ci
1934c87c5fbaSopenharmony_ci    if (result >= 0) {
1935c87c5fbaSopenharmony_ci      if (wait_ms > 0) {
1936c87c5fbaSopenharmony_ci        if ((unsigned)result >= wait_ms) {
1937c87c5fbaSopenharmony_ci          coap_log_info("timeout\n");
1938c87c5fbaSopenharmony_ci          break;
1939c87c5fbaSopenharmony_ci        } else {
1940c87c5fbaSopenharmony_ci          wait_ms -= result;
1941c87c5fbaSopenharmony_ci        }
1942c87c5fbaSopenharmony_ci      }
1943c87c5fbaSopenharmony_ci      if (obs_ms > 0 && !obs_ms_reset) {
1944c87c5fbaSopenharmony_ci        if ((unsigned)result >= obs_ms) {
1945c87c5fbaSopenharmony_ci          coap_log_debug("clear observation relationship\n");
1946c87c5fbaSopenharmony_ci          for (i = 0; i < tracked_tokens_count; i++) {
1947c87c5fbaSopenharmony_ci            if (tracked_tokens[i].observe) {
1948c87c5fbaSopenharmony_ci              coap_cancel_observe(session, tracked_tokens[i].token, msgtype);
1949c87c5fbaSopenharmony_ci              tracked_tokens[i].observe = 0;
1950c87c5fbaSopenharmony_ci              coap_io_process(ctx, COAP_IO_NO_WAIT);
1951c87c5fbaSopenharmony_ci            }
1952c87c5fbaSopenharmony_ci          }
1953c87c5fbaSopenharmony_ci          doing_observe = 0;
1954c87c5fbaSopenharmony_ci
1955c87c5fbaSopenharmony_ci          /* make sure that the obs timer does not fire again */
1956c87c5fbaSopenharmony_ci          obs_ms = 0;
1957c87c5fbaSopenharmony_ci          obs_seconds = 0;
1958c87c5fbaSopenharmony_ci        } else {
1959c87c5fbaSopenharmony_ci          obs_ms -= result;
1960c87c5fbaSopenharmony_ci        }
1961c87c5fbaSopenharmony_ci      }
1962c87c5fbaSopenharmony_ci      if (ready && repeat_count) {
1963c87c5fbaSopenharmony_ci        /* Send off next request if appropriate */
1964c87c5fbaSopenharmony_ci        if (repeat_ms > (unsigned)result) {
1965c87c5fbaSopenharmony_ci          repeat_ms -= (unsigned)result;
1966c87c5fbaSopenharmony_ci        } else {
1967c87c5fbaSopenharmony_ci          /* Doing this once a second */
1968c87c5fbaSopenharmony_ci          repeat_ms = REPEAT_DELAY_MS;
1969c87c5fbaSopenharmony_ci          if (payload.length) {
1970c87c5fbaSopenharmony_ci            /* Create some new data to use for this iteration */
1971c87c5fbaSopenharmony_ci            data = coap_malloc(payload.length);
1972c87c5fbaSopenharmony_ci            if (data == NULL)
1973c87c5fbaSopenharmony_ci              goto failed;
1974c87c5fbaSopenharmony_ci            memcpy(data, payload.s, payload.length);
1975c87c5fbaSopenharmony_ci            data_len = payload.length;
1976c87c5fbaSopenharmony_ci          }
1977c87c5fbaSopenharmony_ci          if (!(pdu = coap_new_request(ctx, session, method, &optlist,
1978c87c5fbaSopenharmony_ci                                       data, data_len))) {
1979c87c5fbaSopenharmony_ci            goto failed;
1980c87c5fbaSopenharmony_ci          }
1981c87c5fbaSopenharmony_ci          coap_log_debug("sending CoAP request:\n");
1982c87c5fbaSopenharmony_ci          if (coap_get_log_level() < COAP_LOG_DEBUG)
1983c87c5fbaSopenharmony_ci            coap_show_pdu(COAP_LOG_INFO, pdu);
1984c87c5fbaSopenharmony_ci
1985c87c5fbaSopenharmony_ci          ready = 0;
1986c87c5fbaSopenharmony_ci          if (coap_send(session, pdu) == COAP_INVALID_MID) {
1987c87c5fbaSopenharmony_ci            coap_log_err("cannot send CoAP pdu\n");
1988c87c5fbaSopenharmony_ci            quit = 1;
1989c87c5fbaSopenharmony_ci          }
1990c87c5fbaSopenharmony_ci          repeat_count--;
1991c87c5fbaSopenharmony_ci        }
1992c87c5fbaSopenharmony_ci      }
1993c87c5fbaSopenharmony_ci      obs_ms_reset = 0;
1994c87c5fbaSopenharmony_ci    }
1995c87c5fbaSopenharmony_ci  }
1996c87c5fbaSopenharmony_ci
1997c87c5fbaSopenharmony_ci  exit_code = 0;
1998c87c5fbaSopenharmony_ci
1999c87c5fbaSopenharmony_cifinish:
2000c87c5fbaSopenharmony_ci
2001c87c5fbaSopenharmony_ci  /* Clean up library usage */
2002c87c5fbaSopenharmony_ci  coap_session_release(session);
2003c87c5fbaSopenharmony_ci  coap_free_context(ctx);
2004c87c5fbaSopenharmony_ci  coap_cleanup();
2005c87c5fbaSopenharmony_ci
2006c87c5fbaSopenharmony_ci  /* Clean up local usage */
2007c87c5fbaSopenharmony_ci  coap_free(ca_mem);
2008c87c5fbaSopenharmony_ci  coap_free(cert_mem);
2009c87c5fbaSopenharmony_ci  coap_free(key_mem);
2010c87c5fbaSopenharmony_ci  coap_free(payload.s);
2011c87c5fbaSopenharmony_ci
2012c87c5fbaSopenharmony_ci  for (i = 0; i < valid_ihs.count; i++) {
2013c87c5fbaSopenharmony_ci    free(valid_ihs.ih_list[i].hint_match);
2014c87c5fbaSopenharmony_ci    coap_delete_bin_const(valid_ihs.ih_list[i].new_identity);
2015c87c5fbaSopenharmony_ci    coap_delete_bin_const(valid_ihs.ih_list[i].new_key);
2016c87c5fbaSopenharmony_ci  }
2017c87c5fbaSopenharmony_ci  if (valid_ihs.count)
2018c87c5fbaSopenharmony_ci    free(valid_ihs.ih_list);
2019c87c5fbaSopenharmony_ci
2020c87c5fbaSopenharmony_ci  for (i = 0; i < tracked_tokens_count; i++) {
2021c87c5fbaSopenharmony_ci    coap_delete_binary(tracked_tokens[i].token);
2022c87c5fbaSopenharmony_ci  }
2023c87c5fbaSopenharmony_ci  free(tracked_tokens);
2024c87c5fbaSopenharmony_ci
2025c87c5fbaSopenharmony_ci  coap_delete_optlist(optlist);
2026c87c5fbaSopenharmony_ci  if (oscore_seq_num_fp)
2027c87c5fbaSopenharmony_ci    fclose(oscore_seq_num_fp);
2028c87c5fbaSopenharmony_ci  close_output();
2029c87c5fbaSopenharmony_ci
2030c87c5fbaSopenharmony_ci  return exit_code;
2031c87c5fbaSopenharmony_ci
2032c87c5fbaSopenharmony_cifailed:
2033c87c5fbaSopenharmony_ci  exit_code = 1;
2034c87c5fbaSopenharmony_ci  goto finish;
2035c87c5fbaSopenharmony_ci}
2036