1c87c5fbaSopenharmony_ci/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2c87c5fbaSopenharmony_ci
3c87c5fbaSopenharmony_ci/* oscore-interop-server
4c87c5fbaSopenharmony_ci *
5c87c5fbaSopenharmony_ci * A server for use in the RFC 8613 OSCORE interop testing.
6c87c5fbaSopenharmony_ci * https://core-wg.github.io/oscore/test-spec5.html
7c87c5fbaSopenharmony_ci *
8c87c5fbaSopenharmony_ci * Copyright (C) 2022-2023 Olaf Bergmann <bergmann@tzi.org> and others
9c87c5fbaSopenharmony_ci *
10c87c5fbaSopenharmony_ci * SPDX-License-Identifier: BSD-2-Clause
11c87c5fbaSopenharmony_ci *
12c87c5fbaSopenharmony_ci * This file is part of the CoAP library libcoap. Please see README for terms
13c87c5fbaSopenharmony_ci * of use.
14c87c5fbaSopenharmony_ci */
15c87c5fbaSopenharmony_ci
16c87c5fbaSopenharmony_ci#include <string.h>
17c87c5fbaSopenharmony_ci#include <stdlib.h>
18c87c5fbaSopenharmony_ci#include <stdio.h>
19c87c5fbaSopenharmony_ci#include <ctype.h>
20c87c5fbaSopenharmony_ci#include <inttypes.h>
21c87c5fbaSopenharmony_ci#include <sys/types.h>
22c87c5fbaSopenharmony_ci#include <sys/stat.h>
23c87c5fbaSopenharmony_ci#include <errno.h>
24c87c5fbaSopenharmony_ci#include <signal.h>
25c87c5fbaSopenharmony_ci#ifdef _WIN32
26c87c5fbaSopenharmony_ci#define strcasecmp _stricmp
27c87c5fbaSopenharmony_ci#define strncasecmp _strnicmp
28c87c5fbaSopenharmony_ci#include "getopt.c"
29c87c5fbaSopenharmony_ci#if !defined(S_ISDIR)
30c87c5fbaSopenharmony_ci#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
31c87c5fbaSopenharmony_ci#endif
32c87c5fbaSopenharmony_ci#ifndef R_OK
33c87c5fbaSopenharmony_ci#define R_OK 4
34c87c5fbaSopenharmony_ci#endif
35c87c5fbaSopenharmony_cistatic char *
36c87c5fbaSopenharmony_cistrndup(const char *s1, size_t n) {
37c87c5fbaSopenharmony_ci  char *copy = (char *)malloc(n + 1);
38c87c5fbaSopenharmony_ci  if (copy) {
39c87c5fbaSopenharmony_ci    memcpy(copy, s1, n);
40c87c5fbaSopenharmony_ci    copy[n] = 0;
41c87c5fbaSopenharmony_ci  }
42c87c5fbaSopenharmony_ci  return copy;
43c87c5fbaSopenharmony_ci}
44c87c5fbaSopenharmony_ci#include <io.h>
45c87c5fbaSopenharmony_ci#define access _access
46c87c5fbaSopenharmony_ci#define fileno _fileno
47c87c5fbaSopenharmony_ci#else
48c87c5fbaSopenharmony_ci#include <unistd.h>
49c87c5fbaSopenharmony_ci#include <sys/select.h>
50c87c5fbaSopenharmony_ci#include <sys/socket.h>
51c87c5fbaSopenharmony_ci#include <netinet/in.h>
52c87c5fbaSopenharmony_ci#include <arpa/inet.h>
53c87c5fbaSopenharmony_ci#include <netdb.h>
54c87c5fbaSopenharmony_ci#include <dirent.h>
55c87c5fbaSopenharmony_ci#endif
56c87c5fbaSopenharmony_ci
57c87c5fbaSopenharmony_ci#include <coap3/coap.h>
58c87c5fbaSopenharmony_ci
59c87c5fbaSopenharmony_ci#ifndef min
60c87c5fbaSopenharmony_ci#define min(a,b) ((a) < (b) ? (a) : (b))
61c87c5fbaSopenharmony_ci#endif
62c87c5fbaSopenharmony_ci
63c87c5fbaSopenharmony_cistatic coap_oscore_conf_t *oscore_conf;
64c87c5fbaSopenharmony_cistatic int doing_oscore = 0;
65c87c5fbaSopenharmony_ci
66c87c5fbaSopenharmony_ci/* set to 1 to request clean server shutdown */
67c87c5fbaSopenharmony_cistatic int quit = 0;
68c87c5fbaSopenharmony_ci
69c87c5fbaSopenharmony_cistatic coap_resource_t *r_observe_1;
70c87c5fbaSopenharmony_cistatic coap_resource_t *r_observe_2;
71c87c5fbaSopenharmony_ci
72c87c5fbaSopenharmony_cistatic int resource_flags = COAP_RESOURCE_FLAGS_NOTIFY_CON;
73c87c5fbaSopenharmony_ci
74c87c5fbaSopenharmony_cistatic uint32_t block_mode = COAP_BLOCK_USE_LIBCOAP;
75c87c5fbaSopenharmony_cistatic uint32_t csm_max_message_size = 0;
76c87c5fbaSopenharmony_ci
77c87c5fbaSopenharmony_ci/* SIGINT handler: set quit to 1 for graceful termination */
78c87c5fbaSopenharmony_cistatic void
79c87c5fbaSopenharmony_cihandle_sigint(int signum COAP_UNUSED) {
80c87c5fbaSopenharmony_ci  quit = 1;
81c87c5fbaSopenharmony_ci}
82c87c5fbaSopenharmony_ci
83c87c5fbaSopenharmony_ci#define INDEX "This is a OSCORE test server made with libcoap " \
84c87c5fbaSopenharmony_ci  "(see https://libcoap.net)\n" \
85c87c5fbaSopenharmony_ci  "Copyright (C) 2023 Olaf Bergmann <bergmann@tzi.org> " \
86c87c5fbaSopenharmony_ci  "and others\n\n"
87c87c5fbaSopenharmony_ci
88c87c5fbaSopenharmony_cistatic void
89c87c5fbaSopenharmony_cihnd_get_index(coap_resource_t *resource,
90c87c5fbaSopenharmony_ci              coap_session_t *session,
91c87c5fbaSopenharmony_ci              const coap_pdu_t *request,
92c87c5fbaSopenharmony_ci              const coap_string_t *query COAP_UNUSED,
93c87c5fbaSopenharmony_ci              coap_pdu_t *response) {
94c87c5fbaSopenharmony_ci
95c87c5fbaSopenharmony_ci  coap_pdu_set_code(response, COAP_RESPONSE_CODE_CONTENT);
96c87c5fbaSopenharmony_ci  coap_add_data_large_response(resource, session, request, response,
97c87c5fbaSopenharmony_ci                               query, COAP_MEDIATYPE_TEXT_PLAIN,
98c87c5fbaSopenharmony_ci                               0x2ffff, 0, strlen(INDEX),
99c87c5fbaSopenharmony_ci                               (const uint8_t *)INDEX, NULL, NULL);
100c87c5fbaSopenharmony_ci}
101c87c5fbaSopenharmony_ci
102c87c5fbaSopenharmony_ci#define HELLO_WORLD "Hello World!"
103c87c5fbaSopenharmony_ci
104c87c5fbaSopenharmony_cistatic void
105c87c5fbaSopenharmony_cihnd_get_hello_coap(coap_resource_t *resource,
106c87c5fbaSopenharmony_ci                   coap_session_t *session,
107c87c5fbaSopenharmony_ci                   const coap_pdu_t *request,
108c87c5fbaSopenharmony_ci                   const coap_string_t *query,
109c87c5fbaSopenharmony_ci                   coap_pdu_t *response) {
110c87c5fbaSopenharmony_ci  coap_pdu_set_code(response, COAP_RESPONSE_CODE_CONTENT);
111c87c5fbaSopenharmony_ci  coap_add_data_large_response(resource, session, request, response,
112c87c5fbaSopenharmony_ci                               query, COAP_MEDIATYPE_TEXT_PLAIN,
113c87c5fbaSopenharmony_ci                               -1, 0, strlen(HELLO_WORLD),
114c87c5fbaSopenharmony_ci                               (const uint8_t *)HELLO_WORLD, NULL, NULL);
115c87c5fbaSopenharmony_ci}
116c87c5fbaSopenharmony_ci
117c87c5fbaSopenharmony_cistatic void
118c87c5fbaSopenharmony_cihnd_get_hello_1(coap_resource_t *resource,
119c87c5fbaSopenharmony_ci                coap_session_t *session,
120c87c5fbaSopenharmony_ci                const coap_pdu_t *request,
121c87c5fbaSopenharmony_ci                const coap_string_t *query,
122c87c5fbaSopenharmony_ci                coap_pdu_t *response) {
123c87c5fbaSopenharmony_ci  coap_pdu_set_code(response, COAP_RESPONSE_CODE_CONTENT);
124c87c5fbaSopenharmony_ci  coap_add_data_large_response(resource, session, request, response,
125c87c5fbaSopenharmony_ci                               query, COAP_MEDIATYPE_TEXT_PLAIN,
126c87c5fbaSopenharmony_ci                               -1, 0, strlen(HELLO_WORLD),
127c87c5fbaSopenharmony_ci                               (const uint8_t *)HELLO_WORLD, NULL, NULL);
128c87c5fbaSopenharmony_ci}
129c87c5fbaSopenharmony_ci
130c87c5fbaSopenharmony_cistatic void
131c87c5fbaSopenharmony_cihnd_get_hello_2(coap_resource_t *resource,
132c87c5fbaSopenharmony_ci                coap_session_t *session,
133c87c5fbaSopenharmony_ci                const coap_pdu_t *request,
134c87c5fbaSopenharmony_ci                const coap_string_t *query,
135c87c5fbaSopenharmony_ci                coap_pdu_t *response) {
136c87c5fbaSopenharmony_ci  coap_pdu_set_code(response, COAP_RESPONSE_CODE_CONTENT);
137c87c5fbaSopenharmony_ci  coap_add_data_large_response(resource, session, request, response,
138c87c5fbaSopenharmony_ci                               query, COAP_MEDIATYPE_TEXT_PLAIN,
139c87c5fbaSopenharmony_ci                               -1, 0x2b, strlen(HELLO_WORLD),
140c87c5fbaSopenharmony_ci                               (const uint8_t *)HELLO_WORLD, NULL, NULL);
141c87c5fbaSopenharmony_ci}
142c87c5fbaSopenharmony_ci
143c87c5fbaSopenharmony_cistatic void
144c87c5fbaSopenharmony_cihnd_get_hello_3(coap_resource_t *resource,
145c87c5fbaSopenharmony_ci                coap_session_t *session,
146c87c5fbaSopenharmony_ci                const coap_pdu_t *request,
147c87c5fbaSopenharmony_ci                const coap_string_t *query,
148c87c5fbaSopenharmony_ci                coap_pdu_t *response) {
149c87c5fbaSopenharmony_ci  coap_pdu_set_code(response, COAP_RESPONSE_CODE_CONTENT);
150c87c5fbaSopenharmony_ci  coap_add_data_large_response(resource, session, request, response,
151c87c5fbaSopenharmony_ci                               query, COAP_MEDIATYPE_TEXT_PLAIN,
152c87c5fbaSopenharmony_ci                               5, 0, strlen(HELLO_WORLD),
153c87c5fbaSopenharmony_ci                               (const uint8_t *)HELLO_WORLD, NULL, NULL);
154c87c5fbaSopenharmony_ci}
155c87c5fbaSopenharmony_ci
156c87c5fbaSopenharmony_cistatic void
157c87c5fbaSopenharmony_cihnd_post_hello_6(coap_resource_t *resource,
158c87c5fbaSopenharmony_ci                 coap_session_t *session,
159c87c5fbaSopenharmony_ci                 const coap_pdu_t *request,
160c87c5fbaSopenharmony_ci                 const coap_string_t *query,
161c87c5fbaSopenharmony_ci                 coap_pdu_t *response) {
162c87c5fbaSopenharmony_ci  size_t size;
163c87c5fbaSopenharmony_ci  const uint8_t *data;
164c87c5fbaSopenharmony_ci
165c87c5fbaSopenharmony_ci  (void)coap_get_data(request, &size, &data);
166c87c5fbaSopenharmony_ci  coap_pdu_set_code(response, COAP_RESPONSE_CODE_CHANGED);
167c87c5fbaSopenharmony_ci  coap_add_data_large_response(resource, session, request, response,
168c87c5fbaSopenharmony_ci                               query, COAP_MEDIATYPE_TEXT_PLAIN,
169c87c5fbaSopenharmony_ci                               -1, 0, size,
170c87c5fbaSopenharmony_ci                               data, NULL, NULL);
171c87c5fbaSopenharmony_ci}
172c87c5fbaSopenharmony_ci
173c87c5fbaSopenharmony_cistatic void
174c87c5fbaSopenharmony_cihnd_put_hello_7(coap_resource_t *resource,
175c87c5fbaSopenharmony_ci                coap_session_t *session,
176c87c5fbaSopenharmony_ci                const coap_pdu_t *request,
177c87c5fbaSopenharmony_ci                const coap_string_t *query,
178c87c5fbaSopenharmony_ci                coap_pdu_t *response) {
179c87c5fbaSopenharmony_ci  size_t size;
180c87c5fbaSopenharmony_ci  const uint8_t *data;
181c87c5fbaSopenharmony_ci  coap_opt_iterator_t opt_iter;
182c87c5fbaSopenharmony_ci  coap_opt_t *option;
183c87c5fbaSopenharmony_ci  uint64_t etag;
184c87c5fbaSopenharmony_ci
185c87c5fbaSopenharmony_ci
186c87c5fbaSopenharmony_ci  if ((option = coap_check_option(request, COAP_OPTION_IF_MATCH,
187c87c5fbaSopenharmony_ci                                  &opt_iter)) != NULL) {
188c87c5fbaSopenharmony_ci    etag = coap_decode_var_bytes8(coap_opt_value(option),
189c87c5fbaSopenharmony_ci                                  coap_opt_length(option));
190c87c5fbaSopenharmony_ci    if (etag != 0x7b) {
191c87c5fbaSopenharmony_ci      coap_pdu_set_code(response, COAP_RESPONSE_CODE_PRECONDITION_FAILED);
192c87c5fbaSopenharmony_ci      return;
193c87c5fbaSopenharmony_ci    }
194c87c5fbaSopenharmony_ci  }
195c87c5fbaSopenharmony_ci
196c87c5fbaSopenharmony_ci  coap_pdu_set_code(response, COAP_RESPONSE_CODE_CHANGED);
197c87c5fbaSopenharmony_ci  (void)coap_get_data(request, &size, &data);
198c87c5fbaSopenharmony_ci  coap_add_data_large_response(resource, session, request, response,
199c87c5fbaSopenharmony_ci                               query, COAP_MEDIATYPE_TEXT_PLAIN,
200c87c5fbaSopenharmony_ci                               -1, 0x7b, size,
201c87c5fbaSopenharmony_ci                               data, NULL, NULL);
202c87c5fbaSopenharmony_ci}
203c87c5fbaSopenharmony_ci
204c87c5fbaSopenharmony_cistatic void
205c87c5fbaSopenharmony_cihnd_get_observe1(coap_resource_t *resource,
206c87c5fbaSopenharmony_ci                 coap_session_t *session,
207c87c5fbaSopenharmony_ci                 const coap_pdu_t *request,
208c87c5fbaSopenharmony_ci                 const coap_string_t *query,
209c87c5fbaSopenharmony_ci                 coap_pdu_t *response) {
210c87c5fbaSopenharmony_ci  static int count = 0;
211c87c5fbaSopenharmony_ci
212c87c5fbaSopenharmony_ci  count++;
213c87c5fbaSopenharmony_ci  switch (count) {
214c87c5fbaSopenharmony_ci  case 1:
215c87c5fbaSopenharmony_ci    coap_pdu_set_code(response, COAP_RESPONSE_CODE_CONTENT);
216c87c5fbaSopenharmony_ci    coap_add_data_large_response(resource, session, request, response,
217c87c5fbaSopenharmony_ci                                 query, COAP_MEDIATYPE_TEXT_PLAIN,
218c87c5fbaSopenharmony_ci                                 1, 0, strlen("one"),
219c87c5fbaSopenharmony_ci                                 (const uint8_t *)"one", NULL, NULL);
220c87c5fbaSopenharmony_ci    break;
221c87c5fbaSopenharmony_ci  case 2:
222c87c5fbaSopenharmony_ci    coap_pdu_set_code(response, COAP_RESPONSE_CODE_CONTENT);
223c87c5fbaSopenharmony_ci    coap_add_data_large_response(resource, session, request, response,
224c87c5fbaSopenharmony_ci                                 query, COAP_MEDIATYPE_TEXT_PLAIN,
225c87c5fbaSopenharmony_ci                                 1, 0, strlen("two"),
226c87c5fbaSopenharmony_ci                                 (const uint8_t *)"two", NULL, NULL);
227c87c5fbaSopenharmony_ci    break;
228c87c5fbaSopenharmony_ci  default:
229c87c5fbaSopenharmony_ci    coap_pdu_set_code(response, COAP_RESPONSE_CODE_INTERNAL_ERROR);
230c87c5fbaSopenharmony_ci    coap_add_data_large_response(resource, session, request, response,
231c87c5fbaSopenharmony_ci                                 query, COAP_MEDIATYPE_TEXT_PLAIN,
232c87c5fbaSopenharmony_ci                                 -1, 0, strlen("Terminate Observe"),
233c87c5fbaSopenharmony_ci                                 (const uint8_t *)"Terminate Observe",
234c87c5fbaSopenharmony_ci                                 NULL, NULL);
235c87c5fbaSopenharmony_ci    r_observe_1 = NULL;
236c87c5fbaSopenharmony_ci  }
237c87c5fbaSopenharmony_ci}
238c87c5fbaSopenharmony_ci
239c87c5fbaSopenharmony_cistatic void
240c87c5fbaSopenharmony_cihnd_get_observe2(coap_resource_t *resource,
241c87c5fbaSopenharmony_ci                 coap_session_t *session,
242c87c5fbaSopenharmony_ci                 const coap_pdu_t *request,
243c87c5fbaSopenharmony_ci                 const coap_string_t *query,
244c87c5fbaSopenharmony_ci                 coap_pdu_t *response) {
245c87c5fbaSopenharmony_ci  static int count = 0;
246c87c5fbaSopenharmony_ci
247c87c5fbaSopenharmony_ci  count++;
248c87c5fbaSopenharmony_ci  switch (count) {
249c87c5fbaSopenharmony_ci  case 1:
250c87c5fbaSopenharmony_ci    coap_pdu_set_code(response, COAP_RESPONSE_CODE_CONTENT);
251c87c5fbaSopenharmony_ci    coap_add_data_large_response(resource, session, request, response,
252c87c5fbaSopenharmony_ci                                 query, COAP_MEDIATYPE_TEXT_PLAIN,
253c87c5fbaSopenharmony_ci                                 1, 0, strlen("one"),
254c87c5fbaSopenharmony_ci                                 (const uint8_t *)"one", NULL, NULL);
255c87c5fbaSopenharmony_ci    break;
256c87c5fbaSopenharmony_ci  case 2:
257c87c5fbaSopenharmony_ci  default:
258c87c5fbaSopenharmony_ci    coap_pdu_set_code(response, COAP_RESPONSE_CODE_CONTENT);
259c87c5fbaSopenharmony_ci    coap_add_data_large_response(resource, session, request, response,
260c87c5fbaSopenharmony_ci                                 query, COAP_MEDIATYPE_TEXT_PLAIN,
261c87c5fbaSopenharmony_ci                                 1, 0, strlen("two"),
262c87c5fbaSopenharmony_ci                                 (const uint8_t *)"two", NULL, NULL);
263c87c5fbaSopenharmony_ci    r_observe_2 = NULL;
264c87c5fbaSopenharmony_ci    break;
265c87c5fbaSopenharmony_ci  }
266c87c5fbaSopenharmony_ci}
267c87c5fbaSopenharmony_ci
268c87c5fbaSopenharmony_cistatic void
269c87c5fbaSopenharmony_cihnd_del_test(coap_resource_t *resource COAP_UNUSED,
270c87c5fbaSopenharmony_ci             coap_session_t *session COAP_UNUSED,
271c87c5fbaSopenharmony_ci             const coap_pdu_t *request COAP_UNUSED,
272c87c5fbaSopenharmony_ci             const coap_string_t *query COAP_UNUSED,
273c87c5fbaSopenharmony_ci             coap_pdu_t *response) {
274c87c5fbaSopenharmony_ci  coap_pdu_set_code(response, COAP_RESPONSE_CODE_DELETED);
275c87c5fbaSopenharmony_ci}
276c87c5fbaSopenharmony_ci
277c87c5fbaSopenharmony_cistatic void
278c87c5fbaSopenharmony_ciinit_resources(coap_context_t *ctx) {
279c87c5fbaSopenharmony_ci  coap_resource_t *r;
280c87c5fbaSopenharmony_ci
281c87c5fbaSopenharmony_ci  r = coap_resource_init(NULL, COAP_RESOURCE_FLAGS_HAS_MCAST_SUPPORT);
282c87c5fbaSopenharmony_ci  coap_register_request_handler(r, COAP_REQUEST_GET, hnd_get_index);
283c87c5fbaSopenharmony_ci
284c87c5fbaSopenharmony_ci  coap_add_attr(r, coap_make_str_const("ct"), coap_make_str_const("0"), 0);
285c87c5fbaSopenharmony_ci  coap_add_attr(r, coap_make_str_const("title"),
286c87c5fbaSopenharmony_ci                coap_make_str_const("\"General Info\""), 0);
287c87c5fbaSopenharmony_ci  coap_add_resource(ctx, r);
288c87c5fbaSopenharmony_ci
289c87c5fbaSopenharmony_ci  r = coap_resource_init(coap_make_str_const("oscore/hello/coap"),
290c87c5fbaSopenharmony_ci                         resource_flags);
291c87c5fbaSopenharmony_ci  coap_register_request_handler(r, COAP_REQUEST_GET, hnd_get_hello_coap);
292c87c5fbaSopenharmony_ci  coap_add_resource(ctx, r);
293c87c5fbaSopenharmony_ci
294c87c5fbaSopenharmony_ci  r = coap_resource_init(coap_make_str_const("oscore/hello/1"),
295c87c5fbaSopenharmony_ci                         resource_flags | COAP_RESOURCE_FLAGS_OSCORE_ONLY);
296c87c5fbaSopenharmony_ci  coap_register_request_handler(r, COAP_REQUEST_GET, hnd_get_hello_1);
297c87c5fbaSopenharmony_ci  coap_add_resource(ctx, r);
298c87c5fbaSopenharmony_ci
299c87c5fbaSopenharmony_ci  r = coap_resource_init(coap_make_str_const("oscore/hello/2"),
300c87c5fbaSopenharmony_ci                         resource_flags | COAP_RESOURCE_FLAGS_OSCORE_ONLY);
301c87c5fbaSopenharmony_ci  coap_register_request_handler(r, COAP_REQUEST_GET, hnd_get_hello_2);
302c87c5fbaSopenharmony_ci  coap_add_resource(ctx, r);
303c87c5fbaSopenharmony_ci
304c87c5fbaSopenharmony_ci  r = coap_resource_init(coap_make_str_const("oscore/hello/3"),
305c87c5fbaSopenharmony_ci                         resource_flags | COAP_RESOURCE_FLAGS_OSCORE_ONLY);
306c87c5fbaSopenharmony_ci  coap_register_request_handler(r, COAP_REQUEST_GET, hnd_get_hello_3);
307c87c5fbaSopenharmony_ci  coap_add_resource(ctx, r);
308c87c5fbaSopenharmony_ci
309c87c5fbaSopenharmony_ci  r = coap_resource_init(coap_make_str_const("oscore/hello/6"),
310c87c5fbaSopenharmony_ci                         resource_flags | COAP_RESOURCE_FLAGS_OSCORE_ONLY);
311c87c5fbaSopenharmony_ci  coap_register_request_handler(r, COAP_REQUEST_POST, hnd_post_hello_6);
312c87c5fbaSopenharmony_ci  coap_add_resource(ctx, r);
313c87c5fbaSopenharmony_ci
314c87c5fbaSopenharmony_ci  r = coap_resource_init(coap_make_str_const("oscore/hello/7"),
315c87c5fbaSopenharmony_ci                         resource_flags | COAP_RESOURCE_FLAGS_OSCORE_ONLY);
316c87c5fbaSopenharmony_ci  coap_register_request_handler(r, COAP_REQUEST_PUT, hnd_put_hello_7);
317c87c5fbaSopenharmony_ci  coap_add_resource(ctx, r);
318c87c5fbaSopenharmony_ci
319c87c5fbaSopenharmony_ci  r = coap_resource_init(coap_make_str_const("oscore/observe1"),
320c87c5fbaSopenharmony_ci                         resource_flags | COAP_RESOURCE_FLAGS_OSCORE_ONLY);
321c87c5fbaSopenharmony_ci  coap_register_request_handler(r, COAP_REQUEST_GET, hnd_get_observe1);
322c87c5fbaSopenharmony_ci  coap_resource_set_get_observable(r, 1);
323c87c5fbaSopenharmony_ci  coap_add_resource(ctx, r);
324c87c5fbaSopenharmony_ci  r_observe_1 = r;
325c87c5fbaSopenharmony_ci
326c87c5fbaSopenharmony_ci  r = coap_resource_init(coap_make_str_const("oscore/observe2"),
327c87c5fbaSopenharmony_ci                         resource_flags | COAP_RESOURCE_FLAGS_OSCORE_ONLY);
328c87c5fbaSopenharmony_ci  coap_register_request_handler(r, COAP_REQUEST_GET, hnd_get_observe2);
329c87c5fbaSopenharmony_ci  coap_resource_set_get_observable(r, 1);
330c87c5fbaSopenharmony_ci  coap_add_resource(ctx, r);
331c87c5fbaSopenharmony_ci  r_observe_2 = r;
332c87c5fbaSopenharmony_ci
333c87c5fbaSopenharmony_ci  r = coap_resource_init(coap_make_str_const("oscore/test"),
334c87c5fbaSopenharmony_ci                         resource_flags | COAP_RESOURCE_FLAGS_OSCORE_ONLY);
335c87c5fbaSopenharmony_ci  coap_register_request_handler(r, COAP_REQUEST_DELETE, hnd_del_test);
336c87c5fbaSopenharmony_ci  coap_add_resource(ctx, r);
337c87c5fbaSopenharmony_ci}
338c87c5fbaSopenharmony_ci
339c87c5fbaSopenharmony_cistatic uint8_t *
340c87c5fbaSopenharmony_ciread_file_mem(const char *file, size_t *length) {
341c87c5fbaSopenharmony_ci  FILE *f;
342c87c5fbaSopenharmony_ci  uint8_t *buf;
343c87c5fbaSopenharmony_ci  struct stat statbuf;
344c87c5fbaSopenharmony_ci
345c87c5fbaSopenharmony_ci  *length = 0;
346c87c5fbaSopenharmony_ci  if (!file || !(f = fopen(file, "r")))
347c87c5fbaSopenharmony_ci    return NULL;
348c87c5fbaSopenharmony_ci
349c87c5fbaSopenharmony_ci  if (fstat(fileno(f), &statbuf) == -1) {
350c87c5fbaSopenharmony_ci    fclose(f);
351c87c5fbaSopenharmony_ci    return NULL;
352c87c5fbaSopenharmony_ci  }
353c87c5fbaSopenharmony_ci
354c87c5fbaSopenharmony_ci  buf = coap_malloc(statbuf.st_size+1);
355c87c5fbaSopenharmony_ci  if (!buf) {
356c87c5fbaSopenharmony_ci    fclose(f);
357c87c5fbaSopenharmony_ci    return NULL;
358c87c5fbaSopenharmony_ci  }
359c87c5fbaSopenharmony_ci
360c87c5fbaSopenharmony_ci  if (fread(buf, 1, statbuf.st_size, f) != (size_t)statbuf.st_size) {
361c87c5fbaSopenharmony_ci    fclose(f);
362c87c5fbaSopenharmony_ci    coap_free(buf);
363c87c5fbaSopenharmony_ci    return NULL;
364c87c5fbaSopenharmony_ci  }
365c87c5fbaSopenharmony_ci  buf[statbuf.st_size] = '\000';
366c87c5fbaSopenharmony_ci  *length = (size_t)(statbuf.st_size + 1);
367c87c5fbaSopenharmony_ci  fclose(f);
368c87c5fbaSopenharmony_ci  return buf;
369c87c5fbaSopenharmony_ci}
370c87c5fbaSopenharmony_ci
371c87c5fbaSopenharmony_cistatic void
372c87c5fbaSopenharmony_ciusage(const char *program, const char *version) {
373c87c5fbaSopenharmony_ci  const char *p;
374c87c5fbaSopenharmony_ci  char buffer[120];
375c87c5fbaSopenharmony_ci  const char *lib_build = coap_package_build();
376c87c5fbaSopenharmony_ci
377c87c5fbaSopenharmony_ci  p = strrchr(program, '/');
378c87c5fbaSopenharmony_ci  if (p)
379c87c5fbaSopenharmony_ci    program = ++p;
380c87c5fbaSopenharmony_ci
381c87c5fbaSopenharmony_ci  fprintf(stderr, "%s v%s -- OSCORE interop implementation\n"
382c87c5fbaSopenharmony_ci          "(c) 2023 Olaf Bergmann <bergmann@tzi.org> and others\n\n"
383c87c5fbaSopenharmony_ci          "Build: %s\n"
384c87c5fbaSopenharmony_ci          "%s\n"
385c87c5fbaSopenharmony_ci          , program, version, lib_build,
386c87c5fbaSopenharmony_ci          coap_string_tls_version(buffer, sizeof(buffer)));
387c87c5fbaSopenharmony_ci  fprintf(stderr, "%s\n", coap_string_tls_support(buffer, sizeof(buffer)));
388c87c5fbaSopenharmony_ci  fprintf(stderr, "\n"
389c87c5fbaSopenharmony_ci          "Usage: %s [-d max] [-g group] [-l loss] [-p port] [-r] [-v num]\n"
390c87c5fbaSopenharmony_ci          "\t\t[-A address] [-E oscore_conf_file[,seq_file]] [-G group_if]\n"
391c87c5fbaSopenharmony_ci          "\t\t[-L value] [-N] [-P scheme://address[:port],[name1[,name2..]]]\n"
392c87c5fbaSopenharmony_ci          "\t\t[-X size]\n"
393c87c5fbaSopenharmony_ci          "General Options\n"
394c87c5fbaSopenharmony_ci          "\t-d max \t\tAllow dynamic creation of up to a total of max\n"
395c87c5fbaSopenharmony_ci          "\t       \t\tresources. If max is reached, a 4.06 code is returned\n"
396c87c5fbaSopenharmony_ci          "\t       \t\tuntil one of the dynamic resources has been deleted\n"
397c87c5fbaSopenharmony_ci          "\t-g group\tJoin the given multicast group\n"
398c87c5fbaSopenharmony_ci          "\t       \t\tNote: DTLS over multicast is not currently supported\n"
399c87c5fbaSopenharmony_ci          "\t-l list\t\tFail to send some datagrams specified by a comma\n"
400c87c5fbaSopenharmony_ci          "\t       \t\tseparated list of numbers or number ranges\n"
401c87c5fbaSopenharmony_ci          "\t       \t\t(for debugging only)\n"
402c87c5fbaSopenharmony_ci          "\t-l loss%%\tRandomly fail to send datagrams with the specified\n"
403c87c5fbaSopenharmony_ci          "\t       \t\tprobability - 100%% all datagrams, 0%% no datagrams\n"
404c87c5fbaSopenharmony_ci          "\t       \t\t(for debugging only)\n"
405c87c5fbaSopenharmony_ci          "\t-p port\t\tListen on specified port for UDP and TCP. If (D)TLS is\n"
406c87c5fbaSopenharmony_ci          "\t       \t\tenabled, then the coap-server will also listen on\n"
407c87c5fbaSopenharmony_ci          "\t       \t\t 'port'+1 for DTLS and TLS.  The default port is 5683\n"
408c87c5fbaSopenharmony_ci          "\t-r     \t\tEnable multicast per resource support.  If enabled,\n"
409c87c5fbaSopenharmony_ci          "\t       \t\tonly '/', '/async' and '/.well-known/core' are enabled\n"
410c87c5fbaSopenharmony_ci          "\t       \t\tfor multicast requests support, otherwise all\n"
411c87c5fbaSopenharmony_ci          "\t       \t\tresources are enabled\n"
412c87c5fbaSopenharmony_ci          "\t-v num \t\tVerbosity level (default 3, maximum is 9). Above 7,\n"
413c87c5fbaSopenharmony_ci          "\t       \t\tthere is increased verbosity in GnuTLS and OpenSSL\n"
414c87c5fbaSopenharmony_ci          "\t       \t\tlogging\n"
415c87c5fbaSopenharmony_ci          "\t-A address\tInterface address to bind to\n"
416c87c5fbaSopenharmony_ci          "\t-E oscore_conf_file[,seq_file]\n"
417c87c5fbaSopenharmony_ci          "\t       \t\toscore_conf_file contains OSCORE configuration. See\n"
418c87c5fbaSopenharmony_ci          "\t       \t\tcoap-oscore-conf(5) for definitions.\n"
419c87c5fbaSopenharmony_ci          "\t       \t\tOptional seq_file is used to save the current transmit\n"
420c87c5fbaSopenharmony_ci          "\t       \t\tsequence number, so on restart sequence numbers continue\n"
421c87c5fbaSopenharmony_ci          "\t-G group_if\tUse this interface for listening for the multicast\n"
422c87c5fbaSopenharmony_ci          "\t       \t\tgroup. This can be different from the implied interface\n"
423c87c5fbaSopenharmony_ci          "\t       \t\tif the -A option is used\n"
424c87c5fbaSopenharmony_ci          "\t-L value\tSum of one or more COAP_BLOCK_* flag valuess for block\n"
425c87c5fbaSopenharmony_ci          "\t       \t\thandling methods. Default is 1 (COAP_BLOCK_USE_LIBCOAP)\n"
426c87c5fbaSopenharmony_ci          "\t       \t\t(Sum of one or more of 1,2 and 4)\n"
427c87c5fbaSopenharmony_ci          "\t-N     \t\tMake \"observe\" responses NON-confirmable. Even if set\n"
428c87c5fbaSopenharmony_ci          "\t       \t\tevery fifth response will still be sent as a confirmable\n"
429c87c5fbaSopenharmony_ci          "\t       \t\tresponse (RFC 7641 requirement)\n"
430c87c5fbaSopenharmony_ci          , program);
431c87c5fbaSopenharmony_ci}
432c87c5fbaSopenharmony_ci
433c87c5fbaSopenharmony_cistatic coap_context_t *
434c87c5fbaSopenharmony_ciget_context(const char *node, const char *port) {
435c87c5fbaSopenharmony_ci  coap_context_t *ctx = NULL;
436c87c5fbaSopenharmony_ci  int s;
437c87c5fbaSopenharmony_ci  struct addrinfo hints;
438c87c5fbaSopenharmony_ci  struct addrinfo *result, *rp;
439c87c5fbaSopenharmony_ci
440c87c5fbaSopenharmony_ci  ctx = coap_new_context(NULL);
441c87c5fbaSopenharmony_ci  if (!ctx) {
442c87c5fbaSopenharmony_ci    return NULL;
443c87c5fbaSopenharmony_ci  }
444c87c5fbaSopenharmony_ci
445c87c5fbaSopenharmony_ci  memset(&hints, 0, sizeof(struct addrinfo));
446c87c5fbaSopenharmony_ci  hints.ai_family = AF_UNSPEC;    /* Allow IPv4 or IPv6 */
447c87c5fbaSopenharmony_ci  hints.ai_socktype = SOCK_DGRAM; /* Coap uses UDP */
448c87c5fbaSopenharmony_ci  hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST;
449c87c5fbaSopenharmony_ci
450c87c5fbaSopenharmony_ci  s = getaddrinfo(node, port, &hints, &result);
451c87c5fbaSopenharmony_ci  if (s != 0) {
452c87c5fbaSopenharmony_ci    fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(s));
453c87c5fbaSopenharmony_ci    coap_free_context(ctx);
454c87c5fbaSopenharmony_ci    return NULL;
455c87c5fbaSopenharmony_ci  }
456c87c5fbaSopenharmony_ci
457c87c5fbaSopenharmony_ci  /* iterate through results until success */
458c87c5fbaSopenharmony_ci  for (rp = result; rp != NULL; rp = rp->ai_next) {
459c87c5fbaSopenharmony_ci    coap_address_t addr;
460c87c5fbaSopenharmony_ci    coap_endpoint_t *ep_udp = NULL;
461c87c5fbaSopenharmony_ci
462c87c5fbaSopenharmony_ci    if (rp->ai_addrlen <= (socklen_t)sizeof(addr.addr)) {
463c87c5fbaSopenharmony_ci      coap_address_init(&addr);
464c87c5fbaSopenharmony_ci      addr.size = (socklen_t)rp->ai_addrlen;
465c87c5fbaSopenharmony_ci      memcpy(&addr.addr, rp->ai_addr, rp->ai_addrlen);
466c87c5fbaSopenharmony_ci
467c87c5fbaSopenharmony_ci      ep_udp = coap_new_endpoint(ctx, &addr, COAP_PROTO_UDP);
468c87c5fbaSopenharmony_ci      if (!ep_udp) {
469c87c5fbaSopenharmony_ci        coap_log_crit("cannot create UDP endpoint\n");
470c87c5fbaSopenharmony_ci        continue;
471c87c5fbaSopenharmony_ci      }
472c87c5fbaSopenharmony_ci      if (coap_tcp_is_supported()) {
473c87c5fbaSopenharmony_ci        coap_endpoint_t *ep_tcp;
474c87c5fbaSopenharmony_ci        ep_tcp = coap_new_endpoint(ctx, &addr, COAP_PROTO_TCP);
475c87c5fbaSopenharmony_ci        if (!ep_tcp) {
476c87c5fbaSopenharmony_ci          coap_log_crit("cannot create TCP endpoint\n");
477c87c5fbaSopenharmony_ci        }
478c87c5fbaSopenharmony_ci      }
479c87c5fbaSopenharmony_ci      if (ep_udp)
480c87c5fbaSopenharmony_ci        goto finish;
481c87c5fbaSopenharmony_ci    }
482c87c5fbaSopenharmony_ci  }
483c87c5fbaSopenharmony_ci
484c87c5fbaSopenharmony_ci  fprintf(stderr, "no context available for interface '%s'\n", node);
485c87c5fbaSopenharmony_ci  coap_free_context(ctx);
486c87c5fbaSopenharmony_ci  ctx = NULL;
487c87c5fbaSopenharmony_ci
488c87c5fbaSopenharmony_cifinish:
489c87c5fbaSopenharmony_ci  freeaddrinfo(result);
490c87c5fbaSopenharmony_ci  return ctx;
491c87c5fbaSopenharmony_ci}
492c87c5fbaSopenharmony_ci
493c87c5fbaSopenharmony_cistatic FILE *oscore_seq_num_fp = NULL;
494c87c5fbaSopenharmony_cistatic const char *oscore_conf_file = NULL;
495c87c5fbaSopenharmony_cistatic const char *oscore_seq_save_file = NULL;
496c87c5fbaSopenharmony_ci
497c87c5fbaSopenharmony_cistatic int
498c87c5fbaSopenharmony_cioscore_save_seq_num(uint64_t sender_seq_num, void *param COAP_UNUSED) {
499c87c5fbaSopenharmony_ci  if (oscore_seq_num_fp) {
500c87c5fbaSopenharmony_ci    rewind(oscore_seq_num_fp);
501c87c5fbaSopenharmony_ci    fprintf(oscore_seq_num_fp, "%" PRIu64 "\n", sender_seq_num);
502c87c5fbaSopenharmony_ci    fflush(oscore_seq_num_fp);
503c87c5fbaSopenharmony_ci  }
504c87c5fbaSopenharmony_ci  return 1;
505c87c5fbaSopenharmony_ci}
506c87c5fbaSopenharmony_ci
507c87c5fbaSopenharmony_cistatic coap_oscore_conf_t *
508c87c5fbaSopenharmony_ciget_oscore_conf(coap_context_t *context) {
509c87c5fbaSopenharmony_ci  uint8_t *buf;
510c87c5fbaSopenharmony_ci  size_t length;
511c87c5fbaSopenharmony_ci  coap_str_const_t file_mem;
512c87c5fbaSopenharmony_ci  uint64_t start_seq_num = 0;
513c87c5fbaSopenharmony_ci
514c87c5fbaSopenharmony_ci  buf = read_file_mem(oscore_conf_file, &length);
515c87c5fbaSopenharmony_ci  if (buf == NULL) {
516c87c5fbaSopenharmony_ci    fprintf(stderr, "OSCORE configuration file error: %s\n", oscore_conf_file);
517c87c5fbaSopenharmony_ci    return NULL;
518c87c5fbaSopenharmony_ci  }
519c87c5fbaSopenharmony_ci  file_mem.s = buf;
520c87c5fbaSopenharmony_ci  file_mem.length = length;
521c87c5fbaSopenharmony_ci  if (oscore_seq_save_file) {
522c87c5fbaSopenharmony_ci    oscore_seq_num_fp = fopen(oscore_seq_save_file, "r+");
523c87c5fbaSopenharmony_ci    if (oscore_seq_num_fp == NULL) {
524c87c5fbaSopenharmony_ci      /* Try creating it */
525c87c5fbaSopenharmony_ci      oscore_seq_num_fp = fopen(oscore_seq_save_file, "w+");
526c87c5fbaSopenharmony_ci      if (oscore_seq_num_fp == NULL) {
527c87c5fbaSopenharmony_ci        fprintf(stderr, "OSCORE save restart info file error: %s\n",
528c87c5fbaSopenharmony_ci                oscore_seq_save_file);
529c87c5fbaSopenharmony_ci        return NULL;
530c87c5fbaSopenharmony_ci      }
531c87c5fbaSopenharmony_ci    }
532c87c5fbaSopenharmony_ci    if (fscanf(oscore_seq_num_fp, "%" PRIu64, &start_seq_num) != 1) {
533c87c5fbaSopenharmony_ci      /* Must be empty */
534c87c5fbaSopenharmony_ci      start_seq_num = 0;
535c87c5fbaSopenharmony_ci    }
536c87c5fbaSopenharmony_ci  }
537c87c5fbaSopenharmony_ci  oscore_conf = coap_new_oscore_conf(file_mem,
538c87c5fbaSopenharmony_ci                                     oscore_save_seq_num,
539c87c5fbaSopenharmony_ci                                     NULL, start_seq_num);
540c87c5fbaSopenharmony_ci  coap_free(buf);
541c87c5fbaSopenharmony_ci  if (oscore_conf == NULL) {
542c87c5fbaSopenharmony_ci    fprintf(stderr, "OSCORE configuration file error: %s\n", oscore_conf_file);
543c87c5fbaSopenharmony_ci    return NULL;
544c87c5fbaSopenharmony_ci  }
545c87c5fbaSopenharmony_ci  coap_context_oscore_server(context, oscore_conf);
546c87c5fbaSopenharmony_ci  return oscore_conf;
547c87c5fbaSopenharmony_ci}
548c87c5fbaSopenharmony_ci
549c87c5fbaSopenharmony_cistatic int
550c87c5fbaSopenharmony_cicmdline_oscore(char *arg) {
551c87c5fbaSopenharmony_ci  if (coap_oscore_is_supported()) {
552c87c5fbaSopenharmony_ci    char *sep = strchr(arg, ',');
553c87c5fbaSopenharmony_ci
554c87c5fbaSopenharmony_ci    if (sep)
555c87c5fbaSopenharmony_ci      *sep = '\000';
556c87c5fbaSopenharmony_ci    oscore_conf_file = arg;
557c87c5fbaSopenharmony_ci
558c87c5fbaSopenharmony_ci    if (sep) {
559c87c5fbaSopenharmony_ci      sep++;
560c87c5fbaSopenharmony_ci      oscore_seq_save_file = sep;
561c87c5fbaSopenharmony_ci    }
562c87c5fbaSopenharmony_ci    doing_oscore = 1;
563c87c5fbaSopenharmony_ci    return 1;
564c87c5fbaSopenharmony_ci  }
565c87c5fbaSopenharmony_ci  fprintf(stderr, "OSCORE support not enabled\n");
566c87c5fbaSopenharmony_ci  return 0;
567c87c5fbaSopenharmony_ci}
568c87c5fbaSopenharmony_ci
569c87c5fbaSopenharmony_ciint
570c87c5fbaSopenharmony_cimain(int argc, char **argv) {
571c87c5fbaSopenharmony_ci  coap_context_t  *ctx;
572c87c5fbaSopenharmony_ci  char *group = NULL;
573c87c5fbaSopenharmony_ci  char *group_if = NULL;
574c87c5fbaSopenharmony_ci  coap_tick_t now;
575c87c5fbaSopenharmony_ci  char addr_str[NI_MAXHOST] = "::";
576c87c5fbaSopenharmony_ci  char port_str[NI_MAXSERV] = "5683";
577c87c5fbaSopenharmony_ci  int opt;
578c87c5fbaSopenharmony_ci  int mcast_per_resource = 0;
579c87c5fbaSopenharmony_ci  coap_log_t log_level = COAP_LOG_WARN;
580c87c5fbaSopenharmony_ci  unsigned wait_ms;
581c87c5fbaSopenharmony_ci  coap_time_t t_last = 0;
582c87c5fbaSopenharmony_ci  int coap_fd;
583c87c5fbaSopenharmony_ci  fd_set m_readfds;
584c87c5fbaSopenharmony_ci  int nfds = 0;
585c87c5fbaSopenharmony_ci  uint16_t cache_ignore_options[] = { COAP_OPTION_BLOCK1,
586c87c5fbaSopenharmony_ci                                      COAP_OPTION_BLOCK2,
587c87c5fbaSopenharmony_ci                                      /* See https://rfc-editor.org/rfc/rfc7959#section-2.10 */
588c87c5fbaSopenharmony_ci                                      COAP_OPTION_MAXAGE,
589c87c5fbaSopenharmony_ci                                      /* See https://rfc-editor.org/rfc/rfc7959#section-2.10 */
590c87c5fbaSopenharmony_ci                                      COAP_OPTION_IF_NONE_MATCH
591c87c5fbaSopenharmony_ci                                    };
592c87c5fbaSopenharmony_ci#ifndef _WIN32
593c87c5fbaSopenharmony_ci  struct sigaction sa;
594c87c5fbaSopenharmony_ci#endif
595c87c5fbaSopenharmony_ci
596c87c5fbaSopenharmony_ci  /* Initialize libcoap library */
597c87c5fbaSopenharmony_ci  coap_startup();
598c87c5fbaSopenharmony_ci
599c87c5fbaSopenharmony_ci  while ((opt = getopt(argc, argv, "g:G:l:p:rv:A:E:L:NX:")) != -1) {
600c87c5fbaSopenharmony_ci    switch (opt) {
601c87c5fbaSopenharmony_ci    case 'A' :
602c87c5fbaSopenharmony_ci      strncpy(addr_str, optarg, NI_MAXHOST-1);
603c87c5fbaSopenharmony_ci      addr_str[NI_MAXHOST - 1] = '\0';
604c87c5fbaSopenharmony_ci      break;
605c87c5fbaSopenharmony_ci    case 'E':
606c87c5fbaSopenharmony_ci      if (!cmdline_oscore(optarg)) {
607c87c5fbaSopenharmony_ci        exit(1);
608c87c5fbaSopenharmony_ci      }
609c87c5fbaSopenharmony_ci      break;
610c87c5fbaSopenharmony_ci    case 'g' :
611c87c5fbaSopenharmony_ci      group = optarg;
612c87c5fbaSopenharmony_ci      break;
613c87c5fbaSopenharmony_ci    case 'G' :
614c87c5fbaSopenharmony_ci      group_if = optarg;
615c87c5fbaSopenharmony_ci      break;
616c87c5fbaSopenharmony_ci    case 'l':
617c87c5fbaSopenharmony_ci      if (!coap_debug_set_packet_loss(optarg)) {
618c87c5fbaSopenharmony_ci        usage(argv[0], LIBCOAP_PACKAGE_VERSION);
619c87c5fbaSopenharmony_ci        exit(1);
620c87c5fbaSopenharmony_ci      }
621c87c5fbaSopenharmony_ci      break;
622c87c5fbaSopenharmony_ci    case 'L':
623c87c5fbaSopenharmony_ci      block_mode = strtoul(optarg, NULL, 0);
624c87c5fbaSopenharmony_ci      if (!(block_mode & COAP_BLOCK_USE_LIBCOAP)) {
625c87c5fbaSopenharmony_ci        fprintf(stderr, "Block mode must include COAP_BLOCK_USE_LIBCOAP (1)\n");
626c87c5fbaSopenharmony_ci        exit(-1);
627c87c5fbaSopenharmony_ci      }
628c87c5fbaSopenharmony_ci      break;
629c87c5fbaSopenharmony_ci    case 'N':
630c87c5fbaSopenharmony_ci      resource_flags = COAP_RESOURCE_FLAGS_NOTIFY_NON;
631c87c5fbaSopenharmony_ci      break;
632c87c5fbaSopenharmony_ci    case 'p' :
633c87c5fbaSopenharmony_ci      strncpy(port_str, optarg, NI_MAXSERV-1);
634c87c5fbaSopenharmony_ci      port_str[NI_MAXSERV - 1] = '\0';
635c87c5fbaSopenharmony_ci      break;
636c87c5fbaSopenharmony_ci    case 'r' :
637c87c5fbaSopenharmony_ci      mcast_per_resource = 1;
638c87c5fbaSopenharmony_ci      break;
639c87c5fbaSopenharmony_ci    case 'v' :
640c87c5fbaSopenharmony_ci      log_level = strtol(optarg, NULL, 10);
641c87c5fbaSopenharmony_ci      break;
642c87c5fbaSopenharmony_ci    case 'X':
643c87c5fbaSopenharmony_ci      csm_max_message_size = strtol(optarg, NULL, 10);
644c87c5fbaSopenharmony_ci      break;
645c87c5fbaSopenharmony_ci    default:
646c87c5fbaSopenharmony_ci      usage(argv[0], LIBCOAP_PACKAGE_VERSION);
647c87c5fbaSopenharmony_ci      exit(1);
648c87c5fbaSopenharmony_ci    }
649c87c5fbaSopenharmony_ci  }
650c87c5fbaSopenharmony_ci
651c87c5fbaSopenharmony_ci#ifdef _WIN32
652c87c5fbaSopenharmony_ci  signal(SIGINT, handle_sigint);
653c87c5fbaSopenharmony_ci#else
654c87c5fbaSopenharmony_ci  memset(&sa, 0, sizeof(sa));
655c87c5fbaSopenharmony_ci  sigemptyset(&sa.sa_mask);
656c87c5fbaSopenharmony_ci  sa.sa_handler = handle_sigint;
657c87c5fbaSopenharmony_ci  sa.sa_flags = 0;
658c87c5fbaSopenharmony_ci  sigaction(SIGINT, &sa, NULL);
659c87c5fbaSopenharmony_ci  sigaction(SIGTERM, &sa, NULL);
660c87c5fbaSopenharmony_ci  /* So we do not exit on a SIGPIPE */
661c87c5fbaSopenharmony_ci  sa.sa_handler = SIG_IGN;
662c87c5fbaSopenharmony_ci  sigaction(SIGPIPE, &sa, NULL);
663c87c5fbaSopenharmony_ci#endif
664c87c5fbaSopenharmony_ci
665c87c5fbaSopenharmony_ci  coap_dtls_set_log_level(log_level);
666c87c5fbaSopenharmony_ci  coap_set_log_level(log_level);
667c87c5fbaSopenharmony_ci
668c87c5fbaSopenharmony_ci  ctx = get_context(addr_str, port_str);
669c87c5fbaSopenharmony_ci  if (!ctx)
670c87c5fbaSopenharmony_ci    return -1;
671c87c5fbaSopenharmony_ci
672c87c5fbaSopenharmony_ci  init_resources(ctx);
673c87c5fbaSopenharmony_ci  if (mcast_per_resource)
674c87c5fbaSopenharmony_ci    coap_mcast_per_resource(ctx);
675c87c5fbaSopenharmony_ci  coap_context_set_block_mode(ctx, block_mode);
676c87c5fbaSopenharmony_ci  if (csm_max_message_size)
677c87c5fbaSopenharmony_ci    coap_context_set_csm_max_message_size(ctx, csm_max_message_size);
678c87c5fbaSopenharmony_ci  if (doing_oscore) {
679c87c5fbaSopenharmony_ci    if (get_oscore_conf(ctx) == NULL)
680c87c5fbaSopenharmony_ci      goto finish;
681c87c5fbaSopenharmony_ci  }
682c87c5fbaSopenharmony_ci
683c87c5fbaSopenharmony_ci  /* Define the options to ignore when setting up cache-keys */
684c87c5fbaSopenharmony_ci  coap_cache_ignore_options(ctx, cache_ignore_options,
685c87c5fbaSopenharmony_ci                            sizeof(cache_ignore_options)/sizeof(cache_ignore_options[0]));
686c87c5fbaSopenharmony_ci  /* join multicast group if requested at command line */
687c87c5fbaSopenharmony_ci  if (group)
688c87c5fbaSopenharmony_ci    coap_join_mcast_group_intf(ctx, group, group_if);
689c87c5fbaSopenharmony_ci
690c87c5fbaSopenharmony_ci  coap_fd = coap_context_get_coap_fd(ctx);
691c87c5fbaSopenharmony_ci  if (coap_fd != -1) {
692c87c5fbaSopenharmony_ci    /* if coap_fd is -1, then epoll is not supported within libcoap */
693c87c5fbaSopenharmony_ci    FD_ZERO(&m_readfds);
694c87c5fbaSopenharmony_ci    FD_SET(coap_fd, &m_readfds);
695c87c5fbaSopenharmony_ci    nfds = coap_fd + 1;
696c87c5fbaSopenharmony_ci  }
697c87c5fbaSopenharmony_ci
698c87c5fbaSopenharmony_ci  wait_ms = COAP_RESOURCE_CHECK_TIME * 1000;
699c87c5fbaSopenharmony_ci
700c87c5fbaSopenharmony_ci  while (!quit) {
701c87c5fbaSopenharmony_ci    int result;
702c87c5fbaSopenharmony_ci
703c87c5fbaSopenharmony_ci    if (coap_fd != -1) {
704c87c5fbaSopenharmony_ci      /*
705c87c5fbaSopenharmony_ci       * Using epoll.  It is more usual to call coap_io_process() with wait_ms
706c87c5fbaSopenharmony_ci       * (as in the non-epoll branch), but doing it this way gives the
707c87c5fbaSopenharmony_ci       * flexibility of potentially working with other file descriptors that
708c87c5fbaSopenharmony_ci       * are not a part of libcoap.
709c87c5fbaSopenharmony_ci       */
710c87c5fbaSopenharmony_ci      fd_set readfds = m_readfds;
711c87c5fbaSopenharmony_ci      struct timeval tv;
712c87c5fbaSopenharmony_ci      coap_tick_t begin, end;
713c87c5fbaSopenharmony_ci
714c87c5fbaSopenharmony_ci      coap_ticks(&begin);
715c87c5fbaSopenharmony_ci
716c87c5fbaSopenharmony_ci      tv.tv_sec = wait_ms / 1000;
717c87c5fbaSopenharmony_ci      tv.tv_usec = (wait_ms % 1000) * 1000;
718c87c5fbaSopenharmony_ci      /* Wait until any i/o takes place or timeout */
719c87c5fbaSopenharmony_ci      result = select(nfds, &readfds, NULL, NULL, &tv);
720c87c5fbaSopenharmony_ci      if (result == -1) {
721c87c5fbaSopenharmony_ci        if (errno != EAGAIN) {
722c87c5fbaSopenharmony_ci          coap_log_debug("select: %s (%d)\n", coap_socket_strerror(),
723c87c5fbaSopenharmony_ci                         errno);
724c87c5fbaSopenharmony_ci          break;
725c87c5fbaSopenharmony_ci        }
726c87c5fbaSopenharmony_ci      }
727c87c5fbaSopenharmony_ci      if (result > 0) {
728c87c5fbaSopenharmony_ci        if (FD_ISSET(coap_fd, &readfds)) {
729c87c5fbaSopenharmony_ci          result = coap_io_process(ctx, COAP_IO_NO_WAIT);
730c87c5fbaSopenharmony_ci        }
731c87c5fbaSopenharmony_ci      }
732c87c5fbaSopenharmony_ci      if (result >= 0) {
733c87c5fbaSopenharmony_ci        coap_ticks(&end);
734c87c5fbaSopenharmony_ci        /* Track the overall time spent in select() and coap_io_process() */
735c87c5fbaSopenharmony_ci        result = (int)(end - begin);
736c87c5fbaSopenharmony_ci      }
737c87c5fbaSopenharmony_ci    } else {
738c87c5fbaSopenharmony_ci      /*
739c87c5fbaSopenharmony_ci       * epoll is not supported within libcoap
740c87c5fbaSopenharmony_ci       *
741c87c5fbaSopenharmony_ci       * result is time spent in coap_io_process()
742c87c5fbaSopenharmony_ci       */
743c87c5fbaSopenharmony_ci      result = coap_io_process(ctx, wait_ms);
744c87c5fbaSopenharmony_ci    }
745c87c5fbaSopenharmony_ci    if (result < 0) {
746c87c5fbaSopenharmony_ci      break;
747c87c5fbaSopenharmony_ci    } else if (result && (unsigned)result < wait_ms) {
748c87c5fbaSopenharmony_ci      /* decrement if there is a result wait time returned */
749c87c5fbaSopenharmony_ci      wait_ms -= result;
750c87c5fbaSopenharmony_ci    } else {
751c87c5fbaSopenharmony_ci      /*
752c87c5fbaSopenharmony_ci       * result == 0, or result >= wait_ms
753c87c5fbaSopenharmony_ci       * (wait_ms could have decremented to a small value, below
754c87c5fbaSopenharmony_ci       * the granularity of the timer in coap_io_process() and hence
755c87c5fbaSopenharmony_ci       * result == 0)
756c87c5fbaSopenharmony_ci       */
757c87c5fbaSopenharmony_ci      wait_ms = COAP_RESOURCE_CHECK_TIME * 1000;
758c87c5fbaSopenharmony_ci    }
759c87c5fbaSopenharmony_ci    if (r_observe_1 || r_observe_2) {
760c87c5fbaSopenharmony_ci      coap_time_t t_now;
761c87c5fbaSopenharmony_ci      unsigned int next_sec_ms;
762c87c5fbaSopenharmony_ci
763c87c5fbaSopenharmony_ci      coap_ticks(&now);
764c87c5fbaSopenharmony_ci      t_now = coap_ticks_to_rt(now);
765c87c5fbaSopenharmony_ci      if (t_last != t_now) {
766c87c5fbaSopenharmony_ci        /* Happens once per second */
767c87c5fbaSopenharmony_ci        t_last = t_now;
768c87c5fbaSopenharmony_ci        if (r_observe_1)
769c87c5fbaSopenharmony_ci          coap_resource_notify_observers(r_observe_1, NULL);
770c87c5fbaSopenharmony_ci        if (r_observe_2)
771c87c5fbaSopenharmony_ci          coap_resource_notify_observers(r_observe_2, NULL);
772c87c5fbaSopenharmony_ci      }
773c87c5fbaSopenharmony_ci      /* need to wait until next second starts if wait_ms is too large */
774c87c5fbaSopenharmony_ci      next_sec_ms = 1000 - (now % COAP_TICKS_PER_SECOND) *
775c87c5fbaSopenharmony_ci                    1000 / COAP_TICKS_PER_SECOND;
776c87c5fbaSopenharmony_ci      if (next_sec_ms && next_sec_ms < wait_ms)
777c87c5fbaSopenharmony_ci        wait_ms = next_sec_ms;
778c87c5fbaSopenharmony_ci    }
779c87c5fbaSopenharmony_ci  }
780c87c5fbaSopenharmony_ci
781c87c5fbaSopenharmony_cifinish:
782c87c5fbaSopenharmony_ci
783c87c5fbaSopenharmony_ci  if (oscore_seq_num_fp)
784c87c5fbaSopenharmony_ci    fclose(oscore_seq_num_fp);
785c87c5fbaSopenharmony_ci
786c87c5fbaSopenharmony_ci  coap_free_context(ctx);
787c87c5fbaSopenharmony_ci  coap_cleanup();
788c87c5fbaSopenharmony_ci
789c87c5fbaSopenharmony_ci  return 0;
790c87c5fbaSopenharmony_ci}
791