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