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