1/* coap-server.c -- Example CoAP server using Contiki and libcoap 2 * 3 * Copyright (C) 2011 Olaf Bergmann <bergmann@tzi.org> 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. Neither the name of the Institute nor the names of its contributors 14 * may be used to endorse or promote products derived from this software 15 * without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 * 29 * This file is part of the Contiki operating system. 30 * 31 */ 32 33#include "contiki-net.h" 34#include "coap3/coap.h" 35 36static coap_context_t *coap_context; 37 38static clock_time_t clock_offset; 39/* changeable clock base (see handle_put_time()) */ 40static clock_time_t my_clock_base = 0; 41static coap_resource_t *time_resource = NULL; /* just for testing */ 42 43PROCESS(coap_server_process, "CoAP server process"); 44AUTOSTART_PROCESSES(&coap_server_process); 45/*---------------------------------------------------------------------------*/ 46void 47init_coap_server(coap_context_t **ctx) { 48 uip_ds6_addr_t *my_address; 49 coap_address_t listen_addr; 50 51 assert(ctx); 52 53 my_address = uip_ds6_get_global(ADDR_PREFERRED); 54 uip_ipaddr_copy(&listen_addr.addr, &my_address->ipaddr); 55 coap_address_set_port(&listen_addr, COAP_DEFAULT_PORT); 56 57 *ctx = coap_new_context(&listen_addr); 58 59 if (!*ctx) { 60 coap_log_crit("cannot create CoAP context\r\n"); 61 } 62 coap_context_set_max_idle_sessions(*ctx, 2); 63} 64 65/*---------------------------------------------------------------------------*/ 66#ifndef min 67# define min(a,b) ((a) < (b) ? (a) : (b)) 68#endif 69 70void 71hnd_get_time(coap_resource_t *resource, coap_session_t *session, 72 const coap_pdu_t *request, const coap_string_t *query, 73 coap_pdu_t *response) { 74 unsigned char buf[40]; 75 size_t len; 76 coap_tick_t now; 77 coap_tick_t t; 78 79 if (my_clock_base) { 80 81 /* calculate current time */ 82 coap_ticks(&t); 83 now = my_clock_base + (t / COAP_TICKS_PER_SECOND); 84 85 if (query != NULL 86 && coap_string_equal(query, coap_make_str_const("ticks"))) { 87 /* output ticks */ 88 len = snprintf((char *)buf, sizeof(buf), "%u", (unsigned int)now); 89 90 } else { /* output human-readable time */ 91 struct tm *tmp; 92 time_t tnow = now; 93 tmp = gmtime(&tnow); 94 if (!tmp) { 95 /* If 'tnow' is not valid */ 96 coap_pdu_set_code(response, COAP_RESPONSE_CODE_NOT_FOUND); 97 return; 98 } else { 99 len = strftime((char *)buf, sizeof(buf), "%b %d %H:%M:%S", tmp); 100 } 101 } 102 coap_add_data_blocked_response(request, response, 103 COAP_MEDIATYPE_TEXT_PLAIN, 1, 104 len, 105 buf); 106 } else { 107 /* if my_clock_base was deleted, we pretend to have no such resource */ 108 coap_pdu_set_code(response, COAP_RESPONSE_CODE_NOT_FOUND); 109 } 110} 111 112void 113init_coap_resources(coap_context_t *ctx) { 114 coap_resource_t *r; 115#if 0 116 r = coap_resource_init(NULL, 0, 0); 117 coap_register_handler(r, COAP_REQUEST_GET, hnd_get_index); 118 119 coap_add_attr(r, coap_make_str_const("ct"), coap_make_str_const("0"), 0); 120 coap_add_attr(r, coap_make_str_const("title"), coap_make_str_const("\"General Info\""), 0); 121 coap_add_resource(ctx, r); 122#endif 123 /* store clock base to use in /time */ 124 my_clock_base = clock_offset; 125 126 r = coap_resource_init(coap_make_str_const("time"), 0); 127 if (!r) 128 goto error; 129 130 coap_resource_set_get_observable(r, 1); 131 time_resource = r; 132 coap_register_handler(r, COAP_REQUEST_GET, hnd_get_time); 133#if 0 134 coap_register_handler(r, COAP_REQUEST_PUT, hnd_put_time); 135 coap_register_handler(r, COAP_REQUEST_DELETE, hnd_delete_time); 136#endif 137 coap_add_attr(r, coap_make_str_const("ct"), coap_make_str_const("0"), 0); 138 /* coap_add_attr(r, coap_make_str_const("title"), coap_make_str_const("\"Internal Clock\""), 0); */ 139 coap_add_attr(r, coap_make_str_const("rt"), coap_make_str_const("\"ticks\""), 0); 140 coap_add_attr(r, coap_make_str_const("if"), coap_make_str_const("\"clock\""), 0); 141 142 coap_add_resource(ctx, r); 143#if 0 144 if (coap_async_is_supported()) { 145 r = coap_resource_init(coap_make_str_const("async"), 0); 146 coap_register_handler(r, COAP_REQUEST_GET, hnd_get_async); 147 148 coap_add_attr(r, coap_make_str_const("ct"), coap_make_str_const("0"), 0); 149 coap_add_resource(ctx, r); 150 } 151#endif 152 153 return; 154error: 155 coap_log_crit("cannot create resource\n"); 156} 157 158/* struct etimer notify_timer; */ 159struct etimer dirty_timer; 160 161/*---------------------------------------------------------------------------*/ 162PROCESS_THREAD(coap_server_process, ev, data) { 163 PROCESS_BEGIN(); 164 165 /* Initialize libcoap library */ 166 coap_startup(); 167 168 clock_offset = clock_time(); 169 init_coap_server(&coap_context); 170 171 if (!coap_context) { 172 coap_log_emerg("cannot create context\n"); 173 PROCESS_EXIT(); 174 } 175 176 init_coap_resources(coap_context); 177 178 /* etimer_set(¬ify_timer, 5 * CLOCK_SECOND); */ 179 etimer_set(&dirty_timer, 30 * CLOCK_SECOND); 180 181 while (1) { 182 PROCESS_YIELD(); 183 if (ev == PROCESS_EVENT_TIMER && etimer_expired(&dirty_timer)) { 184 coap_resource_notify_observers(time_resource, NULL); 185 etimer_reset(&dirty_timer); 186 } 187 } 188 coap_cleanup(); 189 190 PROCESS_END(); 191} 192/*---------------------------------------------------------------------------*/ 193