Initial merge-commit of the OIC code. Should successfully do discovery for single...
[platform/upstream/iotivity.git] / csdk / libcoap-4.1.1 / examples / client.c
1 /* coap-client -- simple CoAP client
2  *
3  * Copyright (C) 2010--2013 Olaf Bergmann <bergmann@tzi.org>
4  *
5  * This file is part of the CoAP library libcoap. Please see
6  * README for terms of use.
7  */
8
9 #include "config.h"
10
11 #include <string.h>
12 #include <stdlib.h>
13 #include <unistd.h>
14 #include <stdio.h>
15 #include <ctype.h>
16 #include <sys/select.h>
17 #include <sys/types.h>
18 #include <sys/stat.h>
19 #include <sys/socket.h>
20 #include <netinet/in.h>
21 #include <arpa/inet.h>
22 #include <netdb.h>
23 #include <logger.h>
24
25 #include "coap.h"
26
27 int flags = 0;
28
29 static unsigned char _token_data[8];
30 str the_token = { 0, _token_data };
31
32 #define MOD_NAME ("CoAP-Client")
33 #define FLAGS_BLOCK 0x01
34
35 static coap_list_t *optlist = NULL;
36 /* Request URI.
37  * TODO: associate the resources with transaction id and make it expireable */
38 static coap_uri_t uri;
39 static str proxy = { 0, NULL };
40 static unsigned short proxy_port = COAP_DEFAULT_PORT;
41
42 /* reading is done when this flag is set */
43 static int ready = 0;
44
45 static str output_file = { 0, NULL }; /* output file name */
46 static FILE *file = NULL;       /* output file stream */
47
48 static str payload = { 0, NULL }; /* optional payload to send */
49
50 unsigned char msgtype = COAP_MESSAGE_CON; /* usually, requests are sent confirmable */
51
52 typedef unsigned char method_t;
53 method_t method = 1;            /* the method we are using in our requests */
54
55 coap_block_t block = { .num = 0, .m = 0, .szx = 6 };
56
57 unsigned int wait_seconds = 90; /* default timeout in seconds */
58 coap_tick_t max_wait;           /* global timeout (changed by set_timeout()) */
59
60 unsigned int obs_seconds = 30;  /* default observe time */
61 coap_tick_t obs_wait = 0;       /* timeout for current subscription */
62
63 #define min(a,b) ((a) < (b) ? (a) : (b))
64
65 static inline void
66 set_timeout(coap_tick_t *timer, const unsigned int seconds) {
67   coap_ticks(timer);
68   *timer += seconds * COAP_TICKS_PER_SECOND;
69 }
70
71 int
72 append_to_output(const unsigned char *data, size_t len) {
73   size_t written;
74
75   if (!file) {
76     if (!output_file.s || (output_file.length && output_file.s[0] == '-'))
77       file = stdout;
78     else {
79       if (!(file = fopen((char *)output_file.s, "w"))) {
80         perror("fopen");
81         return -1;
82       }
83     }
84   }
85
86   do {
87     written = fwrite(data, 1, len, file);
88     len -= written;
89     data += written;
90   } while ( written && len );
91   fflush(file);
92
93   return 0;
94 }
95
96 void
97 close_output() {
98   if (file) {
99
100     /* add a newline before closing in case were writing to stdout */
101     if (!output_file.s || (output_file.length && output_file.s[0] == '-'))
102       fwrite("\n", 1, 1, file);
103
104     fflush(file);
105     fclose(file);
106   }
107 }
108
109 coap_pdu_t *
110 new_ack( coap_context_t  *ctx, coap_queue_t *node ) {
111   coap_pdu_t *pdu = coap_new_pdu();
112   (void)ctx;
113
114   if (pdu) {
115     pdu->hdr->type = COAP_MESSAGE_ACK;
116     pdu->hdr->code = 0;
117     pdu->hdr->id = node->pdu->hdr->id;
118   }
119
120   return pdu;
121 }
122
123 coap_pdu_t *
124 new_response( coap_context_t  *ctx, coap_queue_t *node, unsigned int code ) {
125   coap_pdu_t *pdu = new_ack(ctx, node);
126
127   if (pdu)
128     pdu->hdr->code = code;
129
130   return pdu;
131 }
132
133 coap_pdu_t *
134 coap_new_request(coap_context_t *ctx, method_t m, coap_list_t *options ) {
135   coap_pdu_t *pdu;
136   coap_list_t *opt;
137
138   if ( ! ( pdu = coap_new_pdu() ) )
139     return NULL;
140
141   pdu->hdr->type = msgtype;
142   pdu->hdr->id = coap_new_message_id(ctx);
143   pdu->hdr->code = m;
144
145   pdu->hdr->token_length = the_token.length;
146   if ( !coap_add_token(pdu, the_token.length, the_token.s)) {
147     debug("cannot add token to request\n");
148   }
149
150   coap_show_pdu(pdu);
151
152   for (opt = options; opt; opt = opt->next) {
153     coap_add_option(pdu, COAP_OPTION_KEY(*(coap_option *)opt->data),
154                     COAP_OPTION_LENGTH(*(coap_option *)opt->data),
155                     COAP_OPTION_DATA(*(coap_option *)opt->data));
156   }
157
158   if (payload.length) {
159     if ((flags & FLAGS_BLOCK) == 0)
160       coap_add_data(pdu, payload.length, payload.s);
161     else
162       coap_add_block(pdu, payload.length, payload.s, block.num, block.szx);
163   }
164
165   return pdu;
166 }
167
168 coap_tid_t
169 clear_obs(coap_context_t *ctx, const coap_address_t *remote) {
170   coap_list_t *option;
171   coap_pdu_t *pdu;
172   coap_tid_t tid = COAP_INVALID_TID;
173
174   /* create bare PDU w/o any option  */
175   pdu = coap_new_request(ctx, COAP_REQUEST_GET, NULL);
176
177   if (pdu) {
178     /* FIXME: add token */
179     /* add URI components from optlist */
180     for (option = optlist; option; option = option->next ) {
181       switch (COAP_OPTION_KEY(*(coap_option *)option->data)) {
182       case COAP_OPTION_URI_HOST :
183       case COAP_OPTION_URI_PORT :
184       case COAP_OPTION_URI_PATH :
185       case COAP_OPTION_URI_QUERY :
186         coap_add_option ( pdu, COAP_OPTION_KEY(*(coap_option *)option->data),
187                           COAP_OPTION_LENGTH(*(coap_option *)option->data),
188                           COAP_OPTION_DATA(*(coap_option *)option->data) );
189         break;
190       default:
191         ;                       /* skip other options */
192       }
193     }
194
195     if (pdu->hdr->type == COAP_MESSAGE_CON)
196       tid = coap_send_confirmed(ctx, remote, pdu);
197     else
198       tid = coap_send(ctx, remote, pdu);
199
200     if (tid == COAP_INVALID_TID) {
201       debug("clear_obs: error sending new request");
202       coap_delete_pdu(pdu);
203     } else if (pdu->hdr->type != COAP_MESSAGE_CON)
204       coap_delete_pdu(pdu);
205   }
206   return tid;
207 }
208
209 int
210 resolve_address(const str *server, struct sockaddr *dst) {
211
212   struct addrinfo *res, *ainfo;
213   struct addrinfo hints;
214   static char addrstr[256];
215   int error, len=-1;
216
217
218   memset(addrstr, 0, sizeof(addrstr));
219   if (server->length)
220     memcpy(addrstr, server->s, server->length);
221   else
222     memcpy(addrstr, "localhost", 9);
223
224   OC_LOG_V(DEBUG, MOD_NAME, "Line %d, server %s", __LINE__, addrstr);
225
226   memset ((char *)&hints, 0, sizeof(hints));
227   hints.ai_socktype = SOCK_DGRAM;
228   hints.ai_family = AF_UNSPEC;
229
230   error = getaddrinfo(addrstr, NULL, &hints, &res);
231
232   if (error != 0) {
233     fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(error));
234     return error;
235   }
236
237   for (ainfo = res; ainfo != NULL; ainfo = ainfo->ai_next) {
238     switch (ainfo->ai_family) {
239     case AF_INET6:
240     case AF_INET:
241       len = ainfo->ai_addrlen;
242       memcpy(dst, ainfo->ai_addr, len);
243       goto finish;
244     default:
245       ;
246     }
247   }
248
249  finish:
250   freeaddrinfo(res);
251   return len;
252 }
253
254 static inline coap_opt_t *
255 get_block(coap_pdu_t *pdu, coap_opt_iterator_t *opt_iter) {
256   coap_opt_filter_t f;
257
258   assert(pdu);
259
260   memset(f, 0, sizeof(coap_opt_filter_t));
261   coap_option_setb(f, COAP_OPTION_BLOCK1);
262   coap_option_setb(f, COAP_OPTION_BLOCK2);
263
264   coap_option_iterator_init(pdu, opt_iter, f);
265   return coap_option_next(opt_iter);
266 }
267
268 #define HANDLE_BLOCK1(Pdu)                                              \
269   ((method == COAP_REQUEST_PUT || method == COAP_REQUEST_POST) &&       \
270    ((flags & FLAGS_BLOCK) == 0) &&                                      \
271    ((Pdu)->hdr->code == COAP_RESPONSE_CODE(201) ||                      \
272     (Pdu)->hdr->code == COAP_RESPONSE_CODE(204)))
273
274 inline int
275 check_token(coap_pdu_t *received) {
276   return received->hdr->token_length == the_token.length &&
277     memcmp(received->hdr->token, the_token.s, the_token.length) == 0;
278 }
279
280 void
281 message_handler(struct coap_context_t  *ctx,
282                 const coap_address_t *remote,
283                 coap_pdu_t *sent,
284                 coap_pdu_t *received,
285                 const coap_tid_t id) {
286
287   coap_pdu_t *pdu = NULL;
288   coap_opt_t *block_opt;
289   coap_opt_iterator_t opt_iter;
290   unsigned char buf[4];
291   coap_list_t *option;
292   size_t len;
293   unsigned char *databuf;
294   coap_tid_t tid;
295   (void)id;
296
297 #ifndef NDEBUG
298   if (LOG_DEBUG <= coap_get_log_level()) {
299     debug("** process incoming %d.%02d response:\n",
300           (received->hdr->code >> 5), received->hdr->code & 0x1F);
301     coap_show_pdu(received);
302   }
303 #endif
304
305   /* check if this is a response to our original request */
306   if (!check_token(received)) {
307     /* drop if this was just some message, or send RST in case of notification */
308     if (!sent && (received->hdr->type == COAP_MESSAGE_CON ||
309                   received->hdr->type == COAP_MESSAGE_NON))
310       coap_send_rst(ctx, remote, received);
311     return;
312   }
313
314   switch (received->hdr->type) {
315   case COAP_MESSAGE_CON:
316     /* acknowledge received response if confirmable (TODO: check Token) */
317     coap_send_ack(ctx, remote, received);
318     break;
319   case COAP_MESSAGE_RST:
320     info("got RST\n");
321     return;
322   default:
323     ;
324   }
325
326   /* output the received data, if any */
327   if (received->hdr->code == COAP_RESPONSE_CODE(205)) {
328
329     /* set obs timer if we have successfully subscribed a resource */
330     if (sent && coap_check_option(received, COAP_OPTION_SUBSCRIPTION, &opt_iter)) {
331       debug("observation relationship established, set timeout to %d\n", obs_seconds);
332       set_timeout(&obs_wait, obs_seconds);
333     }
334
335     /* Got some data, check if block option is set. Behavior is undefined if
336      * both, Block1 and Block2 are present. */
337     block_opt = get_block(received, &opt_iter);
338     if (!block_opt) {
339       /* There is no block option set, just read the data and we are done. */
340       if (coap_get_data(received, &len, &databuf))
341         append_to_output(databuf, len);
342     } else {
343       unsigned short blktype = opt_iter.type;
344
345       /* TODO: check if we are looking at the correct block number */
346       if (coap_get_data(received, &len, &databuf))
347         append_to_output(databuf, len);
348
349       if (COAP_OPT_BLOCK_MORE(block_opt)) {
350         /* more bit is set */
351         debug("found the M bit, block size is %u, block nr. %u\n",
352               COAP_OPT_BLOCK_SZX(block_opt), coap_opt_block_num(block_opt));
353
354         /* create pdu with request for next block */
355         pdu = coap_new_request(ctx, method, NULL); /* first, create bare PDU w/o any option  */
356         if ( pdu ) {
357           /* add URI components from optlist */
358           for (option = optlist; option; option = option->next ) {
359             switch (COAP_OPTION_KEY(*(coap_option *)option->data)) {
360             case COAP_OPTION_URI_HOST :
361             case COAP_OPTION_URI_PORT :
362             case COAP_OPTION_URI_PATH :
363             case COAP_OPTION_URI_QUERY :
364               coap_add_option ( pdu, COAP_OPTION_KEY(*(coap_option *)option->data),
365                                 COAP_OPTION_LENGTH(*(coap_option *)option->data),
366                                 COAP_OPTION_DATA(*(coap_option *)option->data) );
367               break;
368             default:
369               ;                 /* skip other options */
370             }
371           }
372
373           /* finally add updated block option from response, clear M bit */
374           /* blocknr = (blocknr & 0xfffffff7) + 0x10; */
375           debug("query block %d\n", (coap_opt_block_num(block_opt) + 1));
376           coap_add_option(pdu, blktype, coap_encode_var_bytes(buf,
377               ((coap_opt_block_num(block_opt) + 1) << 4) |
378               COAP_OPT_BLOCK_SZX(block_opt)), buf);
379
380           if (received->hdr->type == COAP_MESSAGE_CON)
381             tid = coap_send_confirmed(ctx, remote, pdu);
382           else
383             tid = coap_send(ctx, remote, pdu);
384
385           if (tid == COAP_INVALID_TID) {
386             debug("message_handler: error sending new request");
387             coap_delete_pdu(pdu);
388           } else {
389             set_timeout(&max_wait, wait_seconds);
390             if (received->hdr->type != COAP_MESSAGE_CON)
391               coap_delete_pdu(pdu);
392           }
393
394           return;
395         }
396       }
397     }
398   } else {                      /* no 2.05 */
399
400     /* check if an error was signaled and output payload if so */
401     if (COAP_RESPONSE_CLASS(received->hdr->code) >= 4) {
402       fprintf(stderr, "%d.%02d",
403               (received->hdr->code >> 5), received->hdr->code & 0x1F);
404       if (coap_get_data(received, &len, &databuf)) {
405       fprintf(stderr, " ");
406         while(len--)
407           fprintf(stderr, "%c", *databuf++);
408       }
409       fprintf(stderr, "\n");
410     }
411
412   }
413
414   /* finally send new request, if needed */
415   if (pdu && coap_send(ctx, remote, pdu) == COAP_INVALID_TID) {
416     debug("message_handler: error sending response");
417   }
418   coap_delete_pdu(pdu);
419
420   /* our job is done, we can exit at any time */
421   ready = coap_check_option(received, COAP_OPTION_SUBSCRIPTION, &opt_iter) == NULL;
422 }
423
424 void
425 usage( const char *program, const char *version) {
426   const char *p;
427
428   p = strrchr( program, '/' );
429   if ( p )
430     program = ++p;
431
432   fprintf( stderr, "%s v%s -- a small CoAP implementation\n"
433            "(c) 2010-2013 Olaf Bergmann <bergmann@tzi.org>\n\n"
434            "usage: %s [-A type...] [-t type] [-b [num,]size] [-B seconds] [-e text]\n"
435            "\t\t[-g group] [-m method] [-N] [-o file] [-P addr[:port]] [-p port]\n"
436            "\t\t[-s duration] [-O num,text] [-T string] [-v num] URI\n\n"
437            "\tURI can be an absolute or relative coap URI,\n"
438            "\t-A type...\taccepted media types as comma-separated list of\n"
439            "\t\t\tsymbolic or numeric values\n"
440            "\t-t type\t\tcontent type for given resource for PUT/POST\n"
441            "\t-b [num,]size\tblock size to be used in GET/PUT/POST requests\n"
442            "\t       \t\t(value must be a multiple of 16 not larger than 1024)\n"
443            "\t       \t\tIf num is present, the request chain will start at\n"
444            "\t       \t\tblock num\n"
445            "\t-B seconds\tbreak operation after waiting given seconds\n"
446            "\t\t\t(default is %d)\n"
447            "\t-e text\t\tinclude text as payload (use percent-encoding for\n"
448            "\t\t\tnon-ASCII characters)\n"
449            "\t-f file\t\tfile to send with PUT/POST (use '-' for STDIN)\n"
450            "\t-g group\tjoin the given multicast group\n"
451            "\t-m method\trequest method (get|put|post|delete), default is 'get'\n"
452            "\t-N\t\tsend NON-confirmable message\n"
453            "\t-o file\t\toutput received data to this file (use '-' for STDOUT)\n"
454            "\t-p port\t\tlisten on specified port\n"
455            "\t-s duration\tsubscribe for given duration [s]\n"
456            "\t-v num\t\tverbosity level (default: 3)\n"
457            "\t-O num,text\tadd option num with contents text to request\n"
458            "\t-P addr[:port]\tuse proxy (automatically adds Proxy-Uri option to\n"
459            "\t\t\trequest)\n"
460            "\t-T token\tinclude specified token\n"
461            "\n"
462            "examples:\n"
463            "\tcoap-client -m get coap://[::1]/\n"
464            "\tcoap-client -m get coap://[::1]/.well-known/core\n"
465            "\tcoap-client -m get -T cafe coap://[::1]/time\n"
466            "\techo 1000 | coap-client -m put -T cafe coap://[::1]/time -f -\n"
467            ,program, version, program, wait_seconds);
468 }
469
470 int
471 join( coap_context_t *ctx, char *group_name ){
472   struct ipv6_mreq mreq;
473   struct addrinfo   *reslocal = NULL, *resmulti = NULL, hints, *ainfo;
474   int result = -1;
475
476   /* we have to resolve the link-local interface to get the interface id */
477   memset(&hints, 0, sizeof(hints));
478   hints.ai_family = AF_INET6;
479   hints.ai_socktype = SOCK_DGRAM;
480
481   result = getaddrinfo("::", NULL, &hints, &reslocal);
482   if ( result < 0 ) {
483     fprintf(stderr, "join: cannot resolve link-local interface: %s\n",
484             gai_strerror(result));
485     goto finish;
486   }
487
488   /* get the first suitable interface identifier */
489   for (ainfo = reslocal; ainfo != NULL; ainfo = ainfo->ai_next) {
490     if ( ainfo->ai_family == AF_INET6 ) {
491       mreq.ipv6mr_interface =
492               ((struct sockaddr_in6 *)ainfo->ai_addr)->sin6_scope_id;
493       break;
494     }
495   }
496
497   memset(&hints, 0, sizeof(hints));
498   hints.ai_family = AF_INET6;
499   hints.ai_socktype = SOCK_DGRAM;
500
501   /* resolve the multicast group address */
502   result = getaddrinfo(group_name, NULL, &hints, &resmulti);
503
504   if ( result < 0 ) {
505     fprintf(stderr, "join: cannot resolve multicast address: %s\n",
506             gai_strerror(result));
507     goto finish;
508   }
509
510   for (ainfo = resmulti; ainfo != NULL; ainfo = ainfo->ai_next) {
511     if ( ainfo->ai_family == AF_INET6 ) {
512       mreq.ipv6mr_multiaddr =
513         ((struct sockaddr_in6 *)ainfo->ai_addr)->sin6_addr;
514       break;
515     }
516   }
517
518   result = setsockopt( ctx->sockfd, IPPROTO_IPV6, IPV6_JOIN_GROUP,
519                        (char *)&mreq, sizeof(mreq) );
520   if ( result < 0 )
521     perror("join: setsockopt");
522
523  finish:
524   freeaddrinfo(resmulti);
525   freeaddrinfo(reslocal);
526
527   return result;
528 }
529
530 int
531 order_opts(void *a, void *b) {
532   if (!a || !b)
533     return a < b ? -1 : 1;
534
535   if (COAP_OPTION_KEY(*(coap_option *)a) < COAP_OPTION_KEY(*(coap_option *)b))
536     return -1;
537
538   return COAP_OPTION_KEY(*(coap_option *)a) == COAP_OPTION_KEY(*(coap_option *)b);
539 }
540
541
542 coap_list_t *
543 new_option_node(unsigned short key, unsigned int length, unsigned char *data) {
544   coap_option *option;
545   coap_list_t *node;
546
547   option = coap_malloc(sizeof(coap_option) + length);
548   if ( !option )
549     goto error;
550
551   COAP_OPTION_KEY(*option) = key;
552   COAP_OPTION_LENGTH(*option) = length;
553   memcpy(COAP_OPTION_DATA(*option), data, length);
554
555   /* we can pass NULL here as delete function since option is released automatically  */
556   node = coap_new_listnode(option, NULL);
557
558   if ( node )
559     return node;
560
561  error:
562   perror("new_option_node: malloc");
563   coap_free( option );
564   return NULL;
565 }
566
567 typedef struct {
568   unsigned char code;
569   char *media_type;
570 } content_type_t;
571
572 void
573 cmdline_content_type(char *arg, unsigned short key) {
574   static content_type_t content_types[] = {
575     {  0, "plain" },
576     {  0, "text/plain" },
577     { 40, "link" },
578     { 40, "link-format" },
579     { 40, "application/link-format" },
580     { 41, "xml" },
581     { 42, "binary" },
582     { 42, "octet-stream" },
583     { 42, "application/octet-stream" },
584     { 47, "exi" },
585     { 47, "application/exi" },
586     { 50, "json" },
587     { 50, "application/json" },
588     { 255, NULL }
589   };
590   coap_list_t *node;
591   unsigned char i, value[10];
592   int valcnt = 0;
593   unsigned char buf[2];
594   char *p, *q = arg;
595
596   while (q && *q) {
597     p = strchr(q, ',');
598
599     if (isdigit(*q)) {
600       if (p)
601         *p = '\0';
602       value[valcnt++] = atoi(q);
603     } else {
604       for (i=0; content_types[i].media_type &&
605              strncmp(q,content_types[i].media_type, p ? p-q : strlen(q)) != 0 ;
606            ++i)
607         ;
608
609       if (content_types[i].media_type) {
610         value[valcnt] = content_types[i].code;
611         valcnt++;
612       } else {
613         warn("W: unknown content-type '%s'\n",arg);
614       }
615     }
616
617     if (!p || key == COAP_OPTION_CONTENT_TYPE)
618       break;
619
620     q = p+1;
621   }
622
623   for (i = 0; i < valcnt; ++i) {
624     node = new_option_node(key, coap_encode_var_bytes(buf, value[i]), buf);
625     if (node)
626       coap_insert( &optlist, node, order_opts );
627   }
628 }
629
630 void
631 cmdline_uri(char *arg) {
632   unsigned char portbuf[2];
633 #define BUFSIZE 40
634   unsigned char _buf[BUFSIZE];
635   unsigned char *buf = _buf;
636   size_t buflen;
637   int res;
638
639   if (proxy.length) {           /* create Proxy-Uri from argument */
640     size_t len = strlen(arg);
641     while (len > 270) {
642       coap_insert(&optlist,
643                   new_option_node(COAP_OPTION_PROXY_URI,
644                                   270, (unsigned char *)arg),
645                   order_opts);
646       len -= 270;
647       arg += 270;
648     }
649
650     coap_insert(&optlist,
651                 new_option_node(COAP_OPTION_PROXY_URI,
652                                 len, (unsigned char *)arg),
653                 order_opts);
654   } else {                      /* split arg into Uri-* options */
655     coap_split_uri((unsigned char *)arg, strlen(arg), &uri );
656
657     if (uri.port != COAP_DEFAULT_PORT) {
658       coap_insert( &optlist,
659                    new_option_node(COAP_OPTION_URI_PORT,
660                                    coap_encode_var_bytes(portbuf, uri.port),
661                                  portbuf),
662                    order_opts);
663     }
664
665     if (uri.path.length) {
666       buflen = BUFSIZE;
667       res = coap_split_path(uri.path.s, uri.path.length, buf, &buflen);
668
669       while (res--) {
670         coap_insert(&optlist, new_option_node(COAP_OPTION_URI_PATH,
671                                               COAP_OPT_LENGTH(buf),
672                                               COAP_OPT_VALUE(buf)),
673                     order_opts);
674
675         buf += COAP_OPT_SIZE(buf);
676       }
677     }
678
679     if (uri.query.length) {
680       buflen = BUFSIZE;
681       buf = _buf;
682       res = coap_split_query(uri.query.s, uri.query.length, buf, &buflen);
683
684       while (res--) {
685         coap_insert(&optlist, new_option_node(COAP_OPTION_URI_QUERY,
686                                               COAP_OPT_LENGTH(buf),
687                                               COAP_OPT_VALUE(buf)),
688                     order_opts);
689
690         buf += COAP_OPT_SIZE(buf);
691       }
692     }
693   }
694 }
695
696 int
697 cmdline_blocksize(char *arg) {
698   unsigned short size;
699
700  again:
701   size = 0;
702   while(*arg && *arg != ',')
703     size = size * 10 + (*arg++ - '0');
704
705   if (*arg == ',') {
706     arg++;
707     block.num = size;
708     goto again;
709   }
710
711   if (size)
712     block.szx = (coap_fls(size >> 4) - 1) & 0x07;
713
714   flags |= FLAGS_BLOCK;
715   return 1;
716 }
717
718 /* Called after processing the options from the commandline to set
719  * Block1 or Block2 depending on method. */
720 void
721 set_blocksize() {
722   static unsigned char buf[4];  /* hack: temporarily take encoded bytes */
723   unsigned short opt;
724
725   if (method != COAP_REQUEST_DELETE) {
726     opt = method == COAP_REQUEST_GET ? COAP_OPTION_BLOCK2 : COAP_OPTION_BLOCK1;
727
728     coap_insert(&optlist, new_option_node(opt,
729                 coap_encode_var_bytes(buf, (block.num << 4 | block.szx)), buf),
730                 order_opts);
731   }
732 }
733
734 void
735 cmdline_subscribe(char *arg) {
736   (void)arg;
737   obs_seconds = atoi(optarg);
738   coap_insert(&optlist, new_option_node(COAP_OPTION_SUBSCRIPTION, 0, NULL),
739               order_opts);
740 }
741
742 int
743 cmdline_proxy(char *arg) {
744   char *proxy_port_str = strrchr((const char *)arg, ':'); /* explicit port ? */
745   if (proxy_port_str) {
746     char *ipv6_delimiter = strrchr((const char *)arg, ']');
747     if (!ipv6_delimiter) {
748       if (proxy_port_str == strchr((const char *)arg, ':')) {
749         /* host:port format - host not in ipv6 hexadecimal string format */
750         *proxy_port_str++ = '\0'; /* split */
751         proxy_port = atoi(proxy_port_str);
752       }
753     } else {
754       arg = strchr((const char *)arg, '[');
755       if (!arg) return 0;
756       arg++;
757       *ipv6_delimiter = '\0'; /* split */
758       if (ipv6_delimiter + 1 == proxy_port_str++) {
759         /* [ipv6 address]:port */
760         proxy_port = atoi(proxy_port_str);
761       }
762     }
763   }
764
765   proxy.length = strlen(arg);
766   if ( (proxy.s = coap_malloc(proxy.length + 1)) == NULL) {
767     proxy.length = 0;
768     return 0;
769   }
770
771   memcpy(proxy.s, arg, proxy.length+1);
772   return 1;
773 }
774
775 inline void
776 cmdline_token(char *arg) {
777   strncpy((char *)the_token.s, arg, min(sizeof(_token_data), strlen(arg)));
778   the_token.length = strlen(arg);
779 }
780
781 void
782 cmdline_option(char *arg) {
783   unsigned int num = 0;
784
785   while (*arg && *arg != ',') {
786     num = num * 10 + (*arg - '0');
787     ++arg;
788   }
789   if (*arg == ',')
790     ++arg;
791
792   coap_insert( &optlist, new_option_node(num,
793                                          strlen(arg),
794                                          (unsigned char *)arg), order_opts);
795 }
796
797 extern int  check_segment(const unsigned char *s, size_t length);
798 extern void decode_segment(const unsigned char *seg, size_t length, unsigned char *buf);
799
800 int
801 cmdline_input(char *text, str *buf) {
802   int len;
803   len = check_segment((unsigned char *)text, strlen(text));
804
805   if (len < 0)
806     return 0;
807
808   buf->s = (unsigned char *)coap_malloc(len);
809   if (!buf->s)
810     return 0;
811
812   buf->length = len;
813   decode_segment((unsigned char *)text, strlen(text), buf->s);
814   return 1;
815 }
816
817 int
818 cmdline_input_from_file(char *filename, str *buf) {
819   FILE *inputfile = NULL;
820   size_t len;
821   int result = 1;
822   struct stat statbuf;
823
824   if (!filename || !buf)
825     return 0;
826
827   if (filename[0] == '-' && !filename[1]) { /* read from stdin */
828     buf->length = 20000;
829     buf->s = (unsigned char *)coap_malloc(buf->length);
830     if (!buf->s)
831       return 0;
832
833     inputfile = stdin;
834   } else {
835     /* read from specified input file */
836     if (stat(filename, &statbuf) < 0) {
837       perror("cmdline_input_from_file: stat");
838       return 0;
839     }
840
841     buf->length = statbuf.st_size;
842     buf->s = (unsigned char *)coap_malloc(buf->length);
843     if (!buf->s)
844       return 0;
845
846     inputfile = fopen(filename, "r");
847     if ( !inputfile ) {
848       perror("cmdline_input_from_file: fopen");
849       coap_free(buf->s);
850       return 0;
851     }
852   }
853
854   len = fread(buf->s, 1, buf->length, inputfile);
855
856   if (len < buf->length) {
857     if (ferror(inputfile) != 0) {
858       perror("cmdline_input_from_file: fread");
859       coap_free(buf->s);
860       buf->length = 0;
861       buf->s = NULL;
862       result = 0;
863     } else {
864       buf->length = len;
865     }
866   }
867
868   if (inputfile != stdin)
869     fclose(inputfile);
870
871   return result;
872 }
873
874 method_t
875 cmdline_method(char *arg) {
876   static char *methods[] =
877     { 0, "get", "post", "put", "delete", 0};
878   unsigned char i;
879
880   for (i=1; methods[i] && strcasecmp(arg,methods[i]) != 0 ; ++i)
881     ;
882
883   return i;          /* note that we do not prevent illegal methods */
884 }
885
886 coap_context_t *
887 get_context(const char *node, const char *port) {
888   coap_context_t *ctx = NULL;
889   int s;
890   struct addrinfo hints;
891   struct addrinfo *result, *rp;
892
893   memset(&hints, 0, sizeof(struct addrinfo));
894   hints.ai_family = AF_UNSPEC;    /* Allow IPv4 or IPv6 */
895   hints.ai_socktype = SOCK_DGRAM; /* Coap uses UDP */
896 #ifndef __ANDROID__
897   hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST | AI_NUMERICSERV | AI_ALL;
898 #endif //__ANDROID__
899
900
901   OC_LOG_V(DEBUG, MOD_NAME, "Line %d, node %s, port %d", __LINE__, node, port);
902   s = getaddrinfo(node, port, &hints, &result);
903   if ( s != 0 ) {
904     fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(s));
905     return NULL;
906   }
907
908   /* iterate through results until success */
909   for (rp = result; rp != NULL; rp = rp->ai_next) {
910     coap_address_t addr;
911
912     if (rp->ai_addrlen <= sizeof(addr.addr)) {
913       coap_address_init(&addr);
914       addr.size = rp->ai_addrlen;
915       memcpy(&addr.addr, rp->ai_addr, rp->ai_addrlen);
916
917       ctx = coap_new_context(&addr);
918       if (ctx) {
919         /* TODO: output address:port for successful binding */
920         goto finish;
921       }
922     }
923   }
924
925   fprintf(stderr, "no context available for interface '%s'\n", node);
926
927  finish:
928   freeaddrinfo(result);
929   return ctx;
930 }
931
932 int
933 main(int argc, char **argv) {
934   coap_context_t  *ctx = NULL;
935   coap_address_t dst;
936   static char addr[INET6_ADDRSTRLEN];
937   void *addrptr = NULL;
938   fd_set readfds;
939   struct timeval tv;
940   int result;
941   coap_tick_t now;
942   coap_queue_t *nextpdu;
943   coap_pdu_t  *pdu;
944   static str server;
945   unsigned short port = COAP_DEFAULT_PORT;
946   char port_str[NI_MAXSERV] = "0";
947   int opt, res;
948   char *group = NULL;
949   coap_log_t log_level = LOG_WARNING;
950   coap_tid_t tid = COAP_INVALID_TID;
951
952   while ((opt = getopt(argc, argv, "Nb:e:f:g:m:p:s:t:o:v:A:B:O:P:T:")) != -1) {
953     switch (opt) {
954     case 'b' :
955       cmdline_blocksize(optarg);
956       break;
957     case 'B' :
958       wait_seconds = atoi(optarg);
959       break;
960     case 'e' :
961       if (!cmdline_input(optarg,&payload))
962         payload.length = 0;
963       break;
964     case 'f' :
965       if (!cmdline_input_from_file(optarg,&payload))
966         payload.length = 0;
967       break;
968     case 'g' :
969       group = optarg;
970       break;
971     case 'p' :
972       strncpy(port_str, optarg, NI_MAXSERV-1);
973       port_str[NI_MAXSERV - 1] = '\0';
974       break;
975     case 'm' :
976       method = cmdline_method(optarg);
977       break;
978     case 'N' :
979       msgtype = COAP_MESSAGE_NON;
980       break;
981     case 's' :
982       cmdline_subscribe(optarg);
983       break;
984     case 'o' :
985       output_file.length = strlen(optarg);
986       output_file.s = (unsigned char *)coap_malloc(output_file.length + 1);
987
988       if (!output_file.s) {
989         fprintf(stderr, "cannot set output file: insufficient memory\n");
990         exit(-1);
991       } else {
992         /* copy filename including trailing zero */
993         memcpy(output_file.s, optarg, output_file.length + 1);
994       }
995       break;
996     case 'A' :
997       cmdline_content_type(optarg,COAP_OPTION_ACCEPT);
998       break;
999     case 't' :
1000       cmdline_content_type(optarg,COAP_OPTION_CONTENT_TYPE);
1001       break;
1002     case 'O' :
1003       cmdline_option(optarg);
1004       break;
1005     case 'P' :
1006       if (!cmdline_proxy(optarg)) {
1007         fprintf(stderr, "error specifying proxy address\n");
1008         exit(-1);
1009       }
1010       break;
1011     case 'T' :
1012       cmdline_token(optarg);
1013       break;
1014     case 'v' :
1015       log_level = strtol(optarg, NULL, 10);
1016       break;
1017     default:
1018       usage( argv[0], PACKAGE_VERSION );
1019       exit( 1 );
1020     }
1021   }
1022
1023   coap_set_log_level(log_level);
1024
1025   if ( optind < argc )
1026     cmdline_uri( argv[optind] );
1027   else {
1028     usage( argv[0], PACKAGE_VERSION );
1029     exit( 1 );
1030   }
1031
1032   if (proxy.length) {
1033     server = proxy;
1034     port = proxy_port;
1035   } else {
1036     server = uri.host;
1037     port = uri.port;
1038   }
1039
1040   /* resolve destination address where server should be sent */
1041   res = resolve_address(&server, &dst.addr.sa);
1042
1043   if (res < 0) {
1044     fprintf(stderr, "failed to resolve address\n");
1045     exit(-1);
1046   }
1047
1048   dst.size = res;
1049   dst.addr.sin.sin_port = htons(port);
1050
1051   /* add Uri-Host if server address differs from uri.host */
1052
1053   switch (dst.addr.sa.sa_family) {
1054   case AF_INET:
1055     addrptr = &dst.addr.sin.sin_addr;
1056
1057     /* create context for IPv4 */
1058     ctx = get_context("0.0.0.0", port_str);
1059     break;
1060   case AF_INET6:
1061     addrptr = &dst.addr.sin6.sin6_addr;
1062
1063     /* create context for IPv6 */
1064     ctx = get_context("::", port_str);
1065     break;
1066   default:
1067     ;
1068   }
1069
1070   if (!ctx) {
1071     coap_log(LOG_EMERG, "cannot create context\n");
1072     return -1;
1073   }
1074
1075   coap_register_option(ctx, COAP_OPTION_BLOCK2);
1076   coap_register_response_handler(ctx, message_handler);
1077
1078   /* join multicast group if requested at command line */
1079   if (group)
1080     join(ctx, group);
1081
1082   /* construct CoAP message */
1083
1084   if (!proxy.length && addrptr
1085       && (inet_ntop(dst.addr.sa.sa_family, addrptr, addr, sizeof(addr)) != 0)
1086       && (strlen(addr) != uri.host.length
1087           || memcmp(addr, uri.host.s, uri.host.length) != 0)) {
1088       /* add Uri-Host */
1089
1090     coap_insert(&optlist, new_option_node(COAP_OPTION_URI_HOST,
1091                                           uri.host.length, uri.host.s),
1092                 order_opts);
1093   }
1094
1095   /* set block option if requested at commandline */
1096   if (flags & FLAGS_BLOCK)
1097     set_blocksize();
1098
1099   if (! (pdu = coap_new_request(ctx, method, optlist)))
1100     return -1;
1101
1102 #ifndef NDEBUG
1103   if (LOG_DEBUG <= coap_get_log_level()) {
1104     debug("sending CoAP request:\n");
1105     coap_show_pdu(pdu);
1106   }
1107 #endif
1108
1109   if (pdu->hdr->type == COAP_MESSAGE_CON)
1110     tid = coap_send_confirmed(ctx, &dst, pdu);
1111   else
1112     tid = coap_send(ctx, &dst, pdu);
1113
1114   if (pdu->hdr->type != COAP_MESSAGE_CON || tid == COAP_INVALID_TID)
1115     coap_delete_pdu(pdu);
1116
1117   set_timeout(&max_wait, wait_seconds);
1118   debug("timeout is set to %d seconds\n", wait_seconds);
1119
1120   while ( !(ready && coap_can_exit(ctx)) ) {
1121     FD_ZERO(&readfds);
1122     FD_SET( ctx->sockfd, &readfds );
1123
1124     nextpdu = coap_peek_next( ctx );
1125
1126     coap_ticks(&now);
1127     while (nextpdu && nextpdu->t <= now - ctx->sendqueue_basetime) {
1128       coap_retransmit( ctx, coap_pop_next( ctx ));
1129       nextpdu = coap_peek_next( ctx );
1130     }
1131
1132     if (nextpdu && nextpdu->t < min(obs_wait ? obs_wait : max_wait, max_wait) - now) {
1133       /* set timeout if there is a pdu to send */
1134       tv.tv_usec = ((nextpdu->t) % COAP_TICKS_PER_SECOND) * 1000000 / COAP_TICKS_PER_SECOND;
1135       tv.tv_sec = (nextpdu->t) / COAP_TICKS_PER_SECOND;
1136     } else {
1137       /* check if obs_wait fires before max_wait */
1138       if (obs_wait && obs_wait < max_wait) {
1139         tv.tv_usec = ((obs_wait - now) % COAP_TICKS_PER_SECOND) * 1000000 / COAP_TICKS_PER_SECOND;
1140         tv.tv_sec = (obs_wait - now) / COAP_TICKS_PER_SECOND;
1141       } else {
1142         tv.tv_usec = ((max_wait - now) % COAP_TICKS_PER_SECOND) * 1000000 / COAP_TICKS_PER_SECOND;
1143         tv.tv_sec = (max_wait - now) / COAP_TICKS_PER_SECOND;
1144       }
1145     }
1146
1147     result = select(ctx->sockfd + 1, &readfds, 0, 0, &tv);
1148
1149     if ( result < 0 ) {         /* error */
1150       perror("select");
1151     } else if ( result > 0 ) {  /* read from socket */
1152       if ( FD_ISSET( ctx->sockfd, &readfds ) ) {
1153         coap_read( ctx, ctx->sockfd );  /* read received data */
1154         coap_dispatch( ctx );   /* and dispatch PDUs from receivequeue */
1155       }
1156     } else { /* timeout */
1157       coap_ticks(&now);
1158       if (max_wait <= now) {
1159         info("timeout\n");
1160         break;
1161       }
1162       if (obs_wait && obs_wait <= now) {
1163         debug("clear observation relationship\n");
1164         clear_obs(ctx, &dst); /* FIXME: handle error case COAP_TID_INVALID */
1165
1166         /* make sure that the obs timer does not fire again */
1167         obs_wait = 0;
1168         obs_seconds = 0;
1169       }
1170     }
1171   }
1172
1173   close_output();
1174
1175   coap_free_context( ctx );
1176
1177   return 0;
1178 }