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 17coap_context_t *main_coap_context; 18 19static coap_time_t clock_offset; 20/* changeable clock base (see handle_put_time()) */ 21static coap_time_t my_clock_base = 0; 22static 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 28void 29hnd_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 72void 73init_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; 114error: 115 coap_log_crit("cannot create resource\n"); 116} 117 118void 119server_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 200void 201server_coap_finished(void) { 202 coap_free_context(main_coap_context); 203 main_coap_context = NULL; 204 coap_cleanup(); 205} 206 207void 208server_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