1 /* coap -- simple implementation of the Constrained Application Protocol (CoAP)
2 * as defined in draft-ietf-core-coap
4 * Copyright (C) 2010--2013 Olaf Bergmann <bergmann@tzi.org>
6 * This file is part of the CoAP library libcoap. Please see
7 * README for terms of use.
15 #include <sys/select.h>
16 #include <sys/types.h>
17 #include <sys/socket.h>
18 #include <netinet/in.h>
19 #include <arpa/inet.h>
32 #define COAP_RESOURCE_CHECK_TIME 2
34 #define MOD_NAME ("CoAP-Server")
35 static uint8_t coap_wellknown_addr[] = {224,0,1,187};
36 static short coap_def_port = 5683;
39 #define min(a,b) ((a) < (b) ? (a) : (b))
42 /* temporary storage for dynamic resource representations */
45 /* changeable clock base (see handle_put_time()) */
46 static time_t my_clock_base = 0;
48 struct coap_resource_t *time_resource = NULL;
51 /* This variable is used to mimic long-running tasks that require
52 * asynchronous responses. */
53 static coap_async_state_t *async = NULL;
54 #endif /* WITHOUT_ASYNC */
56 /* SIGINT handler: set quit to 1 for graceful termination */
58 handle_sigint(int signum) {
63 #define INDEX "This is a test server made with libcoap (see http://libcoap.sf.net)\n" \
64 "Copyright (C) 2010--2013 Olaf Bergmann <bergmann@tzi.org>\n\n"
67 hnd_get_index(coap_context_t *ctx, struct coap_resource_t *resource,
68 coap_address_t *peer, coap_pdu_t *request, str *token,
69 coap_pdu_t *response) {
77 response->hdr->code = COAP_RESPONSE_CODE(205);
79 coap_add_option(response, COAP_OPTION_CONTENT_TYPE,
80 coap_encode_var_bytes(buf, COAP_MEDIATYPE_TEXT_PLAIN), buf);
82 coap_add_option(response, COAP_OPTION_MAXAGE,
83 coap_encode_var_bytes(buf, 0x2ffff), buf);
85 coap_add_data(response, strlen(INDEX), (unsigned char *)INDEX);
89 hnd_get_time(coap_context_t *ctx, struct coap_resource_t *resource,
90 coap_address_t *peer, coap_pdu_t *request, str *token,
91 coap_pdu_t *response) {
92 coap_opt_iterator_t opt_iter;
94 unsigned char buf[40];
98 coap_subscription_t *subscription;
100 /* FIXME: return time, e.g. in human-readable by default and ticks
101 * when query ?ticks is given. */
103 /* if my_clock_base was deleted, we pretend to have no such resource */
104 response->hdr->code =
105 my_clock_base ? COAP_RESPONSE_CODE(205) : COAP_RESPONSE_CODE(404);
107 if (request != NULL &&
108 coap_check_option(request, COAP_OPTION_OBSERVE, &opt_iter)) {
109 subscription = coap_add_observer(resource, peer, token);
111 subscription->non = request->hdr->type == COAP_MESSAGE_NON;
112 coap_add_option(response, COAP_OPTION_OBSERVE, 0, NULL);
115 if (resource->dirty == 1)
116 coap_add_option(response, COAP_OPTION_OBSERVE,
117 coap_encode_var_bytes(buf, ctx->observe), buf);
121 coap_add_option(response, COAP_OPTION_CONTENT_FORMAT,
122 coap_encode_var_bytes(buf, COAP_MEDIATYPE_TEXT_PLAIN), buf);
124 coap_add_option(response, COAP_OPTION_MAXAGE,
125 coap_encode_var_bytes(buf, 0x01), buf);
129 /* calculate current time */
131 now = my_clock_base + (t / COAP_TICKS_PER_SECOND);
134 && (option = coap_check_option(request, COAP_OPTION_URI_QUERY, &opt_iter))
135 && memcmp(COAP_OPT_VALUE(option), "ticks",
136 min(5, COAP_OPT_LENGTH(option))) == 0) {
138 len = snprintf((char *)buf,
139 min(sizeof(buf), response->max_size - response->length),
140 "%u", (unsigned int)now);
141 coap_add_data(response, len, buf);
143 } else { /* output human-readable time */
146 len = strftime((char *)buf,
147 min(sizeof(buf), response->max_size - response->length),
148 "%b %d %H:%M:%S", tmp);
149 coap_add_data(response, len, buf);
155 hnd_put_time(coap_context_t *ctx, struct coap_resource_t *resource,
156 coap_address_t *peer, coap_pdu_t *request, str *token,
157 coap_pdu_t *response) {
165 /* FIXME: re-set my_clock_base to clock_offset if my_clock_base == 0
166 * and request is empty. When not empty, set to value in request payload
167 * (insist on query ?ticks). Return Created or Ok.
170 /* if my_clock_base was deleted, we pretend to have no such resource */
171 response->hdr->code =
172 my_clock_base ? COAP_RESPONSE_CODE(204) : COAP_RESPONSE_CODE(201);
176 coap_get_data(request, &size, &data);
178 if (size == 0) /* re-init */
179 my_clock_base = clock_offset;
184 my_clock_base = my_clock_base * 10 + *data++;
185 my_clock_base -= t / COAP_TICKS_PER_SECOND;
190 hnd_delete_time(coap_context_t *ctx, struct coap_resource_t *resource,
191 coap_address_t *peer, coap_pdu_t *request, str *token,
192 coap_pdu_t *response) {
199 my_clock_base = 0; /* mark clock as "deleted" */
201 /* type = request->hdr->type == COAP_MESSAGE_CON */
202 /* ? COAP_MESSAGE_ACK : COAP_MESSAGE_NON; */
205 #ifndef WITHOUT_ASYNC
207 hnd_get_async(coap_context_t *ctx, struct coap_resource_t *resource,
208 coap_address_t *peer, coap_pdu_t *request, str *token,
209 coap_pdu_t *response) {
210 coap_opt_iterator_t opt_iter;
212 unsigned long delay = 5;
218 if (async->id != request->hdr->id) {
220 coap_option_filter_clear(f);
221 response->hdr->code = COAP_RESPONSE_CODE(503);
226 option = coap_check_option(request, COAP_OPTION_URI_QUERY, &opt_iter);
228 unsigned char *p = COAP_OPT_VALUE(option);
231 for (size = COAP_OPT_LENGTH(option); size; --size, ++p)
232 delay = delay * 10 + (*p - '0');
235 async = coap_register_async(ctx, peer, request,
236 COAP_ASYNC_SEPARATE | COAP_ASYNC_CONFIRM,
237 (void *)(COAP_TICKS_PER_SECOND * delay));
241 check_async(coap_context_t *ctx, coap_tick_t now) {
242 coap_pdu_t *response;
243 coap_async_state_t *tmp;
245 size_t size = sizeof(coap_hdr_t) + 8;
247 if (!async || now < async->created + (unsigned long)async->appdata)
250 response = coap_pdu_init(async->flags & COAP_ASYNC_CONFIRM
253 COAP_RESPONSE_CODE(205), 0, size);
255 debug("check_async: insufficient memory, we'll try later\n");
257 (void *)((unsigned long)async->appdata + 15 * COAP_TICKS_PER_SECOND);
261 response->hdr->id = coap_new_message_id(ctx);
264 coap_add_token(response, async->tokenlen, async->token);
266 coap_add_data(response, 4, (unsigned char *)"done");
268 if (coap_send(ctx, &async->peer, response) == COAP_INVALID_TID) {
269 debug("check_async: cannot send response for message %d\n",
272 coap_delete_pdu(response);
273 coap_remove_async(ctx, async->id, &tmp);
274 coap_free_async(async);
277 #endif /* WITHOUT_ASYNC */
280 init_resources(coap_context_t *ctx) {
283 r = coap_resource_init(NULL, 0, 0);
284 coap_register_handler(r, COAP_REQUEST_GET, hnd_get_index);
286 coap_add_attr(r, (unsigned char *)"ct", 2, (unsigned char *)"0", 1, 0);
287 coap_add_attr(r, (unsigned char *)"title", 5, (unsigned char *)"\"General Info\"", 14, 0);
288 coap_add_resource(ctx, r);
290 /* store clock base to use in /time */
291 my_clock_base = clock_offset;
293 r = coap_resource_init((unsigned char *)"time", 4, 0);
294 coap_register_handler(r, COAP_REQUEST_GET, hnd_get_time);
295 coap_register_handler(r, COAP_REQUEST_PUT, hnd_put_time);
296 coap_register_handler(r, COAP_REQUEST_DELETE, hnd_delete_time);
298 coap_add_attr(r, (unsigned char *)"ct", 2, (unsigned char *)"0", 1, 0);
299 coap_add_attr(r, (unsigned char *)"title", 5, (unsigned char *)"\"Internal Clock\"", 16, 0);
300 coap_add_attr(r, (unsigned char *)"rt", 2, (unsigned char *)"\"Ticks\"", 7, 0);
302 coap_add_attr(r, (unsigned char *)"if", 2, (unsigned char *)"\"clock\"", 7, 0);
304 coap_add_resource(ctx, r);
307 #ifndef WITHOUT_ASYNC
308 r = coap_resource_init((unsigned char *)"async", 5, 0);
309 coap_register_handler(r, COAP_REQUEST_GET, hnd_get_async);
311 coap_add_attr(r, (unsigned char *)"ct", 2, (unsigned char *)"0", 1, 0);
312 coap_add_resource(ctx, r);
313 #endif /* WITHOUT_ASYNC */
317 usage( const char *program, const char *version) {
320 p = strrchr( program, '/' );
324 fprintf( stderr, "%s v%s -- a small CoAP implementation\n"
325 "(c) 2010,2011 Olaf Bergmann <bergmann@tzi.org>\n\n"
326 "usage: %s [-A address] [-p port]\n\n"
327 "\t-A address\tinterface address to bind to\n"
328 "\t-p port\t\tlisten on specified port\n"
329 "\t-v num\t\tverbosity level (default: 3)\n",
330 program, version, program );
334 get_context(const char *node, const char *port) {
335 coap_context_t *ctx = NULL;
337 struct addrinfo hints;
338 struct addrinfo *result, *rp;
339 OCDevAddr mcast_addr;
341 memset(&hints, 0, sizeof(struct addrinfo));
342 hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */
343 hints.ai_socktype = SOCK_DGRAM; /* Coap uses UDP */
344 hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST;
346 s = getaddrinfo(node, port, &hints, &result);
348 fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(s));
352 /* iterate through results until success */
353 for (rp = result; rp != NULL; rp = rp->ai_next) {
356 if (rp->ai_addrlen <= sizeof(addr.addr)) {
357 coap_address_init(&addr);
358 addr.size = rp->ai_addrlen;
359 memcpy(&addr.addr, rp->ai_addr, rp->ai_addrlen);
360 OC_LOG_BUFFER(DEBUG, MOD_NAME, (uint8_t *)&addr, addr.size + 4 );
362 ctx = coap_new_context(&addr);
364 /* TODO: output address:port for successful binding */
365 OCBuildIPv4Address(coap_wellknown_addr[0], coap_wellknown_addr[1],
366 coap_wellknown_addr[2], coap_wellknown_addr[3], coap_def_port, &mcast_addr);
367 if (coap_join_wellknown_group(ctx, (coap_address_t*)&mcast_addr) != 0) {
368 OC_LOG(ERROR, MOD_NAME, PCF("Unable to join to wellknown multicast group") );
375 fprintf(stderr, "no context available for interface '%s'\n", node);
378 freeaddrinfo(result);
383 main(int argc, char **argv) {
386 struct timeval tv, *timeout;
389 coap_queue_t *nextpdu;
390 char addr_str[NI_MAXHOST] = "::";
391 char port_str[NI_MAXSERV] = "5683";
393 coap_log_t log_level = LOG_WARNING;
395 while ((opt = getopt(argc, argv, "A:p:v:")) != -1) {
398 strncpy(addr_str, optarg, NI_MAXHOST-1);
399 addr_str[NI_MAXHOST - 1] = '\0';
402 strncpy(port_str, optarg, NI_MAXSERV-1);
403 port_str[NI_MAXSERV - 1] = '\0';
406 log_level = strtol(optarg, NULL, 10);
409 usage( argv[0], PACKAGE_VERSION );
414 coap_set_log_level(log_level);
416 ctx = get_context(addr_str, port_str);
422 signal(SIGINT, handle_sigint);
426 FD_SET( ctx->sockfd, &readfds );
427 if (ctx->sockfd_wellknown != -1) {
428 FD_SET( ctx->sockfd_wellknown, &readfds );
432 nextpdu = coap_peek_next( ctx );
435 while (nextpdu && nextpdu->t <= now - ctx->sendqueue_basetime) {
436 coap_retransmit( ctx, coap_pop_next( ctx ) );
437 nextpdu = coap_peek_next( ctx );
440 if ( nextpdu && nextpdu->t <= COAP_RESOURCE_CHECK_TIME ) {
441 /* set timeout if there is a pdu to send before our automatic timeout occurs */
442 tv.tv_usec = ((nextpdu->t) % COAP_TICKS_PER_SECOND) * 1000000 / COAP_TICKS_PER_SECOND;
443 tv.tv_sec = (nextpdu->t) / COAP_TICKS_PER_SECOND;
447 tv.tv_sec = COAP_RESOURCE_CHECK_TIME;
450 result = select( FD_SETSIZE, &readfds, 0, 0, timeout );
452 if ( result < 0 ) { /* error */
455 } else if ( result > 0 ) { /* read from unicast socket */
456 if ( FD_ISSET( ctx->sockfd, &readfds ) ) {
457 coap_read( ctx, ctx->sockfd ); /* read received data */
458 coap_dispatch( ctx ); /* and dispatch PDUs from receivequeue */
461 if (ctx->sockfd_wellknown != -1) {
462 if ( FD_ISSET( ctx->sockfd_wellknown, &readfds ) ) { /* read from multicast socket */
464 OC_LOG(DEBUG, MOD_NAME, PCF("Device Discovery request at well-known address !!"));
465 coap_read( ctx, ctx->sockfd_wellknown ); /* read received data */
466 TODO("Do we need to call coap_dispatch separately for unicast and multicast sockets")
467 coap_dispatch( ctx ); /* and dispatch PDUs from receivequeue */
470 } else { /* timeout */
472 time_resource->dirty = 1;
476 #ifndef WITHOUT_ASYNC
477 /* check if we have to send asynchronous responses */
478 check_async(ctx, now);
479 #endif /* WITHOUT_ASYNC */
481 #ifndef WITHOUT_OBSERVE
482 /* check if we have to send observe notifications */
483 coap_check_notify(ctx);
484 #endif /* WITHOUT_OBSERVE */
487 coap_free_context( ctx );