1c87c5fbaSopenharmony_ci/*
2c87c5fbaSopenharmony_ci * server-coap.c -- LwIP example
3c87c5fbaSopenharmony_ci *
4c87c5fbaSopenharmony_ci * Copyright (C) 2013-2016 Christian Amsüss <chrysn@fsfe.org>
5c87c5fbaSopenharmony_ci * Copyright (C) 2018-2023 Jon Shallow <supjps-libcoap@jpshallow.com>
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
10c87c5fbaSopenharmony_ci * of use.
11c87c5fbaSopenharmony_ci */
12c87c5fbaSopenharmony_ci
13c87c5fbaSopenharmony_ci#include "coap_config.h"
14c87c5fbaSopenharmony_ci#include <coap3/coap.h>
15c87c5fbaSopenharmony_ci#include "server-coap.h"
16c87c5fbaSopenharmony_ci
17c87c5fbaSopenharmony_cicoap_context_t *main_coap_context;
18c87c5fbaSopenharmony_ci
19c87c5fbaSopenharmony_cistatic coap_time_t clock_offset;
20c87c5fbaSopenharmony_ci/* changeable clock base (see handle_put_time()) */
21c87c5fbaSopenharmony_cistatic coap_time_t my_clock_base = 0;
22c87c5fbaSopenharmony_cistatic coap_resource_t *time_resource = NULL; /* just for testing */
23c87c5fbaSopenharmony_ci
24c87c5fbaSopenharmony_ci#ifndef min
25c87c5fbaSopenharmony_ci# define min(a,b) ((a) < (b) ? (a) : (b))
26c87c5fbaSopenharmony_ci#endif
27c87c5fbaSopenharmony_ci
28c87c5fbaSopenharmony_civoid
29c87c5fbaSopenharmony_cihnd_get_time(coap_resource_t *resource, coap_session_t  *session,
30c87c5fbaSopenharmony_ci             const coap_pdu_t *request, const coap_string_t *query,
31c87c5fbaSopenharmony_ci             coap_pdu_t *response) {
32c87c5fbaSopenharmony_ci  unsigned char buf[40];
33c87c5fbaSopenharmony_ci  size_t len;
34c87c5fbaSopenharmony_ci  coap_tick_t now;
35c87c5fbaSopenharmony_ci  coap_tick_t t;
36c87c5fbaSopenharmony_ci
37c87c5fbaSopenharmony_ci  (void)resource;
38c87c5fbaSopenharmony_ci  (void)session;
39c87c5fbaSopenharmony_ci  (void)request;
40c87c5fbaSopenharmony_ci  /* FIXME: return time, e.g. in human-readable by default and ticks
41c87c5fbaSopenharmony_ci   * when query ?ticks is given. */
42c87c5fbaSopenharmony_ci
43c87c5fbaSopenharmony_ci  /* if my_clock_base was deleted, we pretend to have no such resource */
44c87c5fbaSopenharmony_ci  response->code =
45c87c5fbaSopenharmony_ci      my_clock_base ? COAP_RESPONSE_CODE(205) : COAP_RESPONSE_CODE(404);
46c87c5fbaSopenharmony_ci
47c87c5fbaSopenharmony_ci  if (my_clock_base)
48c87c5fbaSopenharmony_ci    coap_add_option(response, COAP_OPTION_CONTENT_FORMAT,
49c87c5fbaSopenharmony_ci                    coap_encode_var_safe(buf, sizeof(buf),
50c87c5fbaSopenharmony_ci                                         COAP_MEDIATYPE_TEXT_PLAIN),
51c87c5fbaSopenharmony_ci                    buf);
52c87c5fbaSopenharmony_ci
53c87c5fbaSopenharmony_ci  coap_add_option(response, COAP_OPTION_MAXAGE,
54c87c5fbaSopenharmony_ci                  coap_encode_var_safe(buf, sizeof(buf), 0x01), buf);
55c87c5fbaSopenharmony_ci
56c87c5fbaSopenharmony_ci  if (my_clock_base) {
57c87c5fbaSopenharmony_ci
58c87c5fbaSopenharmony_ci    /* calculate current time */
59c87c5fbaSopenharmony_ci    coap_ticks(&t);
60c87c5fbaSopenharmony_ci    now = my_clock_base + (t / COAP_TICKS_PER_SECOND);
61c87c5fbaSopenharmony_ci
62c87c5fbaSopenharmony_ci
63c87c5fbaSopenharmony_ci    if (query != NULL
64c87c5fbaSopenharmony_ci        && coap_string_equal(query, coap_make_str_const("ticks"))) {
65c87c5fbaSopenharmony_ci      /* output ticks */
66c87c5fbaSopenharmony_ci      len = snprintf((char *)buf, sizeof(buf), "%u", (unsigned int)now);
67c87c5fbaSopenharmony_ci      coap_add_data(response, len, buf);
68c87c5fbaSopenharmony_ci    }
69c87c5fbaSopenharmony_ci  }
70c87c5fbaSopenharmony_ci}
71c87c5fbaSopenharmony_ci
72c87c5fbaSopenharmony_civoid
73c87c5fbaSopenharmony_ciinit_coap_resources(coap_context_t *ctx) {
74c87c5fbaSopenharmony_ci  coap_resource_t *r;
75c87c5fbaSopenharmony_ci#if 0
76c87c5fbaSopenharmony_ci  r = coap_resource_init(NULL, 0, 0);
77c87c5fbaSopenharmony_ci  coap_register_handler(r, COAP_REQUEST_GET, hnd_get_index);
78c87c5fbaSopenharmony_ci
79c87c5fbaSopenharmony_ci  coap_add_attr(r, coap_make_str_const("ct"), coap_make_str_const("0"), 0);
80c87c5fbaSopenharmony_ci  coap_add_attr(r, coap_make_str_const("title"), coap_make_str_const("\"General Info\""), 0);
81c87c5fbaSopenharmony_ci  coap_add_resource(ctx, r);
82c87c5fbaSopenharmony_ci#endif
83c87c5fbaSopenharmony_ci  /* store clock base to use in /time */
84c87c5fbaSopenharmony_ci  my_clock_base = clock_offset;
85c87c5fbaSopenharmony_ci
86c87c5fbaSopenharmony_ci  r = coap_resource_init(coap_make_str_const("time"), 0);
87c87c5fbaSopenharmony_ci  if (!r)
88c87c5fbaSopenharmony_ci    goto error;
89c87c5fbaSopenharmony_ci
90c87c5fbaSopenharmony_ci  coap_resource_set_get_observable(r, 1);
91c87c5fbaSopenharmony_ci  time_resource = r;
92c87c5fbaSopenharmony_ci  coap_register_handler(r, COAP_REQUEST_GET, hnd_get_time);
93c87c5fbaSopenharmony_ci#if 0
94c87c5fbaSopenharmony_ci  coap_register_handler(r, COAP_REQUEST_PUT, hnd_put_time);
95c87c5fbaSopenharmony_ci  coap_register_handler(r, COAP_REQUEST_DELETE, hnd_delete_time);
96c87c5fbaSopenharmony_ci#endif
97c87c5fbaSopenharmony_ci  coap_add_attr(r, coap_make_str_const("ct"), coap_make_str_const("0"), 0);
98c87c5fbaSopenharmony_ci  /* coap_add_attr(r, coap_make_str_const("title"), coap_make_str_const("\"Internal Clock\""), 0); */
99c87c5fbaSopenharmony_ci  coap_add_attr(r, coap_make_str_const("rt"), coap_make_str_const("\"ticks\""), 0);
100c87c5fbaSopenharmony_ci  coap_add_attr(r, coap_make_str_const("if"), coap_make_str_const("\"clock\""), 0);
101c87c5fbaSopenharmony_ci
102c87c5fbaSopenharmony_ci  coap_add_resource(ctx, r);
103c87c5fbaSopenharmony_ci#if 0
104c87c5fbaSopenharmony_ci  if (coap_async_is_supported()) {
105c87c5fbaSopenharmony_ci    r = coap_resource_init(coap_make_str_const("async"), 0);
106c87c5fbaSopenharmony_ci    coap_register_handler(r, COAP_REQUEST_GET, hnd_get_async);
107c87c5fbaSopenharmony_ci
108c87c5fbaSopenharmony_ci    coap_add_attr(r, coap_make_str_const("ct"), coap_make_str_const("0"), 0);
109c87c5fbaSopenharmony_ci    coap_add_resource(ctx, r);
110c87c5fbaSopenharmony_ci  }
111c87c5fbaSopenharmony_ci#endif
112c87c5fbaSopenharmony_ci
113c87c5fbaSopenharmony_ci  return;
114c87c5fbaSopenharmony_cierror:
115c87c5fbaSopenharmony_ci  coap_log_crit("cannot create resource\n");
116c87c5fbaSopenharmony_ci}
117c87c5fbaSopenharmony_ci
118c87c5fbaSopenharmony_civoid
119c87c5fbaSopenharmony_ciserver_coap_init(coap_lwip_input_wait_handler_t input_wait,
120c87c5fbaSopenharmony_ci                 void *input_arg, int argc, char **argv) {
121c87c5fbaSopenharmony_ci  int opt;
122c87c5fbaSopenharmony_ci  coap_log_t log_level = COAP_LOG_WARN;
123c87c5fbaSopenharmony_ci  coap_log_t dtls_log_level = COAP_LOG_ERR;
124c87c5fbaSopenharmony_ci  const char *use_psk = "secretPSK";
125c87c5fbaSopenharmony_ci  uint32_t scheme_hint_bits = 0;
126c87c5fbaSopenharmony_ci  coap_addr_info_t *info = NULL;
127c87c5fbaSopenharmony_ci  coap_addr_info_t *info_list = NULL;
128c87c5fbaSopenharmony_ci  int have_ep = 0;
129c87c5fbaSopenharmony_ci  coap_str_const_t node;
130c87c5fbaSopenharmony_ci
131c87c5fbaSopenharmony_ci  /* Initialize libcoap library */
132c87c5fbaSopenharmony_ci  coap_startup();
133c87c5fbaSopenharmony_ci
134c87c5fbaSopenharmony_ci  while ((opt = getopt(argc, argv, ":k:v:V:")) != -1) {
135c87c5fbaSopenharmony_ci    switch (opt) {
136c87c5fbaSopenharmony_ci    case 'k':
137c87c5fbaSopenharmony_ci      use_psk = optarg;
138c87c5fbaSopenharmony_ci      break;
139c87c5fbaSopenharmony_ci    case 'v':
140c87c5fbaSopenharmony_ci      log_level = atoi(optarg);
141c87c5fbaSopenharmony_ci      break;
142c87c5fbaSopenharmony_ci    case 'V':
143c87c5fbaSopenharmony_ci      dtls_log_level = atoi(optarg);
144c87c5fbaSopenharmony_ci      break;
145c87c5fbaSopenharmony_ci    default:
146c87c5fbaSopenharmony_ci      printf("%s [-k PSK] [-v level] [ -V level]\n", argv[0]);
147c87c5fbaSopenharmony_ci      exit(1);
148c87c5fbaSopenharmony_ci    }
149c87c5fbaSopenharmony_ci  }
150c87c5fbaSopenharmony_ci
151c87c5fbaSopenharmony_ci  coap_startup();
152c87c5fbaSopenharmony_ci  coap_set_log_level(log_level);
153c87c5fbaSopenharmony_ci  coap_dtls_set_log_level(dtls_log_level);
154c87c5fbaSopenharmony_ci
155c87c5fbaSopenharmony_ci  main_coap_context = coap_new_context(NULL);
156c87c5fbaSopenharmony_ci  LWIP_ASSERT("Failed to initialize context", main_coap_context != NULL);
157c87c5fbaSopenharmony_ci
158c87c5fbaSopenharmony_ci  if (coap_dtls_is_supported()) {
159c87c5fbaSopenharmony_ci    coap_dtls_spsk_t setup_data;
160c87c5fbaSopenharmony_ci
161c87c5fbaSopenharmony_ci    memset(&setup_data, 0, sizeof(setup_data));
162c87c5fbaSopenharmony_ci    setup_data.version = COAP_DTLS_SPSK_SETUP_VERSION;
163c87c5fbaSopenharmony_ci    setup_data.psk_info.key.s = (const uint8_t *)use_psk;
164c87c5fbaSopenharmony_ci    setup_data.psk_info.key.length = strlen(use_psk);
165c87c5fbaSopenharmony_ci    coap_context_set_psk2(main_coap_context, &setup_data);
166c87c5fbaSopenharmony_ci  }
167c87c5fbaSopenharmony_ci
168c87c5fbaSopenharmony_ci  node.s = (const uint8_t *)"::";
169c87c5fbaSopenharmony_ci  node.length = 2;
170c87c5fbaSopenharmony_ci  scheme_hint_bits =
171c87c5fbaSopenharmony_ci      coap_get_available_scheme_hint_bits(use_psk[0],
172c87c5fbaSopenharmony_ci                                          0, COAP_PROTO_NONE);
173c87c5fbaSopenharmony_ci  info_list = coap_resolve_address_info(&node, 0, 0,
174c87c5fbaSopenharmony_ci                                        0, 0,
175c87c5fbaSopenharmony_ci                                        0,
176c87c5fbaSopenharmony_ci                                        scheme_hint_bits,
177c87c5fbaSopenharmony_ci                                        COAP_RESOLVE_TYPE_LOCAL);
178c87c5fbaSopenharmony_ci  for (info = info_list; info != NULL; info = info->next) {
179c87c5fbaSopenharmony_ci    coap_endpoint_t *ep;
180c87c5fbaSopenharmony_ci
181c87c5fbaSopenharmony_ci    ep = coap_new_endpoint(main_coap_context, &info->addr, info->proto);
182c87c5fbaSopenharmony_ci    if (!ep) {
183c87c5fbaSopenharmony_ci      coap_log_warn("cannot create endpoint for proto %u\n",
184c87c5fbaSopenharmony_ci                    info->proto);
185c87c5fbaSopenharmony_ci    } else {
186c87c5fbaSopenharmony_ci      have_ep = 1;
187c87c5fbaSopenharmony_ci    }
188c87c5fbaSopenharmony_ci  }
189c87c5fbaSopenharmony_ci  coap_free_address_info(info_list);
190c87c5fbaSopenharmony_ci  LWIP_ASSERT("Failed to initialize context", have_ep != 0);
191c87c5fbaSopenharmony_ci
192c87c5fbaSopenharmony_ci  /* Limit the number of idle sessions to save RAM (MEMP_NUM_COAPSESSION) */
193c87c5fbaSopenharmony_ci  LWIP_ASSERT("Need a minimum of 2 for MEMP_NUM_COAPSESSION", MEMP_NUM_COAPSESSION > 1);
194c87c5fbaSopenharmony_ci  coap_context_set_max_idle_sessions(main_coap_context, MEMP_NUM_COAPSESSION -1);
195c87c5fbaSopenharmony_ci  clock_offset = 1; /* Need a non-zero value */
196c87c5fbaSopenharmony_ci  init_coap_resources(main_coap_context);
197c87c5fbaSopenharmony_ci  coap_lwip_set_input_wait_handler(main_coap_context, input_wait, input_arg);
198c87c5fbaSopenharmony_ci}
199c87c5fbaSopenharmony_ci
200c87c5fbaSopenharmony_civoid
201c87c5fbaSopenharmony_ciserver_coap_finished(void) {
202c87c5fbaSopenharmony_ci  coap_free_context(main_coap_context);
203c87c5fbaSopenharmony_ci  main_coap_context = NULL;
204c87c5fbaSopenharmony_ci  coap_cleanup();
205c87c5fbaSopenharmony_ci}
206c87c5fbaSopenharmony_ci
207c87c5fbaSopenharmony_civoid
208c87c5fbaSopenharmony_ciserver_coap_poll(void) {
209c87c5fbaSopenharmony_ci  static coap_time_t last_time = 0;
210c87c5fbaSopenharmony_ci  coap_tick_t ticks_now;
211c87c5fbaSopenharmony_ci  coap_time_t time_now;
212c87c5fbaSopenharmony_ci
213c87c5fbaSopenharmony_ci  coap_io_process(main_coap_context, 1000);
214c87c5fbaSopenharmony_ci  coap_ticks(&ticks_now);
215c87c5fbaSopenharmony_ci  time_now = coap_ticks_to_rt(ticks_now);
216c87c5fbaSopenharmony_ci
217c87c5fbaSopenharmony_ci  if (last_time != time_now) {
218c87c5fbaSopenharmony_ci    /* This takes place once a second */
219c87c5fbaSopenharmony_ci    last_time = time_now;
220c87c5fbaSopenharmony_ci    coap_resource_notify_observers(time_resource, NULL);
221c87c5fbaSopenharmony_ci  }
222c87c5fbaSopenharmony_ci  coap_check_notify(main_coap_context);
223c87c5fbaSopenharmony_ci}
224