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