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