Imported Upstream version 0.9.1
[platform/upstream/iotivity.git] / resource / csdk / connectivity / lib / 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
30 #define COAP_RESOURCE_CHECK_TIME 2
31
32 #ifndef min
33 #define min(a,b) ((a) < (b) ? (a) : (b))
34 #endif
35
36 /* temporary storage for dynamic resource representations */
37 static int quit = 0;
38
39 /* changeable clock base (see handle_put_time()) */
40 static time_t my_clock_base = 0;
41
42 struct coap_resource_t *time_resource = NULL;
43
44 #ifndef WITHOUT_ASYNC
45 /* This variable is used to mimic long-running tasks that require
46  * asynchronous responses. */
47 static coap_async_state_t *async = NULL;
48 #endif /* WITHOUT_ASYNC */
49
50 /* SIGINT handler: set quit to 1 for graceful termination */
51 void handle_sigint(int signum)
52 {
53     quit = 1;
54 }
55
56 #define INDEX "This is a test server made with libcoap (see http://libcoap.sf.net)\n" \
57           "Copyright (C) 2010--2013 Olaf Bergmann <bergmann@tzi.org>\n\n"
58
59 void hnd_get_index(coap_context_t *ctx, struct coap_resource_t *resource, coap_address_t *peer,
60         coap_pdu_t *request, str *token, coap_pdu_t *response)
61 {
62     unsigned char buf[3];
63
64     response->hdr->code = COAP_RESPONSE_CODE(205);
65
66     coap_add_option(response, COAP_OPTION_CONTENT_TYPE,
67             coap_encode_var_bytes(buf, COAP_MEDIATYPE_TEXT_PLAIN), buf);
68
69     coap_add_option(response, COAP_OPTION_MAXAGE, coap_encode_var_bytes(buf, 0x2ffff), buf);
70
71     coap_add_data(response, strlen(INDEX), (unsigned char *) INDEX);
72 }
73
74 void hnd_get_time(coap_context_t *ctx, struct coap_resource_t *resource, coap_address_t *peer,
75         coap_pdu_t *request, str *token, coap_pdu_t *response)
76 {
77     coap_opt_iterator_t opt_iter;
78     coap_opt_t *option;
79     unsigned char buf[40];
80     size_t len;
81     time_t now;
82     coap_tick_t t;
83     coap_subscription_t *subscription;
84
85     /* FIXME: return time, e.g. in human-readable by default and ticks
86      * when query ?ticks is given. */
87
88     /* if my_clock_base was deleted, we pretend to have no such resource */
89     response->hdr->code = my_clock_base ? COAP_RESPONSE_CODE(205) : COAP_RESPONSE_CODE(404);
90
91     if (request != NULL && coap_check_option(request, COAP_OPTION_OBSERVE, &opt_iter))
92     {
93         subscription = coap_add_observer(resource, peer, token);
94         if (subscription)
95         {
96             subscription->non = request->hdr->type == COAP_MESSAGE_NON;
97             coap_add_option(response, COAP_OPTION_OBSERVE, 0, NULL);
98         }
99     }
100     if (resource->dirty == 1)
101         coap_add_option(response, COAP_OPTION_OBSERVE, coap_encode_var_bytes(buf, ctx->observe),
102                 buf);
103
104     if (my_clock_base)
105         coap_add_option(response, COAP_OPTION_CONTENT_FORMAT,
106                 coap_encode_var_bytes(buf, COAP_MEDIATYPE_TEXT_PLAIN), buf);
107
108     coap_add_option(response, COAP_OPTION_MAXAGE, coap_encode_var_bytes(buf, 0x01), buf);
109
110     if (my_clock_base)
111     {
112
113         /* calculate current time */
114         coap_ticks(&t);
115         now = my_clock_base + (t / COAP_TICKS_PER_SECOND);
116
117         if (request != NULL
118                 && (option = coap_check_option(request, COAP_OPTION_URI_QUERY, &opt_iter))
119                 && memcmp(COAP_OPT_VALUE(option), "ticks", min(5, COAP_OPT_LENGTH(option))) == 0)
120         {
121             /* output ticks */
122             len = snprintf((char *) buf, min(sizeof(buf), response->max_size - response->length),
123                     "%u", (unsigned int) now);
124             coap_add_data(response, len, buf);
125
126         }
127         else
128         { /* output human-readable time */
129             struct tm *tmp;
130             tmp = gmtime(&now);
131             len = strftime((char *) buf, min(sizeof(buf), response->max_size - response->length),
132                     "%b %d %H:%M:%S", tmp);
133             coap_add_data(response, len, buf);
134         }
135     }
136 }
137
138 void hnd_put_time(coap_context_t *ctx, struct coap_resource_t *resource, coap_address_t *peer,
139         coap_pdu_t *request, str *token, coap_pdu_t *response)
140 {
141     coap_tick_t t;
142     size_t size;
143     unsigned char *data;
144
145     /* FIXME: re-set my_clock_base to clock_offset if my_clock_base == 0
146      * and request is empty. When not empty, set to value in request payload
147      * (insist on query ?ticks). Return Created or Ok.
148      */
149
150     /* if my_clock_base was deleted, we pretend to have no such resource */
151     response->hdr->code = my_clock_base ? COAP_RESPONSE_CODE(204) : COAP_RESPONSE_CODE(201);
152
153     resource->dirty = 1;
154
155     coap_get_data(request, &size, &data);
156
157     if (size == 0) /* re-init */
158         my_clock_base = clock_offset;
159     else
160     {
161         my_clock_base = 0;
162         coap_ticks(&t);
163         while (size--)
164             my_clock_base = my_clock_base * 10 + *data++;
165         my_clock_base -= t / COAP_TICKS_PER_SECOND;
166     }
167 }
168
169 void hnd_delete_time(coap_context_t *ctx, struct coap_resource_t *resource, coap_address_t *peer,
170         coap_pdu_t *request, str *token, coap_pdu_t *response)
171 {
172     my_clock_base = 0; /* mark clock as "deleted" */
173
174     /* type = request->hdr->type == COAP_MESSAGE_CON  */
175     /*   ? COAP_MESSAGE_ACK : COAP_MESSAGE_NON; */
176 }
177
178 #ifndef WITHOUT_ASYNC
179 void hnd_get_async(coap_context_t *ctx, struct coap_resource_t *resource, coap_address_t *peer,
180         coap_pdu_t *request, str *token, coap_pdu_t *response)
181 {
182     coap_opt_iterator_t opt_iter;
183     coap_opt_t *option;
184     unsigned long delay = 5;
185     size_t size;
186
187     if (async)
188     {
189         if (async->id != request->hdr->id)
190         {
191             coap_opt_filter_t f;
192             coap_option_filter_clear(f);
193             response->hdr->code = COAP_RESPONSE_CODE(503);
194         }
195         return;
196     }
197
198     option = coap_check_option(request, COAP_OPTION_URI_QUERY, &opt_iter);
199     if (option)
200     {
201         unsigned char *p = COAP_OPT_VALUE(option);
202
203         delay = 0;
204         for (size = COAP_OPT_LENGTH(option); size; --size, ++p)
205             delay = delay * 10 + (*p - '0');
206     }
207
208     async = coap_register_async(ctx, peer, request, COAP_ASYNC_SEPARATE | COAP_ASYNC_CONFIRM,
209             (void *) (COAP_TICKS_PER_SECOND * delay));
210 }
211
212 void check_async(coap_context_t *ctx, coap_tick_t now)
213 {
214     coap_pdu_t *response;
215     coap_async_state_t *tmp;
216
217     size_t size = sizeof(coap_hdr_t) + 8;
218
219     if (!async || now < async->created + (unsigned long) async->appdata)
220         return;
221
222     response = coap_pdu_init(async->flags & COAP_ASYNC_CONFIRM ? COAP_MESSAGE_CON : COAP_MESSAGE_NON,
223     COAP_RESPONSE_CODE(205), 0, size);
224     if (!response)
225     {
226         debug("check_async: insufficient memory, we'll try later\n");
227         async->appdata = (void *) ((unsigned long) async->appdata + 15 * COAP_TICKS_PER_SECOND);
228         return;
229     }
230
231     response->hdr->id = coap_new_message_id(ctx);
232
233     if (async->tokenlen)
234         coap_add_token(response, async->tokenlen, async->token);
235
236     coap_add_data(response, 4, (unsigned char *) "done");
237
238     if (coap_send(ctx, &async->peer, response) == COAP_INVALID_TID)
239     {
240         debug("check_async: cannot send response for message %d\n", response->hdr->id);
241     }
242     coap_delete_pdu(response);
243     coap_remove_async(ctx, async->id, &tmp);
244     coap_free_async(async);
245     async = NULL;
246 }
247 #endif /* WITHOUT_ASYNC */
248
249 void init_resources(coap_context_t *ctx)
250 {
251     coap_resource_t *r;
252
253     r = coap_resource_init(NULL, 0, 0);
254     coap_register_handler(r, COAP_REQUEST_GET, hnd_get_index);
255
256     coap_add_attr(r, (unsigned char *) "ct", 2, (unsigned char *) "0", 1, 0);
257     coap_add_attr(r, (unsigned char *) "title", 5, (unsigned char *) "\"General Info\"", 14, 0);
258     coap_add_resource(ctx, r);
259
260     /* store clock base to use in /time */
261     my_clock_base = clock_offset;
262
263     r = coap_resource_init((unsigned char *) "time", 4, 0);
264     coap_register_handler(r, COAP_REQUEST_GET, hnd_get_time);
265     coap_register_handler(r, COAP_REQUEST_PUT, hnd_put_time);
266     coap_register_handler(r, COAP_REQUEST_DELETE, hnd_delete_time);
267
268     coap_add_attr(r, (unsigned char *) "ct", 2, (unsigned char *) "0", 1, 0);
269     coap_add_attr(r, (unsigned char *) "title", 5, (unsigned char *) "\"Internal Clock\"", 16, 0);
270     coap_add_attr(r, (unsigned char *) "rt", 2, (unsigned char *) "\"Ticks\"", 7, 0);
271     r->observable = 1;
272     coap_add_attr(r, (unsigned char *) "if", 2, (unsigned char *) "\"clock\"", 7, 0);
273
274     coap_add_resource(ctx, r);
275     time_resource = r;
276
277 #ifndef WITHOUT_ASYNC
278     r = coap_resource_init((unsigned char *) "async", 5, 0);
279     coap_register_handler(r, COAP_REQUEST_GET, hnd_get_async);
280
281     coap_add_attr(r, (unsigned char *) "ct", 2, (unsigned char *) "0", 1, 0);
282     coap_add_resource(ctx, r);
283 #endif /* WITHOUT_ASYNC */
284 }
285
286 void usage(const char *program, const char *version)
287 {
288     const char *p;
289
290     p = strrchr(program, '/');
291     if (p)
292         program = ++p;
293
294     fprintf(stderr, "%s v%s -- a small CoAP implementation\n"
295             "(c) 2010,2011 Olaf Bergmann <bergmann@tzi.org>\n\n"
296             "usage: %s [-A address] [-p port]\n\n"
297             "\t-A address\tinterface address to bind to\n"
298             "\t-p port\t\tlisten on specified port\n"
299             "\t-v num\t\tverbosity level (default: 3)\n", program, version, program);
300 }
301
302 coap_context_t *
303 get_context(const char *node, const char *port)
304 {
305     coap_context_t *ctx = NULL;
306     int s;
307     struct addrinfo hints;
308     struct addrinfo *result, *rp;
309
310     memset(&hints, 0, sizeof(struct addrinfo));
311     hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */
312     hints.ai_socktype = SOCK_DGRAM; /* Coap uses UDP */
313     hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST;
314
315     s = getaddrinfo(node, port, &hints, &result);
316     if (s != 0)
317     {
318         fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(s));
319         return NULL;
320     }
321
322     /* iterate through results until success */
323     for (rp = result; rp != NULL; rp = rp->ai_next)
324     {
325         coap_address_t addr;
326
327         if (rp->ai_addrlen <= sizeof(addr.addr))
328         {
329             coap_address_init(&addr);
330             addr.size = rp->ai_addrlen;
331             memcpy(&addr.addr, rp->ai_addr, rp->ai_addrlen);
332
333             ctx = coap_new_context(&addr);
334             if (ctx)
335             {
336                 /* TODO: output address:port for successful binding */
337                 goto finish;
338             }
339         }
340     }
341
342     fprintf(stderr, "no context available for interface '%s'\n", node);
343
344     finish: freeaddrinfo(result);
345     return ctx;
346 }
347
348 int main(int argc, char **argv)
349 {
350     coap_context_t *ctx;
351     fd_set readfds;
352     struct timeval tv, *timeout;
353     int result;
354     coap_tick_t now;
355     coap_queue_t *nextpdu;
356     char addr_str[NI_MAXHOST] = "::";
357     char port_str[NI_MAXSERV] = "5683";
358     int opt;
359     coap_log_t log_level = LOG_WARNING;
360
361     while ((opt = getopt(argc, argv, "A:p:v:")) != -1)
362     {
363         switch (opt)
364         {
365             case 'A':
366                 strncpy(addr_str, optarg, NI_MAXHOST - 1);
367                 addr_str[NI_MAXHOST - 1] = '\0';
368                 break;
369             case 'p':
370                 strncpy(port_str, optarg, NI_MAXSERV - 1);
371                 port_str[NI_MAXSERV - 1] = '\0';
372                 break;
373             case 'v':
374                 log_level = strtol(optarg, NULL, 10);
375                 break;
376             default:
377                 usage(argv[0], PACKAGE_VERSION);
378                 exit(1);
379         }
380     }
381
382     coap_set_log_level(log_level);
383
384     ctx = get_context(addr_str, port_str);
385     if (!ctx)
386         return -1;
387
388     init_resources(ctx);
389
390     signal(SIGINT, handle_sigint);
391
392     while (!quit)
393     {
394         FD_ZERO(&readfds);
395         FD_SET(ctx->sockfd, &readfds);
396
397         nextpdu = coap_peek_next(ctx);
398
399         coap_ticks(&now);
400         while (nextpdu && nextpdu->t <= now - ctx->sendqueue_basetime)
401         {
402             coap_retransmit(ctx, coap_pop_next(ctx));
403             nextpdu = coap_peek_next(ctx);
404         }
405
406         if (nextpdu && nextpdu->t <= COAP_RESOURCE_CHECK_TIME)
407         {
408             /* set timeout if there is a pdu to send before our automatic timeout occurs */
409             tv.tv_usec = ((nextpdu->t) % COAP_TICKS_PER_SECOND) * 1000000 / COAP_TICKS_PER_SECOND;
410             tv.tv_sec = (nextpdu->t) / COAP_TICKS_PER_SECOND;
411             timeout = &tv;
412         }
413         else
414         {
415             tv.tv_usec = 0;
416             tv.tv_sec = COAP_RESOURCE_CHECK_TIME;
417             timeout = &tv;
418         }
419         result = select(FD_SETSIZE, &readfds, 0, 0, timeout);
420
421         if (result < 0)
422         { /* error */
423             if (errno != EINTR)
424                 perror("select");
425         }
426         else if (result > 0)
427         { /* read from socket */
428             if (FD_ISSET(ctx->sockfd, &readfds))
429             {
430                 coap_read(ctx); /* read received data */
431                 coap_dispatch(ctx); /* and dispatch PDUs from receivequeue */
432             }
433         }
434         else
435         { /* timeout */
436             if (time_resource)
437             {
438                 time_resource->dirty = 1;
439             }
440         }
441
442 #ifndef WITHOUT_ASYNC
443         /* check if we have to send asynchronous responses */
444         check_async(ctx, now);
445 #endif /* WITHOUT_ASYNC */
446
447 #ifndef WITHOUT_OBSERVE
448         /* check if we have to send observe notifications */
449         coap_check_notify(ctx);
450 #endif /* WITHOUT_OBSERVE */
451     }
452
453     coap_free_context(ctx);
454
455     return 0;
456 }