libcoap  4.2.1
coap_debug.c
Go to the documentation of this file.
1 /* debug.c -- debug utilities
2  *
3  * Copyright (C) 2010--2012,2014--2019 Olaf Bergmann <bergmann@tzi.org> and others
4  *
5  * This file is part of the CoAP library libcoap. Please see
6  * README for terms of use.
7  */
8 
9 #include "coap_internal.h"
10 
11 #if defined(HAVE_STRNLEN) && defined(__GNUC__) && !defined(_GNU_SOURCE)
12 #define _GNU_SOURCE 1
13 #endif
14 
15 #include <stdarg.h>
16 #include <stdio.h>
17 #include <string.h>
18 #include <ctype.h>
19 
20 #ifdef HAVE_ARPA_INET_H
21 #include <arpa/inet.h>
22 #endif
23 #ifdef HAVE_WS2TCPIP_H
24 #include <ws2tcpip.h>
25 #endif
26 
27 #ifdef HAVE_TIME_H
28 #include <time.h>
29 #endif
30 
31 #ifdef WITH_LWIP
32 # define fprintf(fd, ...) LWIP_PLATFORM_DIAG((__VA_ARGS__))
33 # define fflush(...)
34 #endif
35 
36 #ifdef WITH_CONTIKI
37 # ifndef DEBUG
38 # define DEBUG DEBUG_PRINT
39 # endif /* DEBUG */
40 #include "net/ip/uip-debug.h"
41 #endif
42 
43 static coap_log_t maxlog = LOG_WARNING; /* default maximum log level */
44 
45 static int use_fprintf_for_show_pdu = 1; /* non zero to output with fprintf */
46 
47 const char *coap_package_name(void) {
48  return PACKAGE_NAME;
49 }
50 
51 const char *coap_package_version(void) {
52  return PACKAGE_STRING;
53 }
54 
55 void
56 coap_set_show_pdu_output(int use_fprintf) {
57  use_fprintf_for_show_pdu = use_fprintf;
58 }
59 
62  return maxlog;
63 }
64 
65 void
67  maxlog = level;
68 }
69 
70 /* this array has the same order as the type log_t */
71 static const char *loglevels[] = {
72  "EMRG", "ALRT", "CRIT", "ERR ", "WARN", "NOTE", "INFO", "DEBG", "????", "CIPH"
73 };
74 
75 #ifdef HAVE_TIME_H
76 
77 COAP_STATIC_INLINE size_t
78 print_timestamp(char *s, size_t len, coap_tick_t t) {
79  struct tm *tmp;
80  time_t now = coap_ticks_to_rt(t);
81  tmp = localtime(&now);
82  return strftime(s, len, "%b %d %H:%M:%S", tmp);
83 }
84 
85 #else /* alternative implementation: just print the timestamp */
86 
87 COAP_STATIC_INLINE size_t
88 print_timestamp(char *s, size_t len, coap_tick_t t) {
89 #ifdef HAVE_SNPRINTF
90  return snprintf(s, len, "%u.%03u",
91  (unsigned int)coap_ticks_to_rt(t),
92  (unsigned int)(t % COAP_TICKS_PER_SECOND));
93 #else /* HAVE_SNPRINTF */
94  /* @todo do manual conversion of timestamp */
95  return 0;
96 #endif /* HAVE_SNPRINTF */
97 }
98 
99 #endif /* HAVE_TIME_H */
100 
101 #ifndef HAVE_STRNLEN
102 
110 static inline size_t
111 strnlen(const char *s, size_t maxlen) {
112  size_t n = 0;
113  while(*s++ && n < maxlen)
114  ++n;
115  return n;
116 }
117 #endif /* HAVE_STRNLEN */
118 
119 static size_t
120 print_readable( const uint8_t *data, size_t len,
121  unsigned char *result, size_t buflen, int encode_always ) {
122  const uint8_t hex[] = "0123456789ABCDEF";
123  size_t cnt = 0;
124  assert(data || len == 0);
125 
126  if (buflen == 0) { /* there is nothing we can do here but return */
127  return 0;
128  }
129 
130  while (len) {
131  if (!encode_always && isprint(*data)) {
132  if (cnt+1 < buflen) { /* keep one byte for terminating zero */
133  *result++ = *data;
134  ++cnt;
135  } else {
136  break;
137  }
138  } else {
139  if (cnt+4 < buflen) { /* keep one byte for terminating zero */
140  *result++ = '\\';
141  *result++ = 'x';
142  *result++ = hex[(*data & 0xf0) >> 4];
143  *result++ = hex[*data & 0x0f];
144  cnt += 4;
145  } else
146  break;
147  }
148 
149  ++data; --len;
150  }
151 
152  *result = '\0'; /* add a terminating zero */
153  return cnt;
154 }
155 
156 #ifndef min
157 #define min(a,b) ((a) < (b) ? (a) : (b))
158 #endif
159 
160 size_t
161 coap_print_addr(const struct coap_address_t *addr, unsigned char *buf, size_t len) {
162 #if defined( HAVE_ARPA_INET_H ) || defined( HAVE_WS2TCPIP_H )
163  const void *addrptr = NULL;
164  in_port_t port;
165  unsigned char *p = buf;
166  size_t need_buf;
167 
168  switch (addr->addr.sa.sa_family) {
169  case AF_INET:
170  addrptr = &addr->addr.sin.sin_addr;
171  port = ntohs(addr->addr.sin.sin_port);
172  need_buf = INET_ADDRSTRLEN;
173  break;
174  case AF_INET6:
175  if (len < 7) /* do not proceed if buffer is even too short for [::]:0 */
176  return 0;
177 
178  *p++ = '[';
179 
180  addrptr = &addr->addr.sin6.sin6_addr;
181  port = ntohs(addr->addr.sin6.sin6_port);
182  need_buf = INET6_ADDRSTRLEN;
183 
184  break;
185  default:
186  memcpy(buf, "(unknown address type)", min(22, len));
187  return min(22, len);
188  }
189 
190  /* Cast needed for Windows, since it doesn't have the correct API signature. */
191  if (inet_ntop(addr->addr.sa.sa_family, addrptr, (char *)p,
192  min(len, need_buf)) == 0) {
193  perror("coap_print_addr");
194  return 0;
195  }
196 
197  p += strnlen((char *)p, len);
198 
199  if (addr->addr.sa.sa_family == AF_INET6) {
200  if (p < buf + len) {
201  *p++ = ']';
202  } else
203  return 0;
204  }
205 
206  p += snprintf((char *)p, buf + len - p + 1, ":%d", port);
207 
208  return buf + len - p;
209 #else /* HAVE_ARPA_INET_H */
210 # if WITH_CONTIKI
211  unsigned char *p = buf;
212  uint8_t i;
213 # if NETSTACK_CONF_WITH_IPV6
214  const uint8_t hex[] = "0123456789ABCDEF";
215 
216  if (len < 41)
217  return 0;
218 
219  *p++ = '[';
220 
221  for (i=0; i < 16; i += 2) {
222  if (i) {
223  *p++ = ':';
224  }
225  *p++ = hex[(addr->addr.u8[i] & 0xf0) >> 4];
226  *p++ = hex[(addr->addr.u8[i] & 0x0f)];
227  *p++ = hex[(addr->addr.u8[i+1] & 0xf0) >> 4];
228  *p++ = hex[(addr->addr.u8[i+1] & 0x0f)];
229  }
230  *p++ = ']';
231 # else /* WITH_UIP6 */
232 # warning "IPv4 network addresses will not be included in debug output"
233 
234  if (len < 21)
235  return 0;
236 # endif /* WITH_UIP6 */
237  if (buf + len - p < 6)
238  return 0;
239 
240 #ifdef HAVE_SNPRINTF
241  p += snprintf((char *)p, buf + len - p + 1, ":%d", uip_htons(addr->port));
242 #else /* HAVE_SNPRINTF */
243  /* @todo manual conversion of port number */
244 #endif /* HAVE_SNPRINTF */
245 
246  return p - buf;
247 # else /* WITH_CONTIKI */
248  /* TODO: output addresses manually */
249 # warning "inet_ntop() not available, network addresses will not be included in debug output"
250 # endif /* WITH_CONTIKI */
251  return 0;
252 #endif
253 }
254 
255 #ifdef WITH_CONTIKI
256 # define fprintf(fd, ...) { (void)fd; PRINTF(__VA_ARGS__); }
257 # define fflush(...)
258 
259 # ifdef HAVE_VPRINTF
260 # define vfprintf(fd, ...) { (void)fd; vprintf(__VA_ARGS__); }
261 # else /* HAVE_VPRINTF */
262 # define vfprintf(fd, ...) { (void)fd; PRINTF(__VA_ARGS__); }
263 # endif /* HAVE_VPRINTF */
264 #endif /* WITH_CONTIKI */
265 
267 static const char *
268 msg_type_string(uint16_t t) {
269  static const char *types[] = { "CON", "NON", "ACK", "RST", "???" };
270 
271  return types[min(t, sizeof(types)/sizeof(char *) - 1)];
272 }
273 
275 static const char *
276 msg_code_string(uint16_t c) {
277  static const char *methods[] = { "0.00", "GET", "POST", "PUT", "DELETE",
278  "FETCH", "PATCH", "iPATCH" };
279  static const char *signals[] = { "7.00", "CSM", "Ping", "Pong", "Release",
280  "Abort" };
281  static char buf[5];
282 
283  if (c < sizeof(methods)/sizeof(const char *)) {
284  return methods[c];
285  } else if (c >= 224 && c - 224 < (int)(sizeof(signals)/sizeof(const char *))) {
286  return signals[c-224];
287  } else {
288  snprintf(buf, sizeof(buf), "%u.%02u", (c >> 5) & 0x7, c & 0x1f);
289  return buf;
290  }
291 }
292 
294 static const char *
295 msg_option_string(uint8_t code, uint16_t option_type) {
296  struct option_desc_t {
297  uint16_t type;
298  const char *name;
299  };
300 
301  static struct option_desc_t options[] = {
302  { COAP_OPTION_IF_MATCH, "If-Match" },
303  { COAP_OPTION_URI_HOST, "Uri-Host" },
304  { COAP_OPTION_ETAG, "ETag" },
305  { COAP_OPTION_IF_NONE_MATCH, "If-None-Match" },
306  { COAP_OPTION_OBSERVE, "Observe" },
307  { COAP_OPTION_URI_PORT, "Uri-Port" },
308  { COAP_OPTION_LOCATION_PATH, "Location-Path" },
309  { COAP_OPTION_URI_PATH, "Uri-Path" },
310  { COAP_OPTION_CONTENT_FORMAT, "Content-Format" },
311  { COAP_OPTION_MAXAGE, "Max-Age" },
312  { COAP_OPTION_URI_QUERY, "Uri-Query" },
313  { COAP_OPTION_ACCEPT, "Accept" },
314  { COAP_OPTION_LOCATION_QUERY, "Location-Query" },
315  { COAP_OPTION_BLOCK2, "Block2" },
316  { COAP_OPTION_BLOCK1, "Block1" },
317  { COAP_OPTION_PROXY_URI, "Proxy-Uri" },
318  { COAP_OPTION_PROXY_SCHEME, "Proxy-Scheme" },
319  { COAP_OPTION_SIZE1, "Size1" },
320  { COAP_OPTION_SIZE2, "Size2" },
321  { COAP_OPTION_NORESPONSE, "No-Response" }
322  };
323 
324  static struct option_desc_t options_csm[] = {
325  { COAP_SIGNALING_OPTION_MAX_MESSAGE_SIZE, "Max-Message-Size" },
326  { COAP_SIGNALING_OPTION_BLOCK_WISE_TRANSFER, "Block-wise-Transfer" }
327  };
328 
329  static struct option_desc_t options_pingpong[] = {
330  { COAP_SIGNALING_OPTION_CUSTODY, "Custody" }
331  };
332 
333  static struct option_desc_t options_release[] = {
334  { COAP_SIGNALING_OPTION_ALTERNATIVE_ADDRESS, "Alternative-Address" },
335  { COAP_SIGNALING_OPTION_HOLD_OFF, "Hold-Off" }
336  };
337 
338  static struct option_desc_t options_abort[] = {
339  { COAP_SIGNALING_OPTION_BAD_CSM_OPTION, "Bad-CSM-Option" }
340  };
341 
342  static char buf[6];
343  size_t i;
344 
345  if (code == COAP_SIGNALING_CSM) {
346  for (i = 0; i < sizeof(options_csm)/sizeof(struct option_desc_t); i++) {
347  if (option_type == options_csm[i].type) {
348  return options_csm[i].name;
349  }
350  }
351  } else if (code == COAP_SIGNALING_PING || code == COAP_SIGNALING_PONG) {
352  for (i = 0; i < sizeof(options_pingpong)/sizeof(struct option_desc_t); i++) {
353  if (option_type == options_pingpong[i].type) {
354  return options_pingpong[i].name;
355  }
356  }
357  } else if (code == COAP_SIGNALING_RELEASE) {
358  for (i = 0; i < sizeof(options_release)/sizeof(struct option_desc_t); i++) {
359  if (option_type == options_release[i].type) {
360  return options_release[i].name;
361  }
362  }
363  } else if (code == COAP_SIGNALING_ABORT) {
364  for (i = 0; i < sizeof(options_abort)/sizeof(struct option_desc_t); i++) {
365  if (option_type == options_abort[i].type) {
366  return options_abort[i].name;
367  }
368  }
369  } else {
370  /* search option_type in list of known options */
371  for (i = 0; i < sizeof(options)/sizeof(struct option_desc_t); i++) {
372  if (option_type == options[i].type) {
373  return options[i].name;
374  }
375  }
376  }
377  /* unknown option type, just print to buf */
378  snprintf(buf, sizeof(buf), "%u", option_type);
379  return buf;
380 }
381 
382 static unsigned int
383 print_content_format(unsigned int format_type,
384  unsigned char *result, unsigned int buflen) {
385  struct desc_t {
386  unsigned int type;
387  const char *name;
388  };
389 
390  static struct desc_t formats[] = {
391  { COAP_MEDIATYPE_TEXT_PLAIN, "text/plain" },
392  { COAP_MEDIATYPE_APPLICATION_LINK_FORMAT, "application/link-format" },
393  { COAP_MEDIATYPE_APPLICATION_XML, "application/xml" },
394  { COAP_MEDIATYPE_APPLICATION_OCTET_STREAM, "application/octet-stream" },
395  { COAP_MEDIATYPE_APPLICATION_EXI, "application/exi" },
396  { COAP_MEDIATYPE_APPLICATION_JSON, "application/json" },
397  { COAP_MEDIATYPE_APPLICATION_CBOR, "application/cbor" },
398  { COAP_MEDIATYPE_APPLICATION_COSE_SIGN, "application/cose; cose-type=\"cose-sign\"" },
399  { COAP_MEDIATYPE_APPLICATION_COSE_SIGN1, "application/cose; cose-type=\"cose-sign1\"" },
400  { COAP_MEDIATYPE_APPLICATION_COSE_ENCRYPT, "application/cose; cose-type=\"cose-encrypt\"" },
401  { COAP_MEDIATYPE_APPLICATION_COSE_ENCRYPT0, "application/cose; cose-type=\"cose-encrypt0\"" },
402  { COAP_MEDIATYPE_APPLICATION_COSE_MAC, "application/cose; cose-type=\"cose-mac\"" },
403  { COAP_MEDIATYPE_APPLICATION_COSE_MAC0, "application/cose; cose-type=\"cose-mac0\"" },
404  { COAP_MEDIATYPE_APPLICATION_COSE_KEY, "application/cose-key" },
405  { COAP_MEDIATYPE_APPLICATION_COSE_KEY_SET, "application/cose-key-set" },
406  { COAP_MEDIATYPE_APPLICATION_SENML_JSON, "application/senml+json" },
407  { COAP_MEDIATYPE_APPLICATION_SENSML_JSON, "application/sensml+json" },
408  { COAP_MEDIATYPE_APPLICATION_SENML_CBOR, "application/senml+cbor" },
409  { COAP_MEDIATYPE_APPLICATION_SENSML_CBOR, "application/sensml+cbor" },
410  { COAP_MEDIATYPE_APPLICATION_SENML_EXI, "application/senml-exi" },
411  { COAP_MEDIATYPE_APPLICATION_SENSML_EXI, "application/sensml-exi" },
412  { COAP_MEDIATYPE_APPLICATION_SENML_XML, "application/senml+xml" },
413  { COAP_MEDIATYPE_APPLICATION_SENSML_XML, "application/sensml+xml" },
414  { 75, "application/dcaf+cbor" }
415  };
416 
417  size_t i;
418 
419  /* search format_type in list of known content formats */
420  for (i = 0; i < sizeof(formats)/sizeof(struct desc_t); i++) {
421  if (format_type == formats[i].type) {
422  return snprintf((char *)result, buflen, "%s", formats[i].name);
423  }
424  }
425 
426  /* unknown content format, just print numeric value to buf */
427  return snprintf((char *)result, buflen, "%d", format_type);
428 }
429 
436 is_binary(int content_format) {
437  return !(content_format == -1 ||
438  content_format == COAP_MEDIATYPE_TEXT_PLAIN ||
439  content_format == COAP_MEDIATYPE_APPLICATION_LINK_FORMAT ||
440  content_format == COAP_MEDIATYPE_APPLICATION_XML ||
441  content_format == COAP_MEDIATYPE_APPLICATION_JSON);
442 }
443 
444 #define COAP_DO_SHOW_OUTPUT_LINE \
445  do { \
446  if (use_fprintf_for_show_pdu) { \
447  fprintf(COAP_DEBUG_FD, "%s", outbuf); \
448  } \
449  else { \
450  coap_log(level, "%s", outbuf); \
451  } \
452  } while (0)
453 
454 void
455 coap_show_pdu(coap_log_t level, const coap_pdu_t *pdu) {
456 #if COAP_CONSTRAINED_STACK
457  static coap_mutex_t static_show_pdu_mutex = COAP_MUTEX_INITIALIZER;
458  static unsigned char buf[min(COAP_DEBUG_BUF_SIZE, 1024)]; /* need some space for output creation */
459  static char outbuf[COAP_DEBUG_BUF_SIZE];
460 #else /* ! COAP_CONSTRAINED_STACK */
461  unsigned char buf[min(COAP_DEBUG_BUF_SIZE, 1024)]; /* need some space for output creation */
462  char outbuf[COAP_DEBUG_BUF_SIZE];
463 #endif /* ! COAP_CONSTRAINED_STACK */
464  size_t buf_len = 0; /* takes the number of bytes written to buf */
465  int encode = 0, have_options = 0, i;
466  coap_opt_iterator_t opt_iter;
467  coap_opt_t *option;
468  int content_format = -1;
469  size_t data_len;
470  unsigned char *data;
471  int outbuflen = 0;
472 
473  /* Save time if not needed */
474  if (level > coap_get_log_level())
475  return;
476 
477 #if COAP_CONSTRAINED_STACK
478  coap_mutex_lock(&static_show_pdu_mutex);
479 #endif /* COAP_CONSTRAINED_STACK */
480 
481  snprintf(outbuf, sizeof(outbuf), "v:%d t:%s c:%s i:%04x {",
483  msg_code_string(pdu->code), pdu->tid);
484 
485  for (i = 0; i < pdu->token_length; i++) {
486  outbuflen = strlen(outbuf);
487  snprintf(&outbuf[outbuflen], sizeof(outbuf)-outbuflen,
488  "%02x", pdu->token[i]);
489  }
490  outbuflen = strlen(outbuf);
491  snprintf(&outbuf[outbuflen], sizeof(outbuf)-outbuflen, "}");
492 
493  /* show options, if any */
494  coap_option_iterator_init(pdu, &opt_iter, COAP_OPT_ALL);
495 
496  outbuflen = strlen(outbuf);
497  snprintf(&outbuf[outbuflen], sizeof(outbuf)-outbuflen, " [");
498  while ((option = coap_option_next(&opt_iter))) {
499  if (!have_options) {
500  have_options = 1;
501  } else {
502  outbuflen = strlen(outbuf);
503  snprintf(&outbuf[outbuflen], sizeof(outbuf)-outbuflen, ",");
504  }
505 
506  if (pdu->code == COAP_SIGNALING_CSM) switch(opt_iter.type) {
508  buf_len = snprintf((char *)buf, sizeof(buf), "%u",
510  coap_opt_length(option)));
511  break;
512  default:
513  buf_len = 0;
514  break;
515  } else if (pdu->code == COAP_SIGNALING_PING
516  || pdu->code == COAP_SIGNALING_PONG) {
517  buf_len = 0;
518  } else if (pdu->code == COAP_SIGNALING_RELEASE) switch(opt_iter.type) {
520  buf_len = print_readable(coap_opt_value(option),
521  coap_opt_length(option),
522  buf, sizeof(buf), 0);
523  break;
525  buf_len = snprintf((char *)buf, sizeof(buf), "%u",
527  coap_opt_length(option)));
528  break;
529  default:
530  buf_len = 0;
531  break;
532  } else if (pdu->code == COAP_SIGNALING_ABORT) switch(opt_iter.type) {
534  buf_len = snprintf((char *)buf, sizeof(buf), "%u",
536  coap_opt_length(option)));
537  break;
538  default:
539  buf_len = 0;
540  break;
541  } else switch (opt_iter.type) {
543  content_format = (int)coap_decode_var_bytes(coap_opt_value(option),
544  coap_opt_length(option));
545 
546  buf_len = print_content_format(content_format, buf, sizeof(buf));
547  break;
548 
549  case COAP_OPTION_BLOCK1:
550  case COAP_OPTION_BLOCK2:
551  /* split block option into number/more/size where more is the
552  * letter M if set, the _ otherwise */
553  buf_len = snprintf((char *)buf, sizeof(buf), "%u/%c/%u",
554  coap_opt_block_num(option), /* block number */
555  COAP_OPT_BLOCK_MORE(option) ? 'M' : '_', /* M bit */
556  (1 << (COAP_OPT_BLOCK_SZX(option) + 4))); /* block size */
557 
558  break;
559 
561  case COAP_OPTION_MAXAGE:
562  case COAP_OPTION_OBSERVE:
563  case COAP_OPTION_SIZE1:
564  case COAP_OPTION_SIZE2:
565  /* show values as unsigned decimal value */
566  buf_len = snprintf((char *)buf, sizeof(buf), "%u",
568  coap_opt_length(option)));
569  break;
570 
571  default:
572  /* generic output function for all other option types */
573  if (opt_iter.type == COAP_OPTION_URI_PATH ||
574  opt_iter.type == COAP_OPTION_PROXY_URI ||
575  opt_iter.type == COAP_OPTION_URI_HOST ||
576  opt_iter.type == COAP_OPTION_LOCATION_PATH ||
577  opt_iter.type == COAP_OPTION_LOCATION_QUERY ||
578  opt_iter.type == COAP_OPTION_URI_QUERY) {
579  encode = 0;
580  } else {
581  encode = 1;
582  }
583 
584  buf_len = print_readable(coap_opt_value(option),
585  coap_opt_length(option),
586  buf, sizeof(buf), encode);
587  }
588 
589  outbuflen = strlen(outbuf);
590  snprintf(&outbuf[outbuflen], sizeof(outbuf)-outbuflen,
591  " %s:%.*s", msg_option_string(pdu->code, opt_iter.type),
592  (int)buf_len, buf);
593  }
594 
595  outbuflen = strlen(outbuf);
596  snprintf(&outbuf[outbuflen], sizeof(outbuf)-outbuflen, " ]");
597 
598  if (coap_get_data(pdu, &data_len, &data)) {
599 
600  outbuflen = strlen(outbuf);
601  snprintf(&outbuf[outbuflen], sizeof(outbuf)-outbuflen, " :: ");
602 
603  if (is_binary(content_format)) {
604  int keep_data_len = data_len;
605  uint8_t *keep_data = data;
606 
607  outbuflen = strlen(outbuf);
608  snprintf(&outbuf[outbuflen], sizeof(outbuf)-outbuflen,
609  "binary data length %zu\n", data_len);
611  /*
612  * Output hex dump of binary data as a continuous entry
613  */
614  outbuf[0] = '\000';
615  snprintf(outbuf, sizeof(outbuf), "<<");
616  while (data_len--) {
617  outbuflen = strlen(outbuf);
618  snprintf(&outbuf[outbuflen], sizeof(outbuf)-outbuflen,
619  "%02x", *data++);
620  }
621  outbuflen = strlen(outbuf);
622  snprintf(&outbuf[outbuflen], sizeof(outbuf)-outbuflen, ">>");
623  data_len = keep_data_len;
624  data = keep_data;
625  outbuflen = strlen(outbuf);
626  snprintf(&outbuf[outbuflen], sizeof(outbuf)-outbuflen, "\n");
628  /*
629  * Output ascii readable (if possible), immediately under the
630  * hex value of the character output above to help binary debugging
631  */
632  outbuf[0] = '\000';
633  snprintf(outbuf, sizeof(outbuf), "<<");
634  while (data_len--) {
635  outbuflen = strlen(outbuf);
636  snprintf(&outbuf[outbuflen], sizeof(outbuf)-outbuflen,
637  "%c ", isprint (*data) ? *data : '.');
638  data++;
639  }
640  outbuflen = strlen(outbuf);
641  snprintf(&outbuf[outbuflen], sizeof(outbuf)-outbuflen, ">>");
642  } else {
643  if (print_readable(data, data_len, buf, sizeof(buf), 0)) {
644  size_t max_length;
645  outbuflen = strlen(outbuf);
646  max_length = sizeof(outbuf)-outbuflen;
647  if (snprintf(&outbuf[outbuflen], max_length, "'%s'", buf) >= (int)max_length)
648  outbuf[sizeof(outbuf)-1] = '\000';
649  }
650  }
651  }
652 
653  outbuflen = strlen(outbuf);
654  snprintf(&outbuf[outbuflen], sizeof(outbuf)-outbuflen, "\n");
656 
657 #if COAP_CONSTRAINED_STACK
658  coap_mutex_unlock(&static_show_pdu_mutex);
659 #endif /* COAP_CONSTRAINED_STACK */
660 }
661 
663 {
664  char buffer[64];
665  coap_string_tls_version(buffer, sizeof(buffer));
666  coap_log(level, "%s\n", buffer);
667 }
668 
669 char *coap_string_tls_version(char *buffer, size_t bufsize)
670 {
672  char beta[8];
673  char sub[2];
674  char b_beta[8];
675  char b_sub[2];
676 
677  switch (tls_version->type) {
679  snprintf(buffer, bufsize, "TLS Library: None");
680  break;
682  snprintf(buffer, bufsize, "TLS Library: TinyDTLS - runtime %lu.%lu.%lu, "
683  "libcoap built for %lu.%lu.%lu",
684  (unsigned long)(tls_version->version >> 16),
685  (unsigned long)((tls_version->version >> 8) & 0xff),
686  (unsigned long)(tls_version->version & 0xff),
687  (unsigned long)(tls_version->built_version >> 16),
688  (unsigned long)((tls_version->built_version >> 8) & 0xff),
689  (unsigned long)(tls_version->built_version & 0xff));
690  break;
692  switch (tls_version->version &0xf) {
693  case 0:
694  strcpy(beta, "-dev");
695  break;
696  case 0xf:
697  strcpy(beta, "");
698  break;
699  default:
700  strcpy(beta, "-beta");
701  beta[5] = (tls_version->version &0xf) + '0';
702  beta[6] = '\000';
703  break;
704  }
705  sub[0] = ((tls_version->version >> 4) & 0xff) ?
706  ((tls_version->version >> 4) & 0xff) + 'a' -1 : '\000';
707  sub[1] = '\000';
708  switch (tls_version->built_version &0xf) {
709  case 0:
710  strcpy(b_beta, "-dev");
711  break;
712  case 0xf:
713  strcpy(b_beta, "");
714  break;
715  default:
716  strcpy(b_beta, "-beta");
717  b_beta[5] = (tls_version->built_version &0xf) + '0';
718  b_beta[6] = '\000';
719  break;
720  }
721  b_sub[0] = ((tls_version->built_version >> 4) & 0xff) ?
722  ((tls_version->built_version >> 4) & 0xff) + 'a' -1 : '\000';
723  b_sub[1] = '\000';
724  snprintf(buffer, bufsize, "TLS Library: OpenSSL - runtime "
725  "%lu.%lu.%lu%s%s, libcoap built for %lu.%lu.%lu%s%s",
726  (unsigned long)(tls_version->version >> 28),
727  (unsigned long)((tls_version->version >> 20) & 0xff),
728  (unsigned long)((tls_version->version >> 12) & 0xff), sub, beta,
729  (unsigned long)(tls_version->built_version >> 28),
730  (unsigned long)((tls_version->built_version >> 20) & 0xff),
731  (unsigned long)((tls_version->built_version >> 12) & 0xff),
732  b_sub, b_beta);
733  break;
735  snprintf(buffer, bufsize, "TLS Library: GnuTLS - runtime %lu.%lu.%lu, "
736  "libcoap built for %lu.%lu.%lu",
737  (unsigned long)(tls_version->version >> 16),
738  (unsigned long)((tls_version->version >> 8) & 0xff),
739  (unsigned long)(tls_version->version & 0xff),
740  (unsigned long)(tls_version->built_version >> 16),
741  (unsigned long)((tls_version->built_version >> 8) & 0xff),
742  (unsigned long)(tls_version->built_version & 0xff));
743  break;
744  default:
745  snprintf(buffer, bufsize, "Library type %d unknown", tls_version->type);
746  break;
747  }
748  return buffer;
749 }
750 
752 
754  log_handler = handler;
755 }
756 
757 void
758 coap_log_impl(coap_log_t level, const char *format, ...) {
759 
760  if (maxlog < level)
761  return;
762 
763  if (log_handler) {
764 #if COAP_CONSTRAINED_STACK
765  static coap_mutex_t static_log_mutex = COAP_MUTEX_INITIALIZER;
766  static char message[COAP_DEBUG_BUF_SIZE];
767 #else /* ! COAP_CONSTRAINED_STACK */
768  char message[COAP_DEBUG_BUF_SIZE];
769 #endif /* ! COAP_CONSTRAINED_STACK */
770  va_list ap;
771  va_start(ap, format);
772 #if COAP_CONSTRAINED_STACK
773  coap_mutex_lock(&static_log_mutex);
774 #endif /* COAP_CONSTRAINED_STACK */
775 
776  vsnprintf( message, sizeof(message), format, ap);
777  va_end(ap);
778  log_handler(level, message);
779 #if COAP_CONSTRAINED_STACK
780  coap_mutex_unlock(&static_log_mutex);
781 #endif /* COAP_CONSTRAINED_STACK */
782  } else {
783  char timebuf[32];
784  coap_tick_t now;
785  va_list ap;
786  FILE *log_fd;
787 
788  log_fd = level <= LOG_CRIT ? COAP_ERR_FD : COAP_DEBUG_FD;
789 
790  coap_ticks(&now);
791  if (print_timestamp(timebuf,sizeof(timebuf), now))
792  fprintf(log_fd, "%s ", timebuf);
793 
794  if (level <= COAP_LOG_CIPHERS)
795  fprintf(log_fd, "%s ", loglevels[level]);
796 
797  va_start(ap, format);
798  vfprintf(log_fd, format, ap);
799  va_end(ap);
800  fflush(log_fd);
801  }
802 }
803 
804 static struct packet_num_interval {
805  int start;
806  int end;
809 static int packet_loss_level = 0;
810 static int send_packet_count = 0;
811 
812 int coap_debug_set_packet_loss(const char *loss_level) {
813  const char *p = loss_level;
814  char *end = NULL;
815  int n = (int)strtol(p, &end, 10), i = 0;
816  if (end == p || n < 0)
817  return 0;
818  if (*end == '%') {
819  if (n > 100)
820  n = 100;
821  packet_loss_level = n * 65536 / 100;
822  coap_log(LOG_DEBUG, "packet loss level set to %d%%\n", n);
823  } else {
824  if (n <= 0)
825  return 0;
826  while (i < 10) {
828  if (*end == '-') {
829  p = end + 1;
830  n = (int)strtol(p, &end, 10);
831  if (end == p || n <= 0)
832  return 0;
833  }
834  packet_loss_intervals[i++].end = n;
835  if (*end == 0)
836  break;
837  if (*end != ',')
838  return 0;
839  p = end + 1;
840  n = (int)strtol(p, &end, 10);
841  if (end == p || n <= 0)
842  return 0;
843  }
844  if (i == 10)
845  return 0;
847  }
848  send_packet_count = 0;
849  return 1;
850 }
851 
854  if (num_packet_loss_intervals > 0) {
855  int i;
856  for (i = 0; i < num_packet_loss_intervals; i++) {
859  return 0;
860  }
861  }
862  if ( packet_loss_level > 0 ) {
863  uint16_t r = 0;
864  prng( (uint8_t*)&r, 2 );
865  if ( r < packet_loss_level )
866  return 0;
867  }
868  return 1;
869 }
uint8_t type
message type
Definition: pdu.h:288
uint8_t code
request method (value 1–10) or response code (value 40-255)
Definition: pdu.h:289
void coap_show_pdu(coap_log_t level, const coap_pdu_t *pdu)
Display the contents of the specified pdu.
Definition: coap_debug.c:455
#define COAP_OPTION_IF_MATCH
Definition: pdu.h:92
#define COAP_MEDIATYPE_APPLICATION_SENSML_JSON
Definition: pdu.h:221
uint8_t coap_opt_t
Use byte-oriented access methods here because sliding a complex struct coap_opt_t over the data buffe...
Definition: option.h:25
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:17
#define COAP_SIGNALING_PING
Definition: pdu.h:181
Using TinyDTLS library.
Definition: coap_dtls.h:42
COAP_STATIC_INLINE int is_binary(int content_format)
Returns 1 if the given content_format is either unknown or known to carry binary data.
Definition: coap_debug.c:436
#define COAP_SIGNALING_CSM
Definition: pdu.h:180
#define COAP_MEDIATYPE_APPLICATION_COSE_MAC0
Definition: pdu.h:214
#define COAP_OPTION_PROXY_URI
Definition: pdu.h:106
#define COAP_OPTION_CONTENT_FORMAT
Definition: pdu.h:99
struct sockaddr_in6 sin6
Definition: address.h:67
struct sockaddr_in sin
Definition: address.h:66
static const char * msg_code_string(uint16_t c)
Returns a textual description of the method or response code.
Definition: coap_debug.c:276
#define COAP_OPTION_NORESPONSE
Definition: pdu.h:122
multi-purpose address abstraction
Definition: address.h:62
#define COAP_OPT_ALL
Pre-defined filter that includes all options.
Definition: option.h:122
const char * coap_package_name(void)
Get the library package name.
Definition: coap_debug.c:47
size_t coap_print_addr(const struct coap_address_t *addr, unsigned char *buf, size_t len)
Print the address into the defined buffer.
Definition: coap_debug.c:161
#define COAP_OPTION_OBSERVE
Definition: pdu.h:112
#define COAP_OPTION_ETAG
Definition: pdu.h:94
#define COAP_DEBUG_BUF_SIZE
Definition: pdu.h:60
#define COAP_MEDIATYPE_APPLICATION_JSON
Definition: pdu.h:205
coap_time_t coap_ticks_to_rt(coap_tick_t t)
Helper function that converts coap ticks to wallclock time.
#define COAP_OPTION_BLOCK1
Definition: pdu.h:118
int coap_debug_set_packet_loss(const char *loss_level)
Set the packet loss level for testing.
Definition: coap_debug.c:812
#define COAP_SIGNALING_OPTION_BLOCK_WISE_TRANSFER
Definition: pdu.h:188
#define COAP_OPTION_MAXAGE
Definition: pdu.h:101
Debug.
Definition: coap_debug.h:55
uint64_t version
(D)TLS runtime Library Version
Definition: coap_dtls.h:52
coap_opt_t * coap_option_next(coap_opt_iterator_t *oi)
Updates the iterator oi to point to the next option.
Definition: option.c:146
#define COAP_MEDIATYPE_APPLICATION_SENSML_EXI
Definition: pdu.h:225
#define COAP_DO_SHOW_OUTPUT_LINE
Definition: coap_debug.c:444
#define COAP_OPTION_LOCATION_QUERY
Definition: pdu.h:104
#define COAP_OPTION_PROXY_SCHEME
Definition: pdu.h:107
#define min(a, b)
Definition: coap_debug.c:157
uint16_t type
decoded option type
Definition: option.h:239
#define COAP_MEDIATYPE_APPLICATION_SENSML_XML
Definition: pdu.h:227
#define COAP_MEDIATYPE_APPLICATION_SENML_CBOR
Definition: pdu.h:222
#define COAP_MEDIATYPE_APPLICATION_SENML_JSON
Definition: pdu.h:220
#define COAP_MEDIATYPE_APPLICATION_EXI
Definition: pdu.h:204
static coap_log_handler_t log_handler
Definition: coap_debug.c:751
No DTLS library.
Definition: coap_dtls.h:41
char * coap_string_tls_version(char *buffer, size_t bufsize)
Build a string containing the current (D)TLS library linked with and built for version.
Definition: coap_debug.c:669
int coap_debug_send_packet(void)
Check to see whether a packet should be sent or not.
Definition: coap_debug.c:852
void coap_set_log_level(coap_log_t level)
Sets the log level to the specified value.
Definition: coap_debug.c:66
static coap_log_t maxlog
Definition: coap_debug.c:43
#define COAP_DEFAULT_VERSION
Definition: pdu.h:64
void coap_log_impl(coap_log_t level, const char *format,...)
Writes the given text to COAP_ERR_FD (for level <= LOG_CRIT) or COAP_DEBUG_FD (for level >= LOG_ERR)...
Definition: coap_debug.c:758
#define COAP_TICKS_PER_SECOND
Use ms resolution on POSIX systems.
Definition: coap_time.h:108
coap_tls_library_t type
Library type.
Definition: coap_dtls.h:53
#define COAP_DEBUG_FD
Used for output for LOG_DEBUG to LOG_ERR.
Definition: coap_debug.h:23
void(* coap_log_handler_t)(coap_log_t level, const char *message)
Logging call-back handler definition.
Definition: coap_debug.h:80
coap_tls_version_t * coap_get_tls_library_version(void)
Determine the type and version of the underlying (D)TLS library.
Definition: coap_notls.c:31
#define COAP_SIGNALING_PONG
Definition: pdu.h:182
structure for CoAP PDUs token, if any, follows the fixed size header, then options until payload mark...
Definition: pdu.h:287
uint16_t coap_opt_length(const coap_opt_t *opt)
Returns the length of the given option.
Definition: option.c:238
#define COAP_SIGNALING_OPTION_MAX_MESSAGE_SIZE
Definition: pdu.h:187
#define COAP_SIGNALING_OPTION_CUSTODY
Definition: pdu.h:190
#define COAP_MEDIATYPE_APPLICATION_COSE_SIGN
Definition: pdu.h:209
#define COAP_OPTION_URI_PORT
Definition: pdu.h:96
Warning.
Definition: coap_debug.h:52
uint64_t coap_tick_t
This data type represents internal timer ticks with COAP_TICKS_PER_SECOND resolution.
Definition: coap_time.h:93
#define COAP_ERR_FD
Used for output for LOG_CRIT to LOG_EMERG.
Definition: coap_debug.h:30
#define COAP_MEDIATYPE_APPLICATION_SENSML_CBOR
Definition: pdu.h:223
static int num_packet_loss_intervals
Definition: coap_debug.c:808
uint8_t * token
first byte of token, if any, or options
Definition: pdu.h:298
void coap_ticks(coap_tick_t *t)
Sets t to the internal time with COAP_TICKS_PER_SECOND resolution.
The structure used for returning the underlying (D)TLS library information.
Definition: coap_dtls.h:51
static size_t print_readable(const uint8_t *data, size_t len, unsigned char *result, size_t buflen, int encode_always)
Definition: coap_debug.c:120
#define COAP_OPTION_IF_NONE_MATCH
Definition: pdu.h:95
#define INET6_ADDRSTRLEN
Iterator to run through PDU options.
Definition: option.h:237
#define COAP_MEDIATYPE_APPLICATION_LINK_FORMAT
Definition: pdu.h:200
int coap_get_data(const coap_pdu_t *pdu, size_t *len, uint8_t **data)
Retrieves the length and data pointer of specified PDU.
Definition: pdu.c:318
#define COAP_OPTION_SIZE1
Definition: pdu.h:108
static unsigned int print_content_format(unsigned int format_type, unsigned char *result, unsigned int buflen)
Definition: coap_debug.c:383
Using OpenSSL library.
Definition: coap_dtls.h:43
static int send_packet_count
Definition: coap_debug.c:810
void coap_set_show_pdu_output(int use_fprintf)
Defines the output mode for the coap_show_pdu() function.
Definition: coap_debug.c:56
Using GnuTLS library.
Definition: coap_dtls.h:44
#define COAP_OPTION_SIZE2
Definition: pdu.h:105
#define COAP_MEDIATYPE_APPLICATION_COSE_ENCRYPT0
Definition: pdu.h:212
#define COAP_STATIC_INLINE
Definition: libcoap.h:38
void coap_show_tls_version(coap_log_t level)
Display the current (D)TLS library linked with and built for version.
Definition: coap_debug.c:662
#define COAP_MEDIATYPE_APPLICATION_XML
Definition: pdu.h:201
#define COAP_OPTION_BLOCK2
Definition: pdu.h:117
#define COAP_OPTION_LOCATION_PATH
Definition: pdu.h:97
unsigned int coap_decode_var_bytes(const uint8_t *buf, unsigned int len)
Decodes multiple-length byte sequences.
Definition: encode.c:29
const uint8_t * coap_opt_value(const coap_opt_t *opt)
Returns a pointer to the value of the given option.
Definition: option.c:275
static const char * loglevels[]
Definition: coap_debug.c:71
#define COAP_MEDIATYPE_APPLICATION_SENML_EXI
Definition: pdu.h:224
#define COAP_OPT_BLOCK_SZX(opt)
Returns the value of the SZX-field of a Block option opt.
Definition: block.h:55
coap_log_t
Pre-defined log levels akin to what is used in syslog with LOG_CIPHERS added.
Definition: coap_debug.h:47
#define COAP_OPTION_URI_PATH
Definition: pdu.h:98
const char * coap_package_version(void)
Get the library package version.
Definition: coap_debug.c:51
CipherInfo.
Definition: coap_debug.h:56
#define COAP_MEDIATYPE_TEXT_PLAIN
Definition: pdu.h:199
#define COAP_MEDIATYPE_APPLICATION_COSE_SIGN1
Definition: pdu.h:210
coap_log_t coap_get_log_level(void)
Get the current logging level.
Definition: coap_debug.c:61
#define COAP_OPTION_URI_QUERY
Definition: pdu.h:102
#define coap_log(level,...)
Logging function.
Definition: coap_debug.h:129
static size_t strnlen(const char *s, size_t maxlen)
A length-safe strlen() fake.
Definition: coap_debug.c:111
union coap_address_t::@0 addr
#define COAP_OPTION_ACCEPT
Definition: pdu.h:103
#define COAP_SIGNALING_OPTION_ALTERNATIVE_ADDRESS
Definition: pdu.h:192
#define COAP_SIGNALING_RELEASE
Definition: pdu.h:183
#define COAP_SIGNALING_OPTION_BAD_CSM_OPTION
Definition: pdu.h:195
void coap_set_log_handler(coap_log_handler_t handler)
Add a custom log callback handler.
Definition: coap_debug.c:753
#define COAP_MEDIATYPE_APPLICATION_CBOR
Definition: pdu.h:206
unsigned char uint8_t
Definition: uthash.h:79
#define COAP_SIGNALING_OPTION_HOLD_OFF
Definition: pdu.h:193
#define COAP_MEDIATYPE_APPLICATION_COSE_KEY
Definition: pdu.h:216
#define COAP_OPT_BLOCK_MORE(opt)
Returns the value of the More-bit of a Block option opt.
Definition: block.h:51
#define COAP_MEDIATYPE_APPLICATION_SENML_XML
Definition: pdu.h:226
#define prng(Buf, Length)
Fills Buf with Length bytes of random data.
Definition: prng.h:112
uint8_t token_length
length of Token
Definition: pdu.h:292
#define COAP_MEDIATYPE_APPLICATION_COSE_ENCRYPT
Definition: pdu.h:211
#define COAP_MEDIATYPE_APPLICATION_COSE_MAC
Definition: pdu.h:213
Critical.
Definition: coap_debug.h:50
coap_opt_iterator_t * coap_option_iterator_init(const 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&#39;s option list...
Definition: option.c:110
uint64_t built_version
(D)TLS Built against Library Version
Definition: coap_dtls.h:54
#define COAP_MEDIATYPE_APPLICATION_OCTET_STREAM
Definition: pdu.h:202
#define COAP_OPTION_URI_HOST
Definition: pdu.h:93
#define COAP_SIGNALING_ABORT
Definition: pdu.h:184
#define COAP_MEDIATYPE_APPLICATION_COSE_KEY_SET
Definition: pdu.h:217
static int use_fprintf_for_show_pdu
Definition: coap_debug.c:45
struct sockaddr sa
Definition: address.h:65
uint16_t tid
transaction id, if any, in regular host byte order
Definition: pdu.h:293
static int packet_loss_level
Definition: coap_debug.c:809
static struct packet_num_interval packet_loss_intervals[10]
Pulls together all the internal only header files.
COAP_STATIC_INLINE size_t print_timestamp(char *s, size_t len, coap_tick_t t)
Definition: coap_debug.c:88
static const char * msg_type_string(uint16_t t)
Returns a textual description of the message type t.
Definition: coap_debug.c:268
static const char * msg_option_string(uint8_t code, uint16_t option_type)
Returns a textual description of the option name.
Definition: coap_debug.c:295