iotivity 0.9.0
[platform/upstream/iotivity.git] / resource / csdk / libcoap-4.1.1 / examples / server.c
1 /* coap -- simple implementation of the Constrained Application Protocol (CoAP)
2  *         as defined in draft-ietf-core-coap
3  *
4  * Copyright (C) 2010--2013 Olaf Bergmann <bergmann@tzi.org>
5  *
6  * This file is part of the CoAP library libcoap. Please see
7  * README for terms of use.
8  */
9
10 #include <string.h>
11 #include <stdlib.h>
12 #include <unistd.h>
13 #include <stdio.h>
14 #include <ctype.h>
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>
20 #include <netdb.h>
21 #include <sys/stat.h>
22 #include <dirent.h>
23 #include <errno.h>
24 #include <signal.h>
25
26 #include "config.h"
27 #include "resource.h"
28 #include "coap.h"
29 #include <logger.h>
30 #include <ocsocket.h>
31
32 #define COAP_RESOURCE_CHECK_TIME 2
33
34 #define MOD_NAME ("CoAP-Server")
35 static uint8_t coap_wellknown_addr[] = {224,0,1,187};
36 static short coap_def_port = 5683;
37
38 #ifndef min
39 #define min(a,b) ((a) < (b) ? (a) : (b))
40 #endif
41
42 /* temporary storage for dynamic resource representations */
43 static int quit = 0;
44
45 /* changeable clock base (see handle_put_time()) */
46 static time_t my_clock_base = 0;
47
48 struct coap_resource_t *time_resource = NULL;
49
50 #ifndef WITHOUT_ASYNC
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 */
55
56 /* SIGINT handler: set quit to 1 for graceful termination */
57 void
58 handle_sigint(int signum) {
59   (void)signum;
60   quit = 1;
61 }
62
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"
65
66 void
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) {
70   unsigned char buf[3];
71   (void)ctx;
72   (void)resource;
73   (void)peer;
74   (void)request;
75   (void)token;
76
77   response->hdr->code = COAP_RESPONSE_CODE(205);
78
79   coap_add_option(response, COAP_OPTION_CONTENT_TYPE,
80           coap_encode_var_bytes(buf, COAP_MEDIATYPE_TEXT_PLAIN), buf);
81
82   coap_add_option(response, COAP_OPTION_MAXAGE,
83           coap_encode_var_bytes(buf, 0x2ffff), buf);
84
85   coap_add_data(response, strlen(INDEX), (unsigned char *)INDEX);
86 }
87
88 void
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;
93   coap_opt_t *option;
94   unsigned char buf[40];
95   size_t len;
96   time_t now;
97   coap_tick_t t;
98   coap_subscription_t *subscription;
99
100   /* FIXME: return time, e.g. in human-readable by default and ticks
101    * when query ?ticks is given. */
102
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);
106
107   if (request != NULL &&
108       coap_check_option(request, COAP_OPTION_OBSERVE, &opt_iter)) {
109     subscription = coap_add_observer(resource, peer, token);
110     if (subscription) {
111       subscription->non = request->hdr->type == COAP_MESSAGE_NON;
112       coap_add_option(response, COAP_OPTION_OBSERVE, 0, NULL);
113     }
114   }
115   if (resource->dirty == 1)
116     coap_add_option(response, COAP_OPTION_OBSERVE,
117                     coap_encode_var_bytes(buf, ctx->observe), buf);
118
119
120   if (my_clock_base)
121     coap_add_option(response, COAP_OPTION_CONTENT_FORMAT,
122                     coap_encode_var_bytes(buf, COAP_MEDIATYPE_TEXT_PLAIN), buf);
123
124   coap_add_option(response, COAP_OPTION_MAXAGE,
125           coap_encode_var_bytes(buf, 0x01), buf);
126
127   if (my_clock_base) {
128
129     /* calculate current time */
130     coap_ticks(&t);
131     now = my_clock_base + (t / COAP_TICKS_PER_SECOND);
132
133     if (request != NULL
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) {
137       /* output ticks */
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);
142
143     } else {                    /* output human-readable time */
144       struct tm *tmp;
145       tmp = gmtime(&now);
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);
150     }
151   }
152 }
153
154 void
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) {
158   coap_tick_t t;
159   size_t size;
160   unsigned char *data;
161   (void)ctx;
162   (void)peer;
163   (void)token;
164
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.
168    */
169
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);
173
174   resource->dirty = 1;
175
176   coap_get_data(request, &size, &data);
177
178   if (size == 0)                /* re-init */
179     my_clock_base = clock_offset;
180   else {
181     my_clock_base = 0;
182     coap_ticks(&t);
183     while(size--)
184       my_clock_base = my_clock_base * 10 + *data++;
185     my_clock_base -= t / COAP_TICKS_PER_SECOND;
186   }
187 }
188
189 void
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) {
193   (void)ctx;
194   (void)resource;
195   (void)peer;
196   (void)request;
197   (void)token;
198   (void)response;
199   my_clock_base = 0;            /* mark clock as "deleted" */
200
201   /* type = request->hdr->type == COAP_MESSAGE_CON  */
202   /*   ? COAP_MESSAGE_ACK : COAP_MESSAGE_NON; */
203 }
204
205 #ifndef WITHOUT_ASYNC
206 void
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;
211   coap_opt_t *option;
212   unsigned long delay = 5;
213   size_t size;
214   (void)resource;
215   (void)token;
216
217   if (async) {
218     if (async->id != request->hdr->id) {
219       coap_opt_filter_t f;
220       coap_option_filter_clear(f);
221       response->hdr->code = COAP_RESPONSE_CODE(503);
222     }
223     return;
224   }
225
226   option = coap_check_option(request, COAP_OPTION_URI_QUERY, &opt_iter);
227   if (option) {
228     unsigned char *p = COAP_OPT_VALUE(option);
229
230     delay = 0;
231     for (size = COAP_OPT_LENGTH(option); size; --size, ++p)
232       delay = delay * 10 + (*p - '0');
233   }
234
235   async = coap_register_async(ctx, peer, request,
236                               COAP_ASYNC_SEPARATE | COAP_ASYNC_CONFIRM,
237                               (void *)(COAP_TICKS_PER_SECOND * delay));
238 }
239
240 void
241 check_async(coap_context_t  *ctx, coap_tick_t now) {
242   coap_pdu_t *response;
243   coap_async_state_t *tmp;
244
245   size_t size = sizeof(coap_hdr_t) + 8;
246
247   if (!async || now < async->created + (unsigned long)async->appdata)
248     return;
249
250   response = coap_pdu_init(async->flags & COAP_ASYNC_CONFIRM
251                            ? COAP_MESSAGE_CON
252                            : COAP_MESSAGE_NON,
253                            COAP_RESPONSE_CODE(205), 0, size);
254   if (!response) {
255     debug("check_async: insufficient memory, we'll try later\n");
256     async->appdata =
257       (void *)((unsigned long)async->appdata + 15 * COAP_TICKS_PER_SECOND);
258     return;
259   }
260
261   response->hdr->id = coap_new_message_id(ctx);
262
263   if (async->tokenlen)
264     coap_add_token(response, async->tokenlen, async->token);
265
266   coap_add_data(response, 4, (unsigned char *)"done");
267
268   if (coap_send(ctx, &async->peer, response) == COAP_INVALID_TID) {
269     debug("check_async: cannot send response for message %d\n",
270           response->hdr->id);
271   }
272   coap_delete_pdu(response);
273   coap_remove_async(ctx, async->id, &tmp);
274   coap_free_async(async);
275   async = NULL;
276 }
277 #endif /* WITHOUT_ASYNC */
278
279 void
280 init_resources(coap_context_t *ctx) {
281   coap_resource_t *r;
282
283   r = coap_resource_init(NULL, 0, 0);
284   coap_register_handler(r, COAP_REQUEST_GET, hnd_get_index);
285
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);
289
290   /* store clock base to use in /time */
291   my_clock_base = clock_offset;
292
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);
297
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);
301   r->observable = 1;
302   coap_add_attr(r, (unsigned char *)"if", 2, (unsigned char *)"\"clock\"", 7, 0);
303
304   coap_add_resource(ctx, r);
305   time_resource = r;
306
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);
310
311   coap_add_attr(r, (unsigned char *)"ct", 2, (unsigned char *)"0", 1, 0);
312   coap_add_resource(ctx, r);
313 #endif /* WITHOUT_ASYNC */
314 }
315
316 void
317 usage( const char *program, const char *version) {
318   const char *p;
319
320   p = strrchr( program, '/' );
321   if ( p )
322     program = ++p;
323
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 );
331 }
332
333 coap_context_t *
334 get_context(const char *node, const char *port) {
335   coap_context_t *ctx = NULL;
336   int s;
337   struct addrinfo hints;
338   struct addrinfo *result, *rp;
339   OCDevAddr mcast_addr;
340
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;
345
346   s = getaddrinfo(node, port, &hints, &result);
347   if ( s != 0 ) {
348     fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(s));
349     return NULL;
350   }
351
352   /* iterate through results until success */
353   for (rp = result; rp != NULL; rp = rp->ai_next) {
354     coap_address_t addr;
355
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 );
361
362       ctx = coap_new_context(&addr);
363       if (ctx) {
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") );
369         }
370         goto finish;
371       }
372     }
373   }
374
375   fprintf(stderr, "no context available for interface '%s'\n", node);
376
377  finish:
378   freeaddrinfo(result);
379   return ctx;
380 }
381
382 int
383 main(int argc, char **argv) {
384   coap_context_t  *ctx;
385   fd_set readfds;
386   struct timeval tv, *timeout;
387   int result;
388   coap_tick_t now;
389   coap_queue_t *nextpdu;
390   char addr_str[NI_MAXHOST] = "::";
391   char port_str[NI_MAXSERV] = "5683";
392   int opt;
393   coap_log_t log_level = LOG_WARNING;
394
395   while ((opt = getopt(argc, argv, "A:p:v:")) != -1) {
396     switch (opt) {
397     case 'A' :
398       strncpy(addr_str, optarg, NI_MAXHOST-1);
399       addr_str[NI_MAXHOST - 1] = '\0';
400       break;
401     case 'p' :
402       strncpy(port_str, optarg, NI_MAXSERV-1);
403       port_str[NI_MAXSERV - 1] = '\0';
404       break;
405     case 'v' :
406       log_level = strtol(optarg, NULL, 10);
407       break;
408     default:
409       usage( argv[0], PACKAGE_VERSION );
410       exit( 1 );
411     }
412   }
413
414   coap_set_log_level(log_level);
415
416   ctx = get_context(addr_str, port_str);
417   if (!ctx)
418     return -1;
419
420   init_resources(ctx);
421
422   signal(SIGINT, handle_sigint);
423
424   while ( !quit ) {
425     FD_ZERO(&readfds);
426     FD_SET( ctx->sockfd, &readfds );
427     if (ctx->sockfd_wellknown != -1) {
428         FD_SET( ctx->sockfd_wellknown, &readfds );
429     }
430
431
432     nextpdu = coap_peek_next( ctx );
433
434     coap_ticks(&now);
435     while (nextpdu && nextpdu->t <= now - ctx->sendqueue_basetime) {
436       coap_retransmit( ctx, coap_pop_next( ctx ) );
437       nextpdu = coap_peek_next( ctx );
438     }
439
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;
444       timeout = &tv;
445     } else {
446       tv.tv_usec = 0;
447       tv.tv_sec = COAP_RESOURCE_CHECK_TIME;
448       timeout = &tv;
449     }
450     result = select( FD_SETSIZE, &readfds, 0, 0, timeout );
451
452     if ( result < 0 ) {         /* error */
453       if (errno != EINTR)
454         perror("select");
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 */
459       }
460
461       if (ctx->sockfd_wellknown != -1) {
462         if ( FD_ISSET( ctx->sockfd_wellknown, &readfds ) ) {  /* read from multicast socket */
463
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 */
468       }
469      }
470     } else {                    /* timeout */
471       if (time_resource) {
472         time_resource->dirty = 1;
473       }
474     }
475
476 #ifndef WITHOUT_ASYNC
477     /* check if we have to send asynchronous responses */
478     check_async(ctx, now);
479 #endif /* WITHOUT_ASYNC */
480
481 #ifndef WITHOUT_OBSERVE
482     /* check if we have to send observe notifications */
483     coap_check_notify(ctx);
484 #endif /* WITHOUT_OBSERVE */
485   }
486
487   coap_free_context( ctx );
488
489   return 0;
490 }