1c87c5fbaSopenharmony_ci/* CoAP server for first ETSI CoAP plugtest, March 2012
2c87c5fbaSopenharmony_ci *
3c87c5fbaSopenharmony_ci * Copyright (C) 2012--2013 Olaf Bergmann <bergmann@tzi.org>
4c87c5fbaSopenharmony_ci *
5c87c5fbaSopenharmony_ci * SPDX-License-Identifier: BSD-2-Clause
6c87c5fbaSopenharmony_ci *
7c87c5fbaSopenharmony_ci * This file is part of the CoAP library libcoap. Please see
8c87c5fbaSopenharmony_ci * README for terms of use.
9c87c5fbaSopenharmony_ci */
10c87c5fbaSopenharmony_ci
11c87c5fbaSopenharmony_ci#include <string.h>
12c87c5fbaSopenharmony_ci#include <stdlib.h>
13c87c5fbaSopenharmony_ci#include <unistd.h>
14c87c5fbaSopenharmony_ci#include <stdio.h>
15c87c5fbaSopenharmony_ci#include <ctype.h>
16c87c5fbaSopenharmony_ci#include <sys/select.h>
17c87c5fbaSopenharmony_ci#include <sys/types.h>
18c87c5fbaSopenharmony_ci#include <sys/socket.h>
19c87c5fbaSopenharmony_ci#include <netinet/in.h>
20c87c5fbaSopenharmony_ci#include <arpa/inet.h>
21c87c5fbaSopenharmony_ci#include <netdb.h>
22c87c5fbaSopenharmony_ci#include <sys/stat.h>
23c87c5fbaSopenharmony_ci#include <dirent.h>
24c87c5fbaSopenharmony_ci#include <errno.h>
25c87c5fbaSopenharmony_ci#include <signal.h>
26c87c5fbaSopenharmony_ci
27c87c5fbaSopenharmony_ci#include <coap3/coap.h>
28c87c5fbaSopenharmony_ci
29c87c5fbaSopenharmony_ci#define COAP_RESOURCE_CHECK_TIME_SEC  1
30c87c5fbaSopenharmony_ci
31c87c5fbaSopenharmony_ci#ifndef min
32c87c5fbaSopenharmony_ci#define min(a,b) ((a) < (b) ? (a) : (b))
33c87c5fbaSopenharmony_ci#endif
34c87c5fbaSopenharmony_ci
35c87c5fbaSopenharmony_ci/* temporary storage for dynamic resource representations */
36c87c5fbaSopenharmony_cistatic int quit = 0;
37c87c5fbaSopenharmony_ci
38c87c5fbaSopenharmony_ci#define COAP_OPT_BLOCK_SZX_MAX 6 /**< allowed maximum for block szx value */
39c87c5fbaSopenharmony_ci
40c87c5fbaSopenharmony_ci#define REQUIRE_ETAG 0x01         /* flag for coap_payload_t: require ETag option  */
41c87c5fbaSopenharmony_citypedef struct {
42c87c5fbaSopenharmony_ci  unsigned int flags;             /* some flags to control behavior */
43c87c5fbaSopenharmony_ci  size_t max_data;                /* maximum size allocated for @p data */
44c87c5fbaSopenharmony_ci  uint16_t media_type;            /* media type for this object */
45c87c5fbaSopenharmony_ci  size_t length;                  /* length of data */
46c87c5fbaSopenharmony_ci  unsigned char data[];           /* the actual contents */
47c87c5fbaSopenharmony_ci} coap_payload_t;
48c87c5fbaSopenharmony_ci
49c87c5fbaSopenharmony_ci/* SIGINT handler: set quit to 1 for graceful termination */
50c87c5fbaSopenharmony_cistatic void
51c87c5fbaSopenharmony_cihandle_sigint(int signum COAP_UNUSED) {
52c87c5fbaSopenharmony_ci  quit = 1;
53c87c5fbaSopenharmony_ci}
54c87c5fbaSopenharmony_ci
55c87c5fbaSopenharmony_ci#define INDEX "libcoap server for ETSI CoAP Plugtest, March 2012, Paris\n" \
56c87c5fbaSopenharmony_ci  "Copyright (C) 2012 Olaf Bergmann <bergmann@tzi.org>\n\n"
57c87c5fbaSopenharmony_ci
58c87c5fbaSopenharmony_cistatic coap_payload_t *
59c87c5fbaSopenharmony_cicoap_new_payload(size_t size) {
60c87c5fbaSopenharmony_ci  coap_payload_t *p;
61c87c5fbaSopenharmony_ci  p = (coap_payload_t *)coap_malloc(sizeof(coap_payload_t) + size);
62c87c5fbaSopenharmony_ci  if (p) {
63c87c5fbaSopenharmony_ci    memset(p, 0, sizeof(coap_payload_t));
64c87c5fbaSopenharmony_ci    p->max_data = size;
65c87c5fbaSopenharmony_ci  }
66c87c5fbaSopenharmony_ci
67c87c5fbaSopenharmony_ci  return p;
68c87c5fbaSopenharmony_ci}
69c87c5fbaSopenharmony_ci
70c87c5fbaSopenharmony_cistatic inline coap_payload_t *
71c87c5fbaSopenharmony_cicoap_find_payload(coap_resource_t *resource) {
72c87c5fbaSopenharmony_ci  return coap_resource_get_userdata(resource);
73c87c5fbaSopenharmony_ci}
74c87c5fbaSopenharmony_ci
75c87c5fbaSopenharmony_cistatic void
76c87c5fbaSopenharmony_cicoap_add_payload(coap_resource_t *resource, coap_payload_t *payload) {
77c87c5fbaSopenharmony_ci  assert(payload);
78c87c5fbaSopenharmony_ci
79c87c5fbaSopenharmony_ci  coap_resource_set_userdata(resource, payload);
80c87c5fbaSopenharmony_ci}
81c87c5fbaSopenharmony_ci
82c87c5fbaSopenharmony_cistatic inline void
83c87c5fbaSopenharmony_cicoap_delete_payload(coap_resource_t *resource) {
84c87c5fbaSopenharmony_ci  coap_free(coap_resource_get_userdata(resource));
85c87c5fbaSopenharmony_ci  coap_resource_set_userdata(resource, NULL);
86c87c5fbaSopenharmony_ci}
87c87c5fbaSopenharmony_ci
88c87c5fbaSopenharmony_cistatic void
89c87c5fbaSopenharmony_cicoap_free_userdata(void *data) {
90c87c5fbaSopenharmony_ci  coap_free(data);
91c87c5fbaSopenharmony_ci}
92c87c5fbaSopenharmony_ci
93c87c5fbaSopenharmony_ci#if 0
94c87c5fbaSopenharmony_cistatic void
95c87c5fbaSopenharmony_cihnd_get_index(coap_resource_t *resource COAP_UNUSED,
96c87c5fbaSopenharmony_ci              coap_session_t *session COAP_UNUSED,
97c87c5fbaSopenharmony_ci              coap_pdu_t *request COAP_UNUSED,
98c87c5fbaSopenharmony_ci              coap_string_t *query COAP_UNUSED,
99c87c5fbaSopenharmony_ci              coap_pdu_t *response) {
100c87c5fbaSopenharmony_ci  unsigned char buf[3];
101c87c5fbaSopenharmony_ci
102c87c5fbaSopenharmony_ci  coap_pdu_set_code(response, COAP_RESPONSE_CODE_CONTENT);
103c87c5fbaSopenharmony_ci
104c87c5fbaSopenharmony_ci  coap_add_option(response, COAP_OPTION_CONTENT_TYPE,
105c87c5fbaSopenharmony_ci                  coap_encode_var_safe(buf, sizeof(buf),
106c87c5fbaSopenharmony_ci                                       COAP_MEDIATYPE_TEXT_PLAIN),
107c87c5fbaSopenharmony_ci                  buf);
108c87c5fbaSopenharmony_ci
109c87c5fbaSopenharmony_ci  coap_add_option(response, COAP_OPTION_MAXAGE,
110c87c5fbaSopenharmony_ci                  coap_encode_var_safe(buf, sizeof(buf), 0x2ffff), buf);
111c87c5fbaSopenharmony_ci
112c87c5fbaSopenharmony_ci  coap_add_data(response, strlen(INDEX), (const uint8_t *)INDEX);
113c87c5fbaSopenharmony_ci}
114c87c5fbaSopenharmony_ci#endif
115c87c5fbaSopenharmony_ci
116c87c5fbaSopenharmony_cistatic void
117c87c5fbaSopenharmony_cihnd_get_resource(coap_resource_t *resource,
118c87c5fbaSopenharmony_ci                 coap_session_t *session COAP_UNUSED,
119c87c5fbaSopenharmony_ci                 const coap_pdu_t *request,
120c87c5fbaSopenharmony_ci                 const coap_string_t *query COAP_UNUSED,
121c87c5fbaSopenharmony_ci                 coap_pdu_t *response) {
122c87c5fbaSopenharmony_ci  coap_payload_t *test_payload;
123c87c5fbaSopenharmony_ci
124c87c5fbaSopenharmony_ci  test_payload = coap_find_payload(resource);
125c87c5fbaSopenharmony_ci  if (!test_payload) {
126c87c5fbaSopenharmony_ci    coap_pdu_set_code(response, COAP_RESPONSE_CODE_INTERNAL_ERROR);
127c87c5fbaSopenharmony_ci
128c87c5fbaSopenharmony_ci    return;
129c87c5fbaSopenharmony_ci  }
130c87c5fbaSopenharmony_ci
131c87c5fbaSopenharmony_ci  coap_pdu_set_code(response, COAP_RESPONSE_CODE_CONTENT);
132c87c5fbaSopenharmony_ci
133c87c5fbaSopenharmony_ci  coap_add_data_blocked_response(request, response,
134c87c5fbaSopenharmony_ci                                 test_payload->media_type, -1,
135c87c5fbaSopenharmony_ci                                 test_payload->length,
136c87c5fbaSopenharmony_ci                                 test_payload->data);
137c87c5fbaSopenharmony_ci  return;
138c87c5fbaSopenharmony_ci}
139c87c5fbaSopenharmony_ci
140c87c5fbaSopenharmony_ci/* DELETE handler for dynamic resources created by POST /test */
141c87c5fbaSopenharmony_cistatic void
142c87c5fbaSopenharmony_cihnd_delete_resource(coap_resource_t *resource,
143c87c5fbaSopenharmony_ci                    coap_session_t *session COAP_UNUSED,
144c87c5fbaSopenharmony_ci                    const coap_pdu_t *request COAP_UNUSED,
145c87c5fbaSopenharmony_ci                    const coap_string_t *query COAP_UNUSED,
146c87c5fbaSopenharmony_ci                    coap_pdu_t *response) {
147c87c5fbaSopenharmony_ci  coap_payload_t *payload;
148c87c5fbaSopenharmony_ci
149c87c5fbaSopenharmony_ci  payload = coap_find_payload(resource);
150c87c5fbaSopenharmony_ci
151c87c5fbaSopenharmony_ci  if (payload)
152c87c5fbaSopenharmony_ci    coap_delete_payload(resource);
153c87c5fbaSopenharmony_ci
154c87c5fbaSopenharmony_ci  coap_delete_resource(NULL, resource);
155c87c5fbaSopenharmony_ci
156c87c5fbaSopenharmony_ci  coap_pdu_set_code(response, COAP_RESPONSE_CODE_DELETED);
157c87c5fbaSopenharmony_ci}
158c87c5fbaSopenharmony_ci
159c87c5fbaSopenharmony_cistatic void
160c87c5fbaSopenharmony_cihnd_post_test(coap_resource_t *resource COAP_UNUSED,
161c87c5fbaSopenharmony_ci              coap_session_t *session COAP_UNUSED,
162c87c5fbaSopenharmony_ci              const coap_pdu_t *request,
163c87c5fbaSopenharmony_ci              const coap_string_t *query COAP_UNUSED,
164c87c5fbaSopenharmony_ci              coap_pdu_t *response) {
165c87c5fbaSopenharmony_ci  coap_opt_iterator_t opt_iter;
166c87c5fbaSopenharmony_ci  coap_opt_t *option;
167c87c5fbaSopenharmony_ci  coap_payload_t *test_payload;
168c87c5fbaSopenharmony_ci  size_t len;
169c87c5fbaSopenharmony_ci  coap_str_const_t *uri;
170c87c5fbaSopenharmony_ci  const uint8_t *data;
171c87c5fbaSopenharmony_ci
172c87c5fbaSopenharmony_ci#define BUFSIZE 20
173c87c5fbaSopenharmony_ci  int res;
174c87c5fbaSopenharmony_ci  unsigned char _buf[BUFSIZE];
175c87c5fbaSopenharmony_ci  unsigned char *buf = _buf;
176c87c5fbaSopenharmony_ci  size_t buflen = BUFSIZE;
177c87c5fbaSopenharmony_ci
178c87c5fbaSopenharmony_ci  coap_get_data(request, &len, &data);
179c87c5fbaSopenharmony_ci
180c87c5fbaSopenharmony_ci  /* allocate storage for resource and to hold URI */
181c87c5fbaSopenharmony_ci  test_payload = coap_new_payload(len);
182c87c5fbaSopenharmony_ci  snprintf((char *)buf, buflen, "test/%p", (void *)test_payload);
183c87c5fbaSopenharmony_ci  uri = coap_new_str_const(buf, strlen((char *)buf));
184c87c5fbaSopenharmony_ci  if (!(test_payload && uri)) {
185c87c5fbaSopenharmony_ci    coap_log_crit("cannot allocate new resource under /test");
186c87c5fbaSopenharmony_ci    coap_pdu_set_code(response, COAP_RESPONSE_CODE_INTERNAL_ERROR);
187c87c5fbaSopenharmony_ci    coap_free(test_payload);
188c87c5fbaSopenharmony_ci    coap_free(uri);
189c87c5fbaSopenharmony_ci  } else {
190c87c5fbaSopenharmony_ci    coap_resource_t *r;
191c87c5fbaSopenharmony_ci
192c87c5fbaSopenharmony_ci    test_payload->length = len;
193c87c5fbaSopenharmony_ci
194c87c5fbaSopenharmony_ci    memcpy(test_payload->data, data, len);
195c87c5fbaSopenharmony_ci
196c87c5fbaSopenharmony_ci    r = coap_resource_init(uri, COAP_RESOURCE_FLAGS_RELEASE_URI);
197c87c5fbaSopenharmony_ci    coap_register_request_handler(r, COAP_REQUEST_GET, hnd_get_resource);
198c87c5fbaSopenharmony_ci    coap_register_request_handler(r, COAP_REQUEST_DELETE, hnd_delete_resource);
199c87c5fbaSopenharmony_ci
200c87c5fbaSopenharmony_ci    /* set media_type if available */
201c87c5fbaSopenharmony_ci    option = coap_check_option(request, COAP_OPTION_CONTENT_TYPE, &opt_iter);
202c87c5fbaSopenharmony_ci    if (option) {
203c87c5fbaSopenharmony_ci      test_payload->media_type =
204c87c5fbaSopenharmony_ci          coap_decode_var_bytes(coap_opt_value(option), coap_opt_length(option));
205c87c5fbaSopenharmony_ci    }
206c87c5fbaSopenharmony_ci
207c87c5fbaSopenharmony_ci    coap_add_resource(coap_session_get_context(session), r);
208c87c5fbaSopenharmony_ci    coap_add_payload(r, test_payload);
209c87c5fbaSopenharmony_ci
210c87c5fbaSopenharmony_ci    /* add Location-Path */
211c87c5fbaSopenharmony_ci    res = coap_split_path(uri->s, uri->length, buf, &buflen);
212c87c5fbaSopenharmony_ci
213c87c5fbaSopenharmony_ci    while (res--) {
214c87c5fbaSopenharmony_ci      coap_add_option(response, COAP_OPTION_LOCATION_PATH,
215c87c5fbaSopenharmony_ci                      coap_opt_length(buf), coap_opt_value(buf));
216c87c5fbaSopenharmony_ci
217c87c5fbaSopenharmony_ci      buf += coap_opt_size(buf);
218c87c5fbaSopenharmony_ci    }
219c87c5fbaSopenharmony_ci
220c87c5fbaSopenharmony_ci    coap_pdu_set_code(response, COAP_RESPONSE_CODE_CREATED);
221c87c5fbaSopenharmony_ci  }
222c87c5fbaSopenharmony_ci
223c87c5fbaSopenharmony_ci}
224c87c5fbaSopenharmony_ci
225c87c5fbaSopenharmony_cistatic void
226c87c5fbaSopenharmony_cihnd_put_test(coap_resource_t *resource,
227c87c5fbaSopenharmony_ci             coap_session_t *session COAP_UNUSED,
228c87c5fbaSopenharmony_ci             const coap_pdu_t *request,
229c87c5fbaSopenharmony_ci             const coap_string_t *query COAP_UNUSED,
230c87c5fbaSopenharmony_ci             coap_pdu_t *response) {
231c87c5fbaSopenharmony_ci  coap_opt_iterator_t opt_iter;
232c87c5fbaSopenharmony_ci  coap_opt_t *option;
233c87c5fbaSopenharmony_ci  coap_payload_t *payload;
234c87c5fbaSopenharmony_ci  size_t len;
235c87c5fbaSopenharmony_ci  const uint8_t *data;
236c87c5fbaSopenharmony_ci
237c87c5fbaSopenharmony_ci  coap_pdu_set_code(response, COAP_RESPONSE_CODE_CHANGED);
238c87c5fbaSopenharmony_ci
239c87c5fbaSopenharmony_ci  coap_get_data(request, &len, &data);
240c87c5fbaSopenharmony_ci
241c87c5fbaSopenharmony_ci  payload = coap_find_payload(resource);
242c87c5fbaSopenharmony_ci  if (payload && payload->max_data < len) { /* need more storage */
243c87c5fbaSopenharmony_ci    coap_delete_payload(resource);
244c87c5fbaSopenharmony_ci    payload = NULL;
245c87c5fbaSopenharmony_ci    /* bug: when subsequent coap_new_payload() fails, our old contents
246c87c5fbaSopenharmony_ci       is gone */
247c87c5fbaSopenharmony_ci  }
248c87c5fbaSopenharmony_ci
249c87c5fbaSopenharmony_ci  if (!payload) {                /* create new payload */
250c87c5fbaSopenharmony_ci    payload = coap_new_payload(len);
251c87c5fbaSopenharmony_ci    if (!payload)
252c87c5fbaSopenharmony_ci      goto error;
253c87c5fbaSopenharmony_ci
254c87c5fbaSopenharmony_ci    coap_add_payload(resource, payload);
255c87c5fbaSopenharmony_ci  }
256c87c5fbaSopenharmony_ci  payload->length = len;
257c87c5fbaSopenharmony_ci  memcpy(payload->data, data, len);
258c87c5fbaSopenharmony_ci
259c87c5fbaSopenharmony_ci  option = coap_check_option(request, COAP_OPTION_CONTENT_TYPE, &opt_iter);
260c87c5fbaSopenharmony_ci  if (option) {
261c87c5fbaSopenharmony_ci    /* set media type given in request */
262c87c5fbaSopenharmony_ci    payload->media_type =
263c87c5fbaSopenharmony_ci        coap_decode_var_bytes(coap_opt_value(option), coap_opt_length(option));
264c87c5fbaSopenharmony_ci  } else {
265c87c5fbaSopenharmony_ci    /* set default value */
266c87c5fbaSopenharmony_ci    payload->media_type = COAP_MEDIATYPE_TEXT_PLAIN;
267c87c5fbaSopenharmony_ci  }
268c87c5fbaSopenharmony_ci  /* FIXME: need to change attribute ct of resource.
269c87c5fbaSopenharmony_ci     To do so, we need dynamic management of the attribute value
270c87c5fbaSopenharmony_ci  */
271c87c5fbaSopenharmony_ci
272c87c5fbaSopenharmony_ci  return;
273c87c5fbaSopenharmony_cierror:
274c87c5fbaSopenharmony_ci  coap_log_warn("cannot modify resource\n");
275c87c5fbaSopenharmony_ci  coap_pdu_set_code(response, COAP_RESPONSE_CODE_INTERNAL_ERROR);
276c87c5fbaSopenharmony_ci}
277c87c5fbaSopenharmony_ci
278c87c5fbaSopenharmony_cistatic void
279c87c5fbaSopenharmony_cihnd_delete_test(coap_resource_t *resource COAP_UNUSED,
280c87c5fbaSopenharmony_ci                coap_session_t *session COAP_UNUSED,
281c87c5fbaSopenharmony_ci                const coap_pdu_t *request COAP_UNUSED,
282c87c5fbaSopenharmony_ci                const coap_string_t *query COAP_UNUSED,
283c87c5fbaSopenharmony_ci                coap_pdu_t *response) {
284c87c5fbaSopenharmony_ci  /* the ETSI validation tool does not like empty resources... */
285c87c5fbaSopenharmony_ci#if 0
286c87c5fbaSopenharmony_ci  coap_payload_t *payload;
287c87c5fbaSopenharmony_ci  payload = coap_find_payload(resource);
288c87c5fbaSopenharmony_ci
289c87c5fbaSopenharmony_ci  if (payload)
290c87c5fbaSopenharmony_ci    payload->length = 0;
291c87c5fbaSopenharmony_ci#endif
292c87c5fbaSopenharmony_ci
293c87c5fbaSopenharmony_ci  coap_pdu_set_code(response, COAP_RESPONSE_CODE_DELETED);
294c87c5fbaSopenharmony_ci}
295c87c5fbaSopenharmony_ci
296c87c5fbaSopenharmony_cistatic void
297c87c5fbaSopenharmony_cihnd_get_query(coap_resource_t *resource COAP_UNUSED,
298c87c5fbaSopenharmony_ci              coap_session_t *session COAP_UNUSED,
299c87c5fbaSopenharmony_ci              const coap_pdu_t *request,
300c87c5fbaSopenharmony_ci              const coap_string_t *query COAP_UNUSED,
301c87c5fbaSopenharmony_ci              coap_pdu_t *response) {
302c87c5fbaSopenharmony_ci  coap_opt_iterator_t opt_iter;
303c87c5fbaSopenharmony_ci  coap_opt_filter_t f;
304c87c5fbaSopenharmony_ci  coap_opt_t *q;
305c87c5fbaSopenharmony_ci  size_t len, L;
306c87c5fbaSopenharmony_ci  unsigned char buf[70];
307c87c5fbaSopenharmony_ci
308c87c5fbaSopenharmony_ci  coap_pdu_set_code(response, COAP_RESPONSE_CODE_CONTENT);
309c87c5fbaSopenharmony_ci
310c87c5fbaSopenharmony_ci  coap_add_option(response, COAP_OPTION_CONTENT_TYPE,
311c87c5fbaSopenharmony_ci                  coap_encode_var_safe(buf, sizeof(buf),
312c87c5fbaSopenharmony_ci                                       COAP_MEDIATYPE_TEXT_PLAIN),
313c87c5fbaSopenharmony_ci                  buf);
314c87c5fbaSopenharmony_ci
315c87c5fbaSopenharmony_ci  coap_option_filter_clear(&f);
316c87c5fbaSopenharmony_ci  coap_option_filter_set(&f, COAP_OPTION_URI_QUERY);
317c87c5fbaSopenharmony_ci
318c87c5fbaSopenharmony_ci  coap_option_iterator_init(request, &opt_iter, &f);
319c87c5fbaSopenharmony_ci
320c87c5fbaSopenharmony_ci  len = 0;
321c87c5fbaSopenharmony_ci  while ((len < sizeof(buf)) && (q = coap_option_next(&opt_iter))) {
322c87c5fbaSopenharmony_ci    L = min(sizeof(buf) - len, 11);
323c87c5fbaSopenharmony_ci    memcpy(buf + len, "Uri-Query: ", L);
324c87c5fbaSopenharmony_ci    len += L;
325c87c5fbaSopenharmony_ci
326c87c5fbaSopenharmony_ci    L = min(sizeof(buf) - len, coap_opt_length(q));
327c87c5fbaSopenharmony_ci    memcpy(buf + len, coap_opt_value(q), L);
328c87c5fbaSopenharmony_ci    len += L;
329c87c5fbaSopenharmony_ci
330c87c5fbaSopenharmony_ci    if (len < sizeof(buf))
331c87c5fbaSopenharmony_ci      buf[len++] = '\n';
332c87c5fbaSopenharmony_ci  }
333c87c5fbaSopenharmony_ci
334c87c5fbaSopenharmony_ci  coap_add_data(response, len, buf);
335c87c5fbaSopenharmony_ci}
336c87c5fbaSopenharmony_ci
337c87c5fbaSopenharmony_ci/* handler for TD_COAP_CORE_16 */
338c87c5fbaSopenharmony_cistatic void
339c87c5fbaSopenharmony_cihnd_get_separate(coap_resource_t *resource COAP_UNUSED,
340c87c5fbaSopenharmony_ci                 coap_session_t *session,
341c87c5fbaSopenharmony_ci                 const coap_pdu_t *request,
342c87c5fbaSopenharmony_ci                 const coap_string_t *query COAP_UNUSED,
343c87c5fbaSopenharmony_ci                 coap_pdu_t *response) {
344c87c5fbaSopenharmony_ci  coap_opt_iterator_t opt_iter;
345c87c5fbaSopenharmony_ci  coap_opt_t *option;
346c87c5fbaSopenharmony_ci  coap_opt_filter_t f;
347c87c5fbaSopenharmony_ci  unsigned long delay = 5;
348c87c5fbaSopenharmony_ci
349c87c5fbaSopenharmony_ci  if (request) {
350c87c5fbaSopenharmony_ci    coap_async_t *async;
351c87c5fbaSopenharmony_ci    coap_bin_const_t token = coap_pdu_get_token(request);
352c87c5fbaSopenharmony_ci
353c87c5fbaSopenharmony_ci    async = coap_find_async(session, token);
354c87c5fbaSopenharmony_ci
355c87c5fbaSopenharmony_ci    if (!async) {
356c87c5fbaSopenharmony_ci      /* Set up an async request to trigger delay in the future */
357c87c5fbaSopenharmony_ci
358c87c5fbaSopenharmony_ci      /* search for option delay in query list */
359c87c5fbaSopenharmony_ci      coap_option_filter_clear(&f);
360c87c5fbaSopenharmony_ci      coap_option_filter_set(&f, COAP_OPTION_URI_QUERY);
361c87c5fbaSopenharmony_ci
362c87c5fbaSopenharmony_ci      coap_option_iterator_init(request, &opt_iter, &f);
363c87c5fbaSopenharmony_ci
364c87c5fbaSopenharmony_ci      while ((option = coap_option_next(&opt_iter))) {
365c87c5fbaSopenharmony_ci        if (strncmp("delay=", (const char *)coap_opt_value(option), 6) == 0) {
366c87c5fbaSopenharmony_ci          unsigned int i;
367c87c5fbaSopenharmony_ci          unsigned long d = 0;
368c87c5fbaSopenharmony_ci
369c87c5fbaSopenharmony_ci          for (i = 6; i < coap_opt_length(option); ++i)
370c87c5fbaSopenharmony_ci            d = d * 10 + coap_opt_value(option)[i] - '0';
371c87c5fbaSopenharmony_ci
372c87c5fbaSopenharmony_ci          /* don't allow delay to be less than COAP_RESOURCE_CHECK_TIME*/
373c87c5fbaSopenharmony_ci          delay = d < COAP_RESOURCE_CHECK_TIME_SEC
374c87c5fbaSopenharmony_ci                  ? COAP_RESOURCE_CHECK_TIME_SEC
375c87c5fbaSopenharmony_ci                  : d;
376c87c5fbaSopenharmony_ci          coap_log_debug("set delay to %lu\n", delay);
377c87c5fbaSopenharmony_ci          break;
378c87c5fbaSopenharmony_ci        }
379c87c5fbaSopenharmony_ci      }
380c87c5fbaSopenharmony_ci      async = coap_register_async(session,
381c87c5fbaSopenharmony_ci                                  request,
382c87c5fbaSopenharmony_ci                                  COAP_TICKS_PER_SECOND * delay);
383c87c5fbaSopenharmony_ci      if (async == NULL) {
384c87c5fbaSopenharmony_ci        coap_pdu_set_code(response, COAP_RESPONSE_CODE_SERVICE_UNAVAILABLE);
385c87c5fbaSopenharmony_ci        return;
386c87c5fbaSopenharmony_ci      }
387c87c5fbaSopenharmony_ci      /* Not setting response code will cause empty ACK to be sent
388c87c5fbaSopenharmony_ci         if Confirmable */
389c87c5fbaSopenharmony_ci      return;
390c87c5fbaSopenharmony_ci    }
391c87c5fbaSopenharmony_ci  }
392c87c5fbaSopenharmony_ci
393c87c5fbaSopenharmony_ci  /* no request (observe) or async set up, so this is the delayed request */
394c87c5fbaSopenharmony_ci  coap_add_data(response, 4, (const uint8_t *)"done");
395c87c5fbaSopenharmony_ci  coap_pdu_set_code(response, COAP_RESPONSE_CODE_CONTENT);
396c87c5fbaSopenharmony_ci
397c87c5fbaSopenharmony_ci  /* async is automatically removed by libcoap */
398c87c5fbaSopenharmony_ci}
399c87c5fbaSopenharmony_ci
400c87c5fbaSopenharmony_cistatic coap_payload_t *
401c87c5fbaSopenharmony_cimake_large(const char *filename) {
402c87c5fbaSopenharmony_ci  coap_payload_t *payload;
403c87c5fbaSopenharmony_ci  FILE *inputfile = NULL;
404c87c5fbaSopenharmony_ci  struct stat statbuf;
405c87c5fbaSopenharmony_ci
406c87c5fbaSopenharmony_ci  if (!filename)
407c87c5fbaSopenharmony_ci    return NULL;
408c87c5fbaSopenharmony_ci
409c87c5fbaSopenharmony_ci  /* read from specified input file */
410c87c5fbaSopenharmony_ci  if (stat(filename, &statbuf) < 0) {
411c87c5fbaSopenharmony_ci    coap_log_warn("cannot stat file %s\n", filename);
412c87c5fbaSopenharmony_ci    return NULL;
413c87c5fbaSopenharmony_ci  }
414c87c5fbaSopenharmony_ci
415c87c5fbaSopenharmony_ci  payload = coap_new_payload(statbuf.st_size);
416c87c5fbaSopenharmony_ci  if (!payload)
417c87c5fbaSopenharmony_ci    return NULL;
418c87c5fbaSopenharmony_ci
419c87c5fbaSopenharmony_ci  inputfile = fopen(filename, "r");
420c87c5fbaSopenharmony_ci  if (!inputfile) {
421c87c5fbaSopenharmony_ci    coap_log_warn("cannot read file %s\n", filename);
422c87c5fbaSopenharmony_ci    coap_free(payload);
423c87c5fbaSopenharmony_ci    return NULL;
424c87c5fbaSopenharmony_ci  }
425c87c5fbaSopenharmony_ci
426c87c5fbaSopenharmony_ci  payload->length = fread(payload->data, 1, statbuf.st_size, inputfile);
427c87c5fbaSopenharmony_ci  payload->media_type = 41;
428c87c5fbaSopenharmony_ci
429c87c5fbaSopenharmony_ci  fclose(inputfile);
430c87c5fbaSopenharmony_ci
431c87c5fbaSopenharmony_ci  return payload;
432c87c5fbaSopenharmony_ci}
433c87c5fbaSopenharmony_ci
434c87c5fbaSopenharmony_cistatic void
435c87c5fbaSopenharmony_ciinit_resources(coap_context_t *ctx) {
436c87c5fbaSopenharmony_ci  coap_resource_t *r;
437c87c5fbaSopenharmony_ci  coap_payload_t *test_payload;
438c87c5fbaSopenharmony_ci
439c87c5fbaSopenharmony_ci  test_payload = coap_new_payload(200);
440c87c5fbaSopenharmony_ci  if (!test_payload) {
441c87c5fbaSopenharmony_ci    coap_log_crit("cannot allocate resource /test");
442c87c5fbaSopenharmony_ci  } else {
443c87c5fbaSopenharmony_ci    test_payload->length = 13;
444c87c5fbaSopenharmony_ci    memcpy(test_payload->data, "put data here", test_payload->length);
445c87c5fbaSopenharmony_ci    /* test_payload->media_type is 0 anyway */
446c87c5fbaSopenharmony_ci
447c87c5fbaSopenharmony_ci    r = coap_resource_init(coap_make_str_const("test"), 0);
448c87c5fbaSopenharmony_ci    coap_register_request_handler(r, COAP_REQUEST_GET, hnd_get_resource);
449c87c5fbaSopenharmony_ci    coap_register_request_handler(r, COAP_REQUEST_POST, hnd_post_test);
450c87c5fbaSopenharmony_ci    coap_register_request_handler(r, COAP_REQUEST_PUT, hnd_put_test);
451c87c5fbaSopenharmony_ci    coap_register_request_handler(r, COAP_REQUEST_DELETE, hnd_delete_test);
452c87c5fbaSopenharmony_ci
453c87c5fbaSopenharmony_ci    coap_add_attr(r, coap_make_str_const("ct"), coap_make_str_const("0"), 0);
454c87c5fbaSopenharmony_ci    coap_add_attr(r, coap_make_str_const("rt"), coap_make_str_const("test"), 0);
455c87c5fbaSopenharmony_ci    coap_add_attr(r, coap_make_str_const("if"), coap_make_str_const("core#b"), 0);
456c87c5fbaSopenharmony_ci#if 0
457c87c5fbaSopenharmony_ci    coap_add_attr(r, coap_make_str_const("obs"), NULL, 0);
458c87c5fbaSopenharmony_ci#endif
459c87c5fbaSopenharmony_ci    coap_add_resource(ctx, r);
460c87c5fbaSopenharmony_ci    coap_resource_release_userdata_handler(ctx, coap_free_userdata);
461c87c5fbaSopenharmony_ci    coap_add_payload(r, test_payload);
462c87c5fbaSopenharmony_ci  }
463c87c5fbaSopenharmony_ci
464c87c5fbaSopenharmony_ci  /* TD_COAP_BLOCK_01
465c87c5fbaSopenharmony_ci   * TD_COAP_BLOCK_02 */
466c87c5fbaSopenharmony_ci  test_payload = make_large("etsi_iot_01_largedata.txt");
467c87c5fbaSopenharmony_ci  if (!test_payload) {
468c87c5fbaSopenharmony_ci    coap_log_crit("cannot allocate resource /large\n");
469c87c5fbaSopenharmony_ci  } else {
470c87c5fbaSopenharmony_ci    r = coap_resource_init(coap_make_str_const("large"), 0);
471c87c5fbaSopenharmony_ci    coap_register_request_handler(r, COAP_REQUEST_GET, hnd_get_resource);
472c87c5fbaSopenharmony_ci
473c87c5fbaSopenharmony_ci    coap_add_attr(r, coap_make_str_const("ct"), coap_make_str_const("41"), 0);
474c87c5fbaSopenharmony_ci    coap_add_attr(r, coap_make_str_const("rt"), coap_make_str_const("large"), 0);
475c87c5fbaSopenharmony_ci    coap_add_resource(ctx, r);
476c87c5fbaSopenharmony_ci
477c87c5fbaSopenharmony_ci    test_payload->flags |= REQUIRE_ETAG;
478c87c5fbaSopenharmony_ci
479c87c5fbaSopenharmony_ci    coap_add_payload(r, test_payload);
480c87c5fbaSopenharmony_ci  }
481c87c5fbaSopenharmony_ci
482c87c5fbaSopenharmony_ci  /* For TD_COAP_CORE_12 */
483c87c5fbaSopenharmony_ci  test_payload = coap_new_payload(20);
484c87c5fbaSopenharmony_ci  if (!test_payload) {
485c87c5fbaSopenharmony_ci    coap_log_crit("cannot allocate resource /seg1/seg2/seg3\n");
486c87c5fbaSopenharmony_ci  } else {
487c87c5fbaSopenharmony_ci    test_payload->length = 10;
488c87c5fbaSopenharmony_ci    memcpy(test_payload->data, "segsegseg!", test_payload->length);
489c87c5fbaSopenharmony_ci    /* test_payload->media_type is 0 anyway */
490c87c5fbaSopenharmony_ci
491c87c5fbaSopenharmony_ci    r = coap_resource_init(coap_make_str_const("seg1/seg2/seg3"), 0);
492c87c5fbaSopenharmony_ci    coap_register_request_handler(r, COAP_REQUEST_GET, hnd_get_resource);
493c87c5fbaSopenharmony_ci
494c87c5fbaSopenharmony_ci    coap_add_attr(r, coap_make_str_const("ct"), coap_make_str_const("0"), 0);
495c87c5fbaSopenharmony_ci    coap_add_resource(ctx, r);
496c87c5fbaSopenharmony_ci
497c87c5fbaSopenharmony_ci    coap_add_payload(r, test_payload);
498c87c5fbaSopenharmony_ci  }
499c87c5fbaSopenharmony_ci
500c87c5fbaSopenharmony_ci  /* For TD_COAP_CORE_13 */
501c87c5fbaSopenharmony_ci  r = coap_resource_init(coap_make_str_const("query"), 0);
502c87c5fbaSopenharmony_ci  coap_register_request_handler(r, COAP_REQUEST_GET, hnd_get_query);
503c87c5fbaSopenharmony_ci
504c87c5fbaSopenharmony_ci  coap_add_attr(r, coap_make_str_const("ct"), coap_make_str_const("0"), 0);
505c87c5fbaSopenharmony_ci  coap_add_resource(ctx, r);
506c87c5fbaSopenharmony_ci
507c87c5fbaSopenharmony_ci  /* For TD_COAP_CORE_16 */
508c87c5fbaSopenharmony_ci  r = coap_resource_init(coap_make_str_const("separate"), 0);
509c87c5fbaSopenharmony_ci  coap_register_request_handler(r, COAP_REQUEST_GET, hnd_get_separate);
510c87c5fbaSopenharmony_ci
511c87c5fbaSopenharmony_ci  coap_add_attr(r, coap_make_str_const("ct"), coap_make_str_const("0"), 0);
512c87c5fbaSopenharmony_ci  coap_add_attr(r, coap_make_str_const("rt"), coap_make_str_const("seperate"), 0);
513c87c5fbaSopenharmony_ci  coap_add_resource(ctx, r);
514c87c5fbaSopenharmony_ci}
515c87c5fbaSopenharmony_ci
516c87c5fbaSopenharmony_cistatic void
517c87c5fbaSopenharmony_ciusage(const char *program, const char *version) {
518c87c5fbaSopenharmony_ci  const char *p;
519c87c5fbaSopenharmony_ci
520c87c5fbaSopenharmony_ci  p = strrchr(program, '/');
521c87c5fbaSopenharmony_ci  if (p)
522c87c5fbaSopenharmony_ci    program = ++p;
523c87c5fbaSopenharmony_ci
524c87c5fbaSopenharmony_ci  fprintf(stderr, "%s v%s -- ETSI CoAP plugtest server\n"
525c87c5fbaSopenharmony_ci          "(c) 2012 Olaf Bergmann <bergmann@tzi.org>\n\n"
526c87c5fbaSopenharmony_ci          "usage: %s [-A address] [-p port]\n\n"
527c87c5fbaSopenharmony_ci          "\t-A address\tinterface address to bind to\n"
528c87c5fbaSopenharmony_ci          "\t-p port\t\tlisten on specified port\n"
529c87c5fbaSopenharmony_ci          "\t-v num\t\tverbosity level (default: 3)\n",
530c87c5fbaSopenharmony_ci          program, version, program);
531c87c5fbaSopenharmony_ci}
532c87c5fbaSopenharmony_ci
533c87c5fbaSopenharmony_cistatic coap_context_t *
534c87c5fbaSopenharmony_ciget_context(const char *node, const char *port) {
535c87c5fbaSopenharmony_ci  coap_context_t *ctx = NULL;
536c87c5fbaSopenharmony_ci  int s;
537c87c5fbaSopenharmony_ci  struct addrinfo hints;
538c87c5fbaSopenharmony_ci  struct addrinfo *result, *rp;
539c87c5fbaSopenharmony_ci
540c87c5fbaSopenharmony_ci  memset(&hints, 0, sizeof(struct addrinfo));
541c87c5fbaSopenharmony_ci  hints.ai_family = AF_UNSPEC;    /* Allow IPv4 or IPv6 */
542c87c5fbaSopenharmony_ci  hints.ai_socktype = SOCK_DGRAM; /* Coap uses UDP */
543c87c5fbaSopenharmony_ci  hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST;
544c87c5fbaSopenharmony_ci
545c87c5fbaSopenharmony_ci  s = getaddrinfo(node, port, &hints, &result);
546c87c5fbaSopenharmony_ci  if (s != 0) {
547c87c5fbaSopenharmony_ci    fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(s));
548c87c5fbaSopenharmony_ci    return NULL;
549c87c5fbaSopenharmony_ci  }
550c87c5fbaSopenharmony_ci
551c87c5fbaSopenharmony_ci  /* iterate through results until success */
552c87c5fbaSopenharmony_ci  for (rp = result; rp != NULL; rp = rp->ai_next) {
553c87c5fbaSopenharmony_ci    coap_address_t addr;
554c87c5fbaSopenharmony_ci
555c87c5fbaSopenharmony_ci    if (rp->ai_addrlen <= (socklen_t)sizeof(addr.addr)) {
556c87c5fbaSopenharmony_ci      coap_address_init(&addr);
557c87c5fbaSopenharmony_ci      addr.size = rp->ai_addrlen;
558c87c5fbaSopenharmony_ci      memcpy(&addr.addr, rp->ai_addr, rp->ai_addrlen);
559c87c5fbaSopenharmony_ci
560c87c5fbaSopenharmony_ci      ctx = coap_new_context(&addr);
561c87c5fbaSopenharmony_ci      if (ctx) {
562c87c5fbaSopenharmony_ci        /* TODO: output address:port for successful binding */
563c87c5fbaSopenharmony_ci        goto finish;
564c87c5fbaSopenharmony_ci      }
565c87c5fbaSopenharmony_ci    }
566c87c5fbaSopenharmony_ci  }
567c87c5fbaSopenharmony_ci
568c87c5fbaSopenharmony_ci  fprintf(stderr, "no context available for interface '%s'\n", node);
569c87c5fbaSopenharmony_ci
570c87c5fbaSopenharmony_cifinish:
571c87c5fbaSopenharmony_ci  freeaddrinfo(result);
572c87c5fbaSopenharmony_ci  return ctx;
573c87c5fbaSopenharmony_ci}
574c87c5fbaSopenharmony_ci
575c87c5fbaSopenharmony_ciint
576c87c5fbaSopenharmony_cimain(int argc, char **argv) {
577c87c5fbaSopenharmony_ci  coap_context_t  *ctx;
578c87c5fbaSopenharmony_ci  int result;
579c87c5fbaSopenharmony_ci  char addr_str[NI_MAXHOST] = "::";
580c87c5fbaSopenharmony_ci  char port_str[NI_MAXSERV] = "5683";
581c87c5fbaSopenharmony_ci  int opt;
582c87c5fbaSopenharmony_ci  coap_log_t log_level = COAP_LOG_WARN;
583c87c5fbaSopenharmony_ci  struct sigaction sa;
584c87c5fbaSopenharmony_ci
585c87c5fbaSopenharmony_ci  /* Initialize libcoap library */
586c87c5fbaSopenharmony_ci  coap_startup();
587c87c5fbaSopenharmony_ci
588c87c5fbaSopenharmony_ci  while ((opt = getopt(argc, argv, "A:p:v:")) != -1) {
589c87c5fbaSopenharmony_ci    switch (opt) {
590c87c5fbaSopenharmony_ci    case 'A' :
591c87c5fbaSopenharmony_ci      strncpy(addr_str, optarg, NI_MAXHOST-1);
592c87c5fbaSopenharmony_ci      addr_str[NI_MAXHOST - 1] = '\0';
593c87c5fbaSopenharmony_ci      break;
594c87c5fbaSopenharmony_ci    case 'p' :
595c87c5fbaSopenharmony_ci      strncpy(port_str, optarg, NI_MAXSERV-1);
596c87c5fbaSopenharmony_ci      port_str[NI_MAXSERV - 1] = '\0';
597c87c5fbaSopenharmony_ci      break;
598c87c5fbaSopenharmony_ci    case 'v' :
599c87c5fbaSopenharmony_ci      log_level = strtol(optarg, NULL, 10);
600c87c5fbaSopenharmony_ci      break;
601c87c5fbaSopenharmony_ci    default:
602c87c5fbaSopenharmony_ci      usage(argv[0], LIBCOAP_PACKAGE_VERSION);
603c87c5fbaSopenharmony_ci      exit(1);
604c87c5fbaSopenharmony_ci    }
605c87c5fbaSopenharmony_ci  }
606c87c5fbaSopenharmony_ci
607c87c5fbaSopenharmony_ci  coap_set_log_level(log_level);
608c87c5fbaSopenharmony_ci
609c87c5fbaSopenharmony_ci  ctx = get_context(addr_str, port_str);
610c87c5fbaSopenharmony_ci  if (!ctx)
611c87c5fbaSopenharmony_ci    return -1;
612c87c5fbaSopenharmony_ci
613c87c5fbaSopenharmony_ci  init_resources(ctx);
614c87c5fbaSopenharmony_ci
615c87c5fbaSopenharmony_ci  memset(&sa, 0, sizeof(sa));
616c87c5fbaSopenharmony_ci  sigemptyset(&sa.sa_mask);
617c87c5fbaSopenharmony_ci  sa.sa_handler = handle_sigint;
618c87c5fbaSopenharmony_ci  sa.sa_flags = 0;
619c87c5fbaSopenharmony_ci  sigaction(SIGINT, &sa, NULL);
620c87c5fbaSopenharmony_ci  sigaction(SIGTERM, &sa, NULL);
621c87c5fbaSopenharmony_ci  /* So we do not exit on a SIGPIPE */
622c87c5fbaSopenharmony_ci  sa.sa_handler = SIG_IGN;
623c87c5fbaSopenharmony_ci  sigaction(SIGPIPE, &sa, NULL);
624c87c5fbaSopenharmony_ci
625c87c5fbaSopenharmony_ci  while (!quit) {
626c87c5fbaSopenharmony_ci    result = coap_io_process(ctx, COAP_RESOURCE_CHECK_TIME * 1000);
627c87c5fbaSopenharmony_ci    if (result >= 0) {
628c87c5fbaSopenharmony_ci      /* coap_check_resource_list( ctx ); */
629c87c5fbaSopenharmony_ci    }
630c87c5fbaSopenharmony_ci  }
631c87c5fbaSopenharmony_ci
632c87c5fbaSopenharmony_ci  coap_free_context(ctx);
633c87c5fbaSopenharmony_ci  coap_cleanup();
634c87c5fbaSopenharmony_ci
635c87c5fbaSopenharmony_ci  return 0;
636c87c5fbaSopenharmony_ci}
637