libcoap 4.3.5-develop-19cef11
coap_debug.c
Go to the documentation of this file.
1/* coap_debug.c -- debug utilities
2 *
3 * Copyright (C) 2010--2012,2014--2024 Olaf Bergmann <bergmann@tzi.org> and others
4 *
5 * SPDX-License-Identifier: BSD-2-Clause
6 *
7 * This file is part of the CoAP library libcoap. Please see
8 * README for terms of use.
9 */
10
17
18#if defined(HAVE_STRNLEN) && defined(__GNUC__) && !defined(_GNU_SOURCE)
19#define _GNU_SOURCE 1
20#endif
21
22#include <stdarg.h>
23#include <stdio.h>
24#include <string.h>
25#include <ctype.h>
26
27#ifdef HAVE_ARPA_INET_H
28#include <arpa/inet.h>
29#endif
30#ifdef HAVE_WS2TCPIP_H
31#include <ws2tcpip.h>
32#endif
33
34#ifdef HAVE_TIME_H
35#include <time.h>
36#endif
37
38#ifdef WITH_LWIP
39# define fprintf(fd, ...) LWIP_PLATFORM_DIAG((__VA_ARGS__))
40# define fflush(...)
41#endif
42
43#ifdef WITH_CONTIKI
44# define fprintf(fd, ...) { (void)fd; printf(__VA_ARGS__); }
45# define fflush(...)
46# define vfprintf(fd, ...) { (void)fd; printf(__VA_ARGS__); }
47
48# ifndef LOG_CONF_LEVEL_COAP
49# define LOG_CONF_LEVEL_COAP 2 /* = LOG_LEVEL_WARN */
50# endif
51static coap_log_t maxlog = LOG_CONF_LEVEL_COAP == 0 ? /* = LOG_LEVEL_NONE */
53 (LOG_CONF_LEVEL_COAP == 1 ? /* = LOG_LEVEL_ERR */
55 (LOG_CONF_LEVEL_COAP == 2 ? /* = LOG_LEVEL_WARN */
57 (LOG_CONF_LEVEL_COAP == 3 ? /* = LOG_LEVEL_INFO */
60#else /* !WITH_CONTIKI */
61static coap_log_t maxlog = COAP_LOG_WARN; /* default maximum CoAP log level */
62#endif /* !WITH_CONTIKI */
63
64#ifdef RIOT_VERSION
65#include "flash_utils.h"
66#endif /* RIOT_VERSION */
67
68static int use_fprintf_for_show_pdu = 1; /* non zero to output with fprintf */
69static int enable_data_for_show_pdu = 1; /* By default show PDU data for coap_show_pdu() */
70
71const char *
73 return PACKAGE_NAME;
74}
75
76const char *
78 return PACKAGE_STRING;
79}
80
81const char *
83#ifdef LIBCOAP_PACKAGE_BUILD
84 return LIBCOAP_PACKAGE_BUILD;
85#else /* !LIBCOAP_PACKAGE_BUILD */
86 return PACKAGE_STRING;
87#endif /* !LIBCOAP_PACKAGE_BUILD */
88}
89
90void
91coap_set_show_pdu_output(int use_fprintf) {
92 use_fprintf_for_show_pdu = use_fprintf;
93}
94
95void
97 enable_data_for_show_pdu = enable_data;
98}
99
102 return maxlog;
103}
104
105void
107 if (level > COAP_MAX_LOGGING_LEVEL)
109 maxlog = level;
110}
111
112/* this array has the same order as the type coap_log_t with the (D)TLS
113 entries added to the list with a COAP_LOG_DTLS_BASE offset */
114static const char *loglevels[] = {
115 /* General logging */
116 "EMRG", "ALRT", "CRIT", "ERR ", "WARN", "NOTE", "INFO", "DEBG", "OSC ",
117 /* (D)TLS logging */
118 "Emrg", "Alrt", "Crit", "Err ", "Warn", "Note", "Info", "Debg"
119};
120
121const char *
123 static char bad[8];
124 if (level >= sizeof(loglevels)/sizeof(loglevels[0])) {
125 snprintf(bad, sizeof(bad), "%4d", level);
126 return bad;
127 } else {
128 return loglevels[level];
129 }
130}
131
132#ifdef WITH_CONTIKI
133void
134coap_print_contiki_prefix(coap_log_t level) {
135 printf("[%s: COAP ] ", coap_log_level_desc(level));
136}
137#endif /* WITH_CONTIKI */
138
139#ifdef HAVE_TIME_H
140
142print_timestamp(char *s, size_t len, coap_tick_t t) {
143 struct tm *tmp;
144 size_t lensofar;
145 time_t now = coap_ticks_to_rt(t);
146 tmp = localtime(&now);
147 lensofar = strftime(s, len, "%b %d %H:%M:%S", tmp);
148 if (len > lensofar + 4) {
149 lensofar += snprintf(&s[lensofar], len-lensofar, ".%03u",
150 (unsigned int)((coap_ticks_to_rt_us(t) % 1000000)/1000));
151 }
152 return lensofar;
153}
154
155#else /* alternative implementation: just print the timestamp */
156
158print_timestamp(char *s, size_t len, coap_tick_t t) {
159#ifdef HAVE_SNPRINTF
160 return snprintf(s, len, "%u.%03u",
161 (unsigned int)coap_ticks_to_rt(t),
162 (unsigned int)((coap_ticks_to_rt_us(t) % 1000000)/1000));
163#else /* HAVE_SNPRINTF */
164 /* @todo do manual conversion of timestamp */
165 return 0;
166#endif /* HAVE_SNPRINTF */
167}
168
169#endif /* HAVE_TIME_H */
170
171#if !defined(HAVE_STRNLEN) && !defined(__MINGW32__)
180static inline size_t
181strnlen(const char *s, size_t maxlen) {
182 size_t n = 0;
183 while (*s++ && n < maxlen)
184 ++n;
185 return n;
186}
187#endif /* HAVE_STRNLEN && !__MINGW32__ */
188
189static size_t
190print_readable(const uint8_t *data, size_t len,
191 unsigned char *result, size_t buflen, int encode_always) {
192 const uint8_t hex[] = "0123456789ABCDEF";
193 size_t cnt = 0;
194 assert(data || len == 0);
195
196 if (buflen == 0) { /* there is nothing we can do here but return */
197 return 0;
198 }
199
200 while (len) {
201 if (!encode_always && isprint(*data)) {
202 if (cnt+1 < buflen) { /* keep one byte for terminating zero */
203 *result++ = *data;
204 ++cnt;
205 } else {
206 break;
207 }
208 } else {
209 if (cnt+4 < buflen) { /* keep one byte for terminating zero */
210 *result++ = '\\';
211 *result++ = 'x';
212 *result++ = hex[(*data & 0xf0) >> 4];
213 *result++ = hex[*data & 0x0f];
214 cnt += 4;
215 } else
216 break;
217 }
218
219 ++data;
220 --len;
221 }
222
223 *result = '\0'; /* add a terminating zero */
224 return cnt;
225}
226
227#ifndef min
228#define min(a,b) ((a) < (b) ? (a) : (b))
229#endif
230
231#ifndef INET6_ADDRSTRLEN
232#define INET6_ADDRSTRLEN 46
233#endif
234/*
235 * Returned buf is always NULL terminated.
236 * Returned size is number of characters, not including NULL terminator.
237 */
238size_t
239coap_print_addr(const coap_address_t *addr, unsigned char *buf, size_t len) {
240#if (defined( HAVE_ARPA_INET_H ) || defined( HAVE_WS2TCPIP_H )) && !defined(RIOT_VERSION)
241 char scratch[INET6_ADDRSTRLEN];
242
243 assert(buf);
244 assert(len);
245 buf[0] = '\000';
246
247 switch (addr->addr.sa.sa_family) {
248#if COAP_IPV4_SUPPORT
249 case AF_INET:
250 snprintf((char *)buf, len, "%s:%d",
251 coap_print_ip_addr(addr, scratch, sizeof(scratch)),
253 break;
254#endif /* COAP_IPV4_SUPPORT */
255#if COAP_IPV6_SUPPORT
256 case AF_INET6:
257 snprintf((char *)buf, len, "[%s]:%d",
258 coap_print_ip_addr(addr, scratch, sizeof(scratch)),
260 break;
261#endif /* COAP_IPV6_SUPPORT */
262#if COAP_AF_UNIX_SUPPORT
263 case AF_UNIX:
264 snprintf((char *)buf, len, "%s", addr->addr.cun.sun_path);
265 break;
266#endif /* COAP_AF_UNIX_SUPPORT */
267 default:
268 /* Include trailing NULL if possible */
269 memcpy(buf, "(unknown address type)", min(22+1, len));
270 buf[len-1] = '\000';
271 break;
272 }
273 return strlen((char *)buf);
274
275#else /* HAVE_ARPA_INET_H */
276
277# if defined(RIOT_VERSION)
278 char scratch[INET6_ADDRSTRLEN];
279
280 assert(buf);
281 assert(len);
282 buf[0] = '\000';
283
284 switch (addr->riot.family) {
285#if COAP_IPV4_SUPPORT
286 case AF_INET:
287 snprintf((char *)buf, len, "%s:%d",
288 coap_print_ip_addr(addr, scratch, sizeof(scratch)),
290 break;
291#endif /* COAP_IPV4_SUPPORT */
292#if COAP_IPV6_SUPPORT
293 case AF_INET6:
294 snprintf((char *)buf, len, "[%s]:%d",
295 coap_print_ip_addr(addr, scratch, sizeof(scratch)),
297 break;
298#endif /* COAP_IPV6_SUPPORT */
299 default:
300 /* Include trailing NULL if possible */
301 memcpy(buf, "(unknown address type)", min(22+1, len));
302 buf[len-1] = '\000';
303 break;
304 }
305 return strlen((char *)buf);
306
307# elif WITH_CONTIKI
308
309 char scratch[INET6_ADDRSTRLEN];
310#ifdef HAVE_SNPRINTF
311
312 snprintf((char *)buf, len, "[%s]:%d",
313 coap_print_ip_addr(addr, scratch, sizeof(scratch)),
315 return strlen((char *)buf);
316#else /* HAVE_SNPRINTF */
317 unsigned char *p = buf;
318# if NETSTACK_CONF_WITH_IPV6
319
320 assert(buf);
321 assert(len);
322 buf[0] = '\000';
323 if (len < 40 + 2 + 6)
324 return 0;
325
326 *p++ = '[';
327 memcpy(p, coap_print_ip_addr(addr, scratch, sizeof(scratch)), 40);
328 p += 40 - 1;
329 *p++ = ']';
330# else /* WITH_UIP6 */
331# warning "IPv4 network addresses will not be included in debug output"
332
333 if (len < 21) {
334 *p = '\000';
335 return 0;
336 }
337# endif /* WITH_UIP6 */
338
339 *p++ = ':';
340 *p++ = '0' + (coap_address_get_port(addr) / 10000) % 10;
341 *p++ = '0' + (coap_address_get_port(addr) / 1000) % 10;
342 *p++ = '0' + (coap_address_get_port(addr) / 100) % 10;
343 *p++ = '0' + (coap_address_get_port(addr) / 10) % 10;
344 *p++ = '0' + coap_address_get_port(addr) % 10;
345 *p = '\000';
346
347 return strlen((char *)buf);
348#endif /* HAVE_SNPRINTF */
349
350# elif WITH_LWIP
351
352 char scratch[INET6_ADDRSTRLEN];
353#ifdef HAVE_SNPRINTF
354
355 snprintf((char *)buf, len, "[%s]:%d",
356 coap_print_ip_addr(addr, scratch, sizeof(scratch)),
357 addr->port);
358 return strlen((char *)buf);
359#else /* HAVE_SNPRINTF */
360 unsigned char *p = buf;
361
362 assert(buf);
363 assert(len);
364 buf[0] = '\000';
365
366 switch (IP_GET_TYPE(addr->addr)) {
367 case IPADDR_TYPE_V4:
368 if (len < IP4ADDR_STRLEN_MAX + 6)
369 return 0;
370 memcpy(buf, coap_print_ip_addr(addr, scratch, sizeof(scratch)), IP4ADDR_STRLEN_MAX);
371 p += strlen((char *)buf);
372 break;
373#if LWIP_IPV6
374 case IPADDR_TYPE_V6:
375 case IPADDR_TYPE_ANY:
376 if (len < 40 + 2 + 6)
377 return 0;
378 *p++ = '[';
379 memcpy(p, coap_print_ip_addr(addr, scratch, sizeof(scratch)), 40);
380 p += strlen((char *)buf);
381 *p++ = ']';
382 break;
383#endif /* LWIP_IPV6 */
384 }
385
386 *p++ = ':';
387 *p++ = '0' + (addr->port / 10000) % 10;
388 *p++ = '0' + (addr->port / 1000) % 10;
389 *p++ = '0' + (addr->port / 100) % 10;
390 *p++ = '0' + (addr->port / 10) % 10;
391 *p++ = '0' + addr->port % 10;
392 *p = '\000';
393
394 return strlen((char *)buf);
395#endif /* HAVE_SNPRINTF */
396
397# else /* ! WITH_CONTIKI && ! WITH_LWIP */
398
399 (void)addr;
400 (void)len;
401
402 /* TODO: output addresses manually */
403# warning "inet_ntop() not available, network addresses will not be included in debug output"
404# endif /* ! WITH_CONTIKI && ! WITH_LWIP */
405 buf[0] = '\000';
406 return 0;
407#endif
408}
409
410/*
411 * Returned buf is always NULL terminated with as much as possible of the
412 * IP address filled in.
413 */
414const char *
415coap_print_ip_addr(const coap_address_t *addr, char *buf, size_t len) {
416#if (defined( HAVE_ARPA_INET_H ) || defined( HAVE_WS2TCPIP_H )) && !defined(RIOT_VERSION)
417 const void *addrptr = NULL;
418
419 assert(buf);
420 assert(len);
421 buf[0] = '\000';
422
423 switch (addr->addr.sa.sa_family) {
424#if COAP_IPV4_SUPPORT
425 case AF_INET:
426 if (len < INET_ADDRSTRLEN)
427 return buf;
428 addrptr = &addr->addr.sin.sin_addr;
429 break;
430#endif /* COAP_IPV4_SUPPORT */
431#if COAP_IPV6_SUPPORT
432 case AF_INET6:
433 if (len < INET6_ADDRSTRLEN)
434 return buf;
435 addrptr = &addr->addr.sin6.sin6_addr;
436 break;
437#endif /* COAP_IPV6_SUPPORT */
438#if COAP_AF_UNIX_SUPPORT
439 case AF_UNIX:
440 snprintf(buf, len, "%s", addr->addr.cun.sun_path);
441 return buf;
442#endif /* COAP_AF_UNIX_SUPPORT */
443 default:
444 /* Include trailing NULL if possible */
445 memcpy(buf, "(unknown address type)", min(22+1, len));
446 buf[len-1] = '\000';
447 return buf;
448 }
449
450 /* Cast needed for Windows, since it doesn't have the correct API signature. */
451 if (inet_ntop(addr->addr.sa.sa_family, addrptr, (char *)buf, len) == 0) {
452 coap_log_err("coap_print_ip_addr: inet_ntop\n");
453 buf[0] = '\000';
454 return buf;
455 }
456 return buf;
457
458#else /* HAVE_ARPA_INET_H */
459
460# if defined(RIOT_VERSION)
461 assert(buf);
462 assert(len);
463 buf[0] = '\000';
464
465 switch (addr->riot.family) {
466#if COAP_IPV4_SUPPORT
467 case AF_INET:
468 if (ipv4_addr_to_str(buf, (ipv4_addr_t *)&addr->riot.addr.ipv4, (size_t)len) == NULL) {
469 goto error;
470 }
471 break;
472#endif /* COAP_IPV4_SUPPORT */
473#if COAP_IPV6_SUPPORT
474 case AF_INET6:
475 if (ipv6_addr_to_str(buf, (ipv6_addr_t *)&addr->riot.addr.ipv6, (size_t)len) == NULL) {
476 goto error;
477 }
478 break;
479#endif /* COAP_IPV6_SUPPORT */
480 default:
481 goto error;
482 }
483 return buf;
484
485error:
486 coap_log_err("coap_print_ip_addr: inet_ntop\n");
487 buf[0] = '\000';
488 return buf;
489
490# elif WITH_CONTIKI
491 char *p = buf;
492 uint8_t i;
493# if NETSTACK_CONF_WITH_IPV6
494 const char hex[] = "0123456789ABCDEF";
495
496 assert(buf);
497 assert(len);
498 buf[0] = '\000';
499 if (len < 40)
500 return 0;
501
502 for (i=0; i < 16; i += 2) {
503 if (i) {
504 *p++ = ':';
505 }
506 *p++ = hex[(addr->addr.u8[i] & 0xf0) >> 4];
507 *p++ = hex[(addr->addr.u8[i] & 0x0f)];
508 *p++ = hex[(addr->addr.u8[i+1] & 0xf0) >> 4];
509 *p++ = hex[(addr->addr.u8[i+1] & 0x0f)];
510 }
511 *p = '\000';
512# else /* WITH_UIP6 */
513# warning "IPv4 network addresses will not be included in debug output"
514
515 if (len < 21) {
516 return buf;
517 }
518# endif /* WITH_UIP6 */
519 return buf;
520
521# elif WITH_LWIP
522
523 assert(buf);
524 assert(len);
525 buf[0] = '\000';
526
527 switch (IP_GET_TYPE(&addr->addr)) {
528#if LWIP_IPV4
529 case IPADDR_TYPE_V4:
530 if (len < IP4ADDR_STRLEN_MAX)
531 return buf;
532 memcpy(buf, ip4addr_ntoa(ip_2_ip4(&addr->addr)), IP4ADDR_STRLEN_MAX);
533 break;
534#endif /* LWIP_IPV4 */
535#if LWIP_IPV6
536 case IPADDR_TYPE_V6:
537 case IPADDR_TYPE_ANY:
538 if (len < 40)
539 return buf;
540#if LWIP_IPV4
541 memcpy(buf, ip6addr_ntoa(&addr->addr.u_addr.ip6), 40);
542#else /* LWIP_IPV4 */
543 memcpy(buf, ip6addr_ntoa(&addr->addr), 40);
544#endif /* LWIP_IPV4 */
545 break;
546#endif /* LWIP_IPV6 */
547 }
548 return buf;
549
550# else /* ! WITH_CONTIKI && ! WITH_LWIP */
551
552 (void)addr;
553 (void)len;
554
555 /* TODO: output addresses manually */
556# warning "inet_ntop() not available, network addresses will not be included in debug output"
557# endif /* WITH_CONTIKI */
558 buf[0] = '\000';
559 return buf;
560#endif
561}
562
564static const char *
565msg_type_string(uint16_t t) {
566 static const char *types[] = { "CON", "NON", "ACK", "RST", "???" };
567
568 return types[min(t, sizeof(types)/sizeof(char *) - 1)];
569}
570
572static const char *
573msg_code_string(uint16_t c) {
574 static const char *methods[] = { "0.00", "GET", "POST", "PUT", "DELETE",
575 "FETCH", "PATCH", "iPATCH"
576 };
577 static const char *signals[] = { "7.00", "CSM", "Ping", "Pong", "Release",
578 "Abort"
579 };
580 static char buf[5];
581
582 if (c < sizeof(methods)/sizeof(const char *)) {
583 return methods[c];
584 } else if (c >= 224 && c - 224 < (int)(sizeof(signals)/sizeof(const char *))) {
585 return signals[c-224];
586 } else {
587 snprintf(buf, sizeof(buf), "%u.%02u", (c >> 5) & 0x7, c & 0x1f);
588 return buf;
589 }
590}
591
593static const char *
594msg_option_string(uint8_t code, uint16_t option_type) {
595 struct option_desc_t {
596 uint16_t type;
597 const char *name;
598 };
599
600 static struct option_desc_t options[] = {
601 { COAP_OPTION_IF_MATCH, "If-Match" },
602 { COAP_OPTION_URI_HOST, "Uri-Host" },
603 { COAP_OPTION_ETAG, "ETag" },
604 { COAP_OPTION_IF_NONE_MATCH, "If-None-Match" },
605 { COAP_OPTION_OBSERVE, "Observe" },
606 { COAP_OPTION_URI_PORT, "Uri-Port" },
607 { COAP_OPTION_LOCATION_PATH, "Location-Path" },
608 { COAP_OPTION_OSCORE, "Oscore" },
609 { COAP_OPTION_URI_PATH, "Uri-Path" },
610 { COAP_OPTION_CONTENT_FORMAT, "Content-Format" },
611 { COAP_OPTION_MAXAGE, "Max-Age" },
612 { COAP_OPTION_URI_QUERY, "Uri-Query" },
613 { COAP_OPTION_HOP_LIMIT, "Hop-Limit" },
614 { COAP_OPTION_ACCEPT, "Accept" },
615 { COAP_OPTION_LOCATION_QUERY, "Location-Query" },
616 { COAP_OPTION_BLOCK2, "Block2" },
617 { COAP_OPTION_BLOCK1, "Block1" },
618 { COAP_OPTION_SIZE2, "Size2" },
619 { COAP_OPTION_PROXY_URI, "Proxy-Uri" },
620 { COAP_OPTION_PROXY_SCHEME, "Proxy-Scheme" },
621 { COAP_OPTION_SIZE1, "Size1" },
622 { COAP_OPTION_ECHO, "Echo" },
623 { COAP_OPTION_NORESPONSE, "No-Response" },
624 { COAP_OPTION_RTAG, "Request-Tag" },
625 { COAP_OPTION_Q_BLOCK1, "Q-Block1" },
626 { COAP_OPTION_Q_BLOCK2, "Q-Block2" }
627 };
628
629 static struct option_desc_t options_csm[] = {
630 { COAP_SIGNALING_OPTION_MAX_MESSAGE_SIZE, "Max-Message-Size" },
631 { COAP_SIGNALING_OPTION_BLOCK_WISE_TRANSFER, "Block-Wise-Transfer" },
632 { COAP_SIGNALING_OPTION_EXTENDED_TOKEN_LENGTH, "Extended-Token-Length" }
633 };
634
635 static struct option_desc_t options_pingpong[] = {
636 { COAP_SIGNALING_OPTION_CUSTODY, "Custody" }
637 };
638
639 static struct option_desc_t options_release[] = {
640 { COAP_SIGNALING_OPTION_ALTERNATIVE_ADDRESS, "Alternative-Address" },
641 { COAP_SIGNALING_OPTION_HOLD_OFF, "Hold-Off" }
642 };
643
644 static struct option_desc_t options_abort[] = {
645 { COAP_SIGNALING_OPTION_BAD_CSM_OPTION, "Bad-CSM-Option" }
646 };
647
648 static char buf[6];
649 size_t i;
650
651 if (code == COAP_SIGNALING_CSM) {
652 for (i = 0; i < sizeof(options_csm)/sizeof(struct option_desc_t); i++) {
653 if (option_type == options_csm[i].type) {
654 return options_csm[i].name;
655 }
656 }
657 } else if (code == COAP_SIGNALING_PING || code == COAP_SIGNALING_PONG) {
658 for (i = 0; i < sizeof(options_pingpong)/sizeof(struct option_desc_t); i++) {
659 if (option_type == options_pingpong[i].type) {
660 return options_pingpong[i].name;
661 }
662 }
663 } else if (code == COAP_SIGNALING_RELEASE) {
664 for (i = 0; i < sizeof(options_release)/sizeof(struct option_desc_t); i++) {
665 if (option_type == options_release[i].type) {
666 return options_release[i].name;
667 }
668 }
669 } else if (code == COAP_SIGNALING_ABORT) {
670 for (i = 0; i < sizeof(options_abort)/sizeof(struct option_desc_t); i++) {
671 if (option_type == options_abort[i].type) {
672 return options_abort[i].name;
673 }
674 }
675 } else {
676 /* search option_type in list of known options */
677 for (i = 0; i < sizeof(options)/sizeof(struct option_desc_t); i++) {
678 if (option_type == options[i].type) {
679 return options[i].name;
680 }
681 }
682 }
683 /* unknown option type, just print to buf */
684 snprintf(buf, sizeof(buf), "%u", option_type);
685 return buf;
686}
687
688static unsigned int
689print_content_format(unsigned int format_type,
690 unsigned char *result, unsigned int buflen) {
691 struct desc_t {
692 unsigned int type;
693 const char *name;
694 };
695
696 static struct desc_t formats[] = {
697 { COAP_MEDIATYPE_TEXT_PLAIN, "text/plain" },
698 { COAP_MEDIATYPE_APPLICATION_LINK_FORMAT, "application/link-format" },
699 { COAP_MEDIATYPE_APPLICATION_XML, "application/xml" },
700 { COAP_MEDIATYPE_APPLICATION_OCTET_STREAM, "application/octet-stream" },
701 { COAP_MEDIATYPE_APPLICATION_RDF_XML, "application/rdf+xml" },
702 { COAP_MEDIATYPE_APPLICATION_EXI, "application/exi" },
703 { COAP_MEDIATYPE_APPLICATION_JSON, "application/json" },
704 { COAP_MEDIATYPE_APPLICATION_CBOR, "application/cbor" },
705 { COAP_MEDIATYPE_APPLICATION_CWT, "application/cwt" },
706 { COAP_MEDIATYPE_APPLICATION_COAP_GROUP_JSON, "application/coap-group+json" },
707 { COAP_MEDIATYPE_APPLICATION_COSE_SIGN, "application/cose; cose-type=\"cose-sign\"" },
708 { COAP_MEDIATYPE_APPLICATION_COSE_SIGN1, "application/cose; cose-type=\"cose-sign1\"" },
709 { COAP_MEDIATYPE_APPLICATION_COSE_ENCRYPT, "application/cose; cose-type=\"cose-encrypt\"" },
710 { COAP_MEDIATYPE_APPLICATION_COSE_ENCRYPT0, "application/cose; cose-type=\"cose-encrypt0\"" },
711 { COAP_MEDIATYPE_APPLICATION_COSE_MAC, "application/cose; cose-type=\"cose-mac\"" },
712 { COAP_MEDIATYPE_APPLICATION_COSE_MAC0, "application/cose; cose-type=\"cose-mac0\"" },
713 { COAP_MEDIATYPE_APPLICATION_COSE_KEY, "application/cose-key" },
714 { COAP_MEDIATYPE_APPLICATION_COSE_KEY_SET, "application/cose-key-set" },
715 { COAP_MEDIATYPE_APPLICATION_SENML_JSON, "application/senml+json" },
716 { COAP_MEDIATYPE_APPLICATION_SENSML_JSON, "application/sensml+json" },
717 { COAP_MEDIATYPE_APPLICATION_SENML_CBOR, "application/senml+cbor" },
718 { COAP_MEDIATYPE_APPLICATION_SENSML_CBOR, "application/sensml+cbor" },
719 { COAP_MEDIATYPE_APPLICATION_SENML_EXI, "application/senml-exi" },
720 { COAP_MEDIATYPE_APPLICATION_SENSML_EXI, "application/sensml-exi" },
721 { COAP_MEDIATYPE_APPLICATION_SENML_XML, "application/senml+xml" },
722 { COAP_MEDIATYPE_APPLICATION_SENSML_XML, "application/sensml+xml" },
723 { COAP_MEDIATYPE_APPLICATION_DOTS_CBOR, "application/dots+cbor" },
724 { COAP_MEDIATYPE_APPLICATION_ACE_CBOR, "application/ace+cbor" },
725 { COAP_MEDIATYPE_APPLICATION_MB_CBOR_SEQ, "application/missing-blocks+cbor-seq" },
726 { COAP_MEDIATYPE_APPLICATION_OSCORE, "application/oscore" },
727 { 75, "application/dcaf+cbor" }
728 };
729
730 size_t i;
731
732 /* search format_type in list of known content formats */
733 for (i = 0; i < sizeof(formats)/sizeof(struct desc_t); i++) {
734 if (format_type == formats[i].type) {
735 return snprintf((char *)result, buflen, "%s", formats[i].name);
736 }
737 }
738
739 /* unknown content format, just print numeric value to buf */
740 return snprintf((char *)result, buflen, "%d", format_type);
741}
742
749is_binary(int content_format) {
750 return !(content_format == -1 ||
751 content_format == COAP_MEDIATYPE_TEXT_PLAIN ||
752 content_format == COAP_MEDIATYPE_APPLICATION_LINK_FORMAT ||
753 content_format == COAP_MEDIATYPE_APPLICATION_XML ||
754 content_format == COAP_MEDIATYPE_APPLICATION_JSON);
755}
756
757#define COAP_DO_SHOW_OUTPUT_LINE \
758 do { \
759 if (use_fprintf_for_show_pdu) { \
760 fprintf(COAP_DEBUG_FD, "%s", outbuf); \
761 } \
762 else { \
763 coap_log(level, "%s", outbuf); \
764 } \
765 } while (0)
766
767/*
768 * It is possible to override the output debug buffer size and hence control
769 * the amount of information printed out about a CoAP PDU.
770 * Note: Adding a byte may be insufficient to output the next byte of the PDU.
771 *
772 * This is done by the adding of a -DCOAP_DEBUG_BUF_SIZE=nnnn option to the
773 * CPPFLAGS parameter that is optionally used on the ./configure command line.
774 *
775 * E.g. ./configure CPPFLAGS="-DCOAP_DEBUG_BUF_SIZE=4096"
776 *
777 */
778
779#if COAP_DEBUG_BUF_SIZE < 5
780#error "COAP_DEBUG_BUF_SIZE must be at least 5, should be >= 32 to be useful"
781#endif /* COAP_DEBUG_BUF_SIZE < 5 */
782
783void
785#if COAP_CONSTRAINED_STACK
786 /* Proxy-Uri: can be 1034 bytes long */
787 /* buf and outbuf can be protected by global_lock if needed */
788 static unsigned char buf[min(COAP_DEBUG_BUF_SIZE, 1035)];
789 static char outbuf[COAP_DEBUG_BUF_SIZE];
790#else /* ! COAP_CONSTRAINED_STACK */
791 /* Proxy-Uri: can be 1034 bytes long */
792 unsigned char buf[min(COAP_DEBUG_BUF_SIZE, 1035)];
793 char outbuf[COAP_DEBUG_BUF_SIZE];
794#endif /* ! COAP_CONSTRAINED_STACK */
795 size_t buf_len = 0; /* takes the number of bytes written to buf */
796 int encode = 0, have_options = 0;
797 uint32_t i;
798 coap_opt_iterator_t opt_iter;
799 coap_opt_t *option;
800 int content_format = -1;
801 size_t data_len;
802 const uint8_t *data;
803 uint32_t opt_len;
804 const uint8_t *opt_val;
805 size_t outbuflen = 0;
806 int is_oscore_payload = 0;
807
808 /* Save time if not needed */
809 if (level > coap_get_log_level())
810 return;
811
812 if (!pdu->session || COAP_PROTO_NOT_RELIABLE(pdu->session->proto)) {
813 snprintf(outbuf, sizeof(outbuf), "v:%d t:%s c:%s i:%04x {",
815 msg_code_string(pdu->code), pdu->mid);
816 } else if (pdu->session->proto == COAP_PROTO_WS ||
817 pdu->session->proto == COAP_PROTO_WSS) {
818 if (pdu->type != COAP_MESSAGE_CON)
819 coap_log_alert("WebSocket: type != CON\n");
820 snprintf(outbuf, sizeof(outbuf), "v:WebSocket c:%s {",
821 msg_code_string(pdu->code));
822 } else {
823 if (pdu->type != COAP_MESSAGE_CON)
824 coap_log_alert("Reliable: type != CON\n");
825 snprintf(outbuf, sizeof(outbuf), "v:Reliable c:%s {",
826 msg_code_string(pdu->code));
827 }
828
829 for (i = 0; i < pdu->actual_token.length; i++) {
830 outbuflen = strlen(outbuf);
831 snprintf(&outbuf[outbuflen], sizeof(outbuf)-outbuflen,
832 "%02x", pdu->actual_token.s[i]);
833 }
834 outbuflen = strlen(outbuf);
835 snprintf(&outbuf[outbuflen], sizeof(outbuf)-outbuflen, "}");
836
837 /* show options, if any */
839
840 outbuflen = strlen(outbuf);
841 snprintf(&outbuf[outbuflen], sizeof(outbuf)-outbuflen, " [");
842 while ((option = coap_option_next(&opt_iter))) {
843 buf[0] = '\000';
844 if (!have_options) {
845 have_options = 1;
846 } else {
847 outbuflen = strlen(outbuf);
848 snprintf(&outbuf[outbuflen], sizeof(outbuf)-outbuflen, ",");
849 }
850
851 if (pdu->code == COAP_SIGNALING_CODE_CSM) {
852 switch (opt_iter.number) {
855 buf_len = snprintf((char *)buf, sizeof(buf), "%u",
857 coap_opt_length(option)));
858 break;
859 default:
860 buf_len = 0;
861 break;
862 }
863 } else if (pdu->code == COAP_SIGNALING_CODE_PING ||
865 buf_len = 0;
866 } else if (pdu->code == COAP_SIGNALING_CODE_RELEASE) {
867 switch (opt_iter.number) {
869 buf_len = print_readable(coap_opt_value(option),
870 coap_opt_length(option),
871 buf, sizeof(buf), 0);
872 break;
874 buf_len = snprintf((char *)buf, sizeof(buf), "%u",
876 coap_opt_length(option)));
877 break;
878 default:
879 buf_len = 0;
880 break;
881 }
882 } else if (pdu->code == COAP_SIGNALING_CODE_ABORT) {
883 switch (opt_iter.number) {
885 buf_len = snprintf((char *)buf, sizeof(buf), "%u",
887 coap_opt_length(option)));
888 break;
889 default:
890 buf_len = 0;
891 break;
892 }
893 } else {
894 switch (opt_iter.number) {
897 content_format = (int)coap_decode_var_bytes(coap_opt_value(option),
898 coap_opt_length(option));
899
900 buf_len = print_content_format(content_format, buf, sizeof(buf));
901 break;
902
907 /* split block option into number/more/size where more is the
908 * letter M if set, the _ otherwise */
909 if (COAP_OPT_BLOCK_SZX(option) == 7) {
910 if (coap_get_data(pdu, &data_len, &data))
911 buf_len = snprintf((char *)buf, sizeof(buf), "%u/%c/BERT(%zu)",
912 coap_opt_block_num(option), /* block number */
913 COAP_OPT_BLOCK_MORE(option) ? 'M' : '_', /* M bit */
914 data_len);
915 else
916 buf_len = snprintf((char *)buf, sizeof(buf), "%u/%c/BERT",
917 coap_opt_block_num(option), /* block number */
918 COAP_OPT_BLOCK_MORE(option) ? 'M' : '_'); /* M bit */
919 } else {
920 buf_len = snprintf((char *)buf, sizeof(buf), "%u/%c/%u",
921 coap_opt_block_num(option), /* block number */
922 COAP_OPT_BLOCK_MORE(option) ? 'M' : '_', /* M bit */
923 (1 << (COAP_OPT_BLOCK_SZX(option) + 4))); /* block size */
924 }
925
926 break;
927
929 opt_len = coap_opt_length(option);
930 buf[0] = '\000';
931 if (opt_len) {
932 size_t ofs = 1;
933 size_t cnt;
934
935 opt_val = coap_opt_value(option);
936 if (opt_val[0] & 0x20) {
937 /* Group Flag */
938 snprintf((char *)buf, sizeof(buf), "grp");
939 }
940 if (opt_val[0] & 0x07) {
941 /* Partial IV */
942 cnt = opt_val[0] & 0x07;
943 if (cnt > opt_len - ofs)
944 goto no_more;
945 buf_len = strlen((char *)buf);
946 snprintf((char *)&buf[buf_len], sizeof(buf)-buf_len, "%spIV=0x",
947 buf_len ? "," : "");
948 for (i = 0; (uint32_t)i < cnt; i++) {
949 buf_len = strlen((char *)buf);
950 snprintf((char *)&buf[buf_len], sizeof(buf)-buf_len,
951 "%02x", opt_val[ofs + i]);
952 }
953 ofs += cnt;
954 }
955 if (opt_val[0] & 0x10) {
956 /* kid context */
957 if (ofs >= opt_len)
958 goto no_more;
959 cnt = opt_val[ofs];
960 if (cnt > opt_len - ofs - 1)
961 goto no_more;
962 ofs++;
963 buf_len = strlen((char *)buf);
964 snprintf((char *)&buf[buf_len], sizeof(buf)-buf_len, "%skc=0x",
965 buf_len ? "," : "");
966 for (i = 0; (uint32_t)i < cnt; i++) {
967 buf_len = strlen((char *)buf);
968 snprintf((char *)&buf[buf_len], sizeof(buf)-buf_len,
969 "%02x", opt_val[ofs + i]);
970 }
971 ofs += cnt;
972 }
973 if (opt_val[0] & 0x08) {
974 /* kid */
975 if (ofs >= opt_len)
976 goto no_more;
977 cnt = opt_len - ofs;
978 buf_len = strlen((char *)buf);
979 snprintf((char *)&buf[buf_len], sizeof(buf)-buf_len, "%skid=0x",
980 buf_len ? "," : "");
981 for (i = 0; (uint32_t)i < cnt; i++) {
982 buf_len = strlen((char *)buf);
983 snprintf((char *)&buf[buf_len], sizeof(buf)-buf_len,
984 "%02x", opt_val[ofs + i]);
985 }
986 }
987 }
988no_more:
989 buf_len = strlen((char *)buf);
990 is_oscore_payload = 1;
991 break;
992
999 if (coap_opt_length(option)) {
1000 /* show values as unsigned decimal value */
1001 buf_len = snprintf((char *)buf, sizeof(buf), "%u",
1003 coap_opt_length(option)));
1004 }
1005 break;
1006
1008 case COAP_OPTION_ETAG:
1009 case COAP_OPTION_ECHO:
1011 case COAP_OPTION_RTAG:
1012 opt_len = coap_opt_length(option);
1013 opt_val = coap_opt_value(option);
1014 snprintf((char *)buf, sizeof(buf), "0x");
1015 for (i = 0; (uint32_t)i < opt_len; i++) {
1016 buf_len = strlen((char *)buf);
1017 snprintf((char *)&buf[buf_len], sizeof(buf)-buf_len,
1018 "%02x", opt_val[i]);
1019 }
1020 buf_len = strlen((char *)buf);
1021 break;
1022 default:
1023 /* generic output function for all other option types */
1024 if (opt_iter.number == COAP_OPTION_URI_PATH ||
1025 opt_iter.number == COAP_OPTION_PROXY_URI ||
1026 opt_iter.number == COAP_OPTION_URI_HOST ||
1027 opt_iter.number == COAP_OPTION_LOCATION_PATH ||
1028 opt_iter.number == COAP_OPTION_LOCATION_QUERY ||
1029 opt_iter.number == COAP_OPTION_PROXY_SCHEME ||
1030 opt_iter.number == COAP_OPTION_URI_QUERY) {
1031 encode = 0;
1032 } else {
1033 encode = 1;
1034 }
1035 buf_len = print_readable(coap_opt_value(option),
1036 coap_opt_length(option),
1037 buf, sizeof(buf), encode);
1038 }
1039 }
1040 outbuflen = strlen(outbuf);
1041 snprintf(&outbuf[outbuflen], sizeof(outbuf)-outbuflen,
1042 " %s:%.*s", msg_option_string(pdu->code, opt_iter.number),
1043 (int)buf_len, buf);
1044 }
1045
1046 outbuflen = strlen(outbuf);
1047 snprintf(&outbuf[outbuflen], sizeof(outbuf)-outbuflen, " ]");
1048
1049 if (coap_get_data(pdu, &data_len, &data)) {
1051 /* Only output data if wanted */
1052 outbuflen = strlen(outbuf);
1053 snprintf(&outbuf[outbuflen], sizeof(outbuf)-outbuflen, " :: ");
1054 outbuflen = strlen(outbuf);
1055 snprintf(&outbuf[outbuflen], sizeof(outbuf)-outbuflen,
1056 "data length %zu (data suppressed)\n", data_len);
1058 return;
1059 }
1060
1061 outbuflen = strlen(outbuf);
1062 snprintf(&outbuf[outbuflen], sizeof(outbuf)-outbuflen, " :: ");
1063
1064 if (is_binary(content_format) || !isprint(data[0]) || is_oscore_payload) {
1065 size_t keep_data_len = data_len;
1066 const uint8_t *keep_data = data;
1067
1068 outbuflen = strlen(outbuf);
1069 snprintf(&outbuf[outbuflen], sizeof(outbuf)-outbuflen,
1070 "binary data length %zu\n", data_len);
1072 /*
1073 * Output hex dump of binary data as a continuous entry
1074 */
1075 outbuf[0] = '\000';
1076 snprintf(outbuf, sizeof(outbuf), "<<");
1077 while (data_len--) {
1078 outbuflen = strlen(outbuf);
1079 snprintf(&outbuf[outbuflen], sizeof(outbuf)-outbuflen,
1080 "%02x", *data++);
1081 }
1082 outbuflen = strlen(outbuf);
1083 snprintf(&outbuf[outbuflen], sizeof(outbuf)-outbuflen, ">>");
1084 data_len = keep_data_len;
1085 data = keep_data;
1086 outbuflen = strlen(outbuf);
1087 if (outbuflen == sizeof(outbuf)-1)
1088 outbuflen--;
1089 snprintf(&outbuf[outbuflen], sizeof(outbuf)-outbuflen, "\n");
1091 /*
1092 * Output ascii readable (if possible), immediately under the
1093 * hex value of the character output above to help binary debugging
1094 */
1095 outbuf[0] = '\000';
1096 snprintf(outbuf, sizeof(outbuf), "<<");
1097 while (data_len--) {
1098 outbuflen = strlen(outbuf);
1099 snprintf(&outbuf[outbuflen], sizeof(outbuf)-outbuflen,
1100 "%c ", isprint(*data) ? *data : '.');
1101 data++;
1102 }
1103 outbuflen = strlen(outbuf);
1104 snprintf(&outbuf[outbuflen], sizeof(outbuf)-outbuflen, ">>");
1105 } else {
1106 size_t max_length;
1107
1108 outbuflen = strlen(outbuf);
1109 max_length = sizeof(outbuf)-outbuflen;
1110 if (max_length > 1) {
1111 outbuf[outbuflen++] = '\'';
1112 outbuf[outbuflen] = '\000';
1113 max_length--;
1114 }
1115 if (max_length > 1) {
1116 outbuflen += print_readable(data, data_len,
1117 (unsigned char *)&outbuf[outbuflen],
1118 max_length, 0);
1119 }
1120 /* print_readable may be handling unprintables - hence headroom of 4 */
1121 if (outbuflen < sizeof(outbuf)-4-1) {
1122 outbuf[outbuflen++] = '\'';
1123 outbuf[outbuflen] = '\000';
1124 }
1125 }
1126 }
1127
1128 outbuflen = strlen(outbuf);
1129 if (outbuflen == sizeof(outbuf)-1)
1130 outbuflen--;
1131 snprintf(&outbuf[outbuflen], sizeof(outbuf)-outbuflen, "\n");
1133}
1134
1135void
1137 char buffer[128];
1138 coap_string_tls_version(buffer, sizeof(buffer));
1139 coap_log(level, "%s\n", buffer);
1140}
1141
1142char *
1143coap_string_tls_version(char *buffer, size_t bufsize) {
1145 char beta[8];
1146 char sub[2];
1147 char b_beta[8];
1148 char b_sub[2];
1149
1150 switch (tls_version->type) {
1152 snprintf(buffer, bufsize, "TLS Library: None");
1153 break;
1155 snprintf(buffer, bufsize, "TLS Library: TinyDTLS - runtime %lu.%lu.%lu, "
1156 "libcoap built for %lu.%lu.%lu",
1157 (unsigned long)(tls_version->version >> 16),
1158 (unsigned long)((tls_version->version >> 8) & 0xff),
1159 (unsigned long)(tls_version->version & 0xff),
1160 (unsigned long)(tls_version->built_version >> 16),
1161 (unsigned long)((tls_version->built_version >> 8) & 0xff),
1162 (unsigned long)(tls_version->built_version & 0xff));
1163 break;
1165 switch (tls_version->version &0xf) {
1166 case 0:
1167 strcpy(beta, "-dev");
1168 break;
1169 case 0xf:
1170 strcpy(beta, "");
1171 break;
1172 default:
1173 strcpy(beta, "-beta");
1174 beta[5] = (tls_version->version &0xf) + '0';
1175 beta[6] = '\000';
1176 break;
1177 }
1178 sub[0] = ((tls_version->version >> 4) & 0xff) ?
1179 ((tls_version->version >> 4) & 0xff) + 'a' -1 : '\000';
1180 sub[1] = '\000';
1181 switch (tls_version->built_version &0xf) {
1182 case 0:
1183 strcpy(b_beta, "-dev");
1184 break;
1185 case 0xf:
1186 strcpy(b_beta, "");
1187 break;
1188 default:
1189 strcpy(b_beta, "-beta");
1190 b_beta[5] = (tls_version->built_version &0xf) + '0';
1191 b_beta[6] = '\000';
1192 break;
1193 }
1194 b_sub[0] = ((tls_version->built_version >> 4) & 0xff) ?
1195 ((tls_version->built_version >> 4) & 0xff) + 'a' -1 : '\000';
1196 b_sub[1] = '\000';
1197 snprintf(buffer, bufsize, "TLS Library: OpenSSL - runtime "
1198 "%lu.%lu.%lu%s%s, libcoap built for %lu.%lu.%lu%s%s",
1199 (unsigned long)(tls_version->version >> 28),
1200 (unsigned long)((tls_version->version >> 20) & 0xff),
1201 (unsigned long)((tls_version->version >> 12) & 0xff), sub, beta,
1202 (unsigned long)(tls_version->built_version >> 28),
1203 (unsigned long)((tls_version->built_version >> 20) & 0xff),
1204 (unsigned long)((tls_version->built_version >> 12) & 0xff),
1205 b_sub, b_beta);
1206 break;
1208 snprintf(buffer, bufsize, "TLS Library: GnuTLS - runtime %lu.%lu.%lu, "
1209 "libcoap built for %lu.%lu.%lu",
1210 (unsigned long)(tls_version->version >> 16),
1211 (unsigned long)((tls_version->version >> 8) & 0xff),
1212 (unsigned long)(tls_version->version & 0xff),
1213 (unsigned long)(tls_version->built_version >> 16),
1214 (unsigned long)((tls_version->built_version >> 8) & 0xff),
1215 (unsigned long)(tls_version->built_version & 0xff));
1216 break;
1218 snprintf(buffer, bufsize, "TLS Library: Mbed TLS - runtime %lu.%lu.%lu, "
1219 "libcoap built for %lu.%lu.%lu",
1220 (unsigned long)(tls_version->version >> 24),
1221 (unsigned long)((tls_version->version >> 16) & 0xff),
1222 (unsigned long)((tls_version->version >> 8) & 0xff),
1223 (unsigned long)(tls_version->built_version >> 24),
1224 (unsigned long)((tls_version->built_version >> 16) & 0xff),
1225 (unsigned long)((tls_version->built_version >> 8) & 0xff));
1226 break;
1228 snprintf(buffer, bufsize, "TLS Library: wolfSSL - runtime %lu.%lu.%lu, "
1229 "libcoap built for %lu.%lu.%lu",
1230 (unsigned long)(tls_version->version >> 24),
1231 (unsigned long)((tls_version->version >> 12) & 0xfff),
1232 (unsigned long)((tls_version->version >> 0) & 0xfff),
1233 (unsigned long)(tls_version->built_version >> 24),
1234 (unsigned long)((tls_version->built_version >> 12) & 0xfff),
1235 (unsigned long)((tls_version->built_version >> 0) & 0xfff));
1236 break;
1237 default:
1238 snprintf(buffer, bufsize, "Library type %d unknown", tls_version->type);
1239 break;
1240 }
1241 return buffer;
1242}
1243
1244char *
1245coap_string_tls_support(char *buffer, size_t bufsize) {
1246 const int have_tls = coap_tls_is_supported();
1247 const int have_dtls = coap_dtls_is_supported();
1248 const int have_psk = coap_dtls_psk_is_supported();
1249 const int have_pki = coap_dtls_pki_is_supported();
1250 const int have_pkcs11 = coap_dtls_pkcs11_is_supported();
1251 const int have_rpk = coap_dtls_rpk_is_supported();
1252 const int have_cid = coap_dtls_cid_is_supported();
1253 const int have_oscore = coap_oscore_is_supported();
1254 const int have_ws = coap_ws_is_supported();
1255
1256 if (have_dtls == 0 && have_tls == 0) {
1257 snprintf(buffer, bufsize, "(No DTLS or TLS support)");
1258 return buffer;
1259 }
1260 snprintf(buffer, bufsize,
1261 "(%sDTLS and %sTLS support; %sPSK, %sPKI, %sPKCS11, %sRPK and %sCID support)\n(%sOSCORE)\n(%sWebSockets)",
1262 have_dtls ? "" : "No ",
1263 have_tls ? "" : "no ",
1264 have_psk ? "" : "no ",
1265 have_pki ? "" : "no ",
1266 have_pkcs11 ? "" : "no ",
1267 have_rpk ? "" : "no ",
1268 have_cid ? "" : "no ",
1269 have_oscore ? "Have " : "No ",
1270 have_ws ? "Have " : "No ");
1271 return buffer;
1272}
1273
1275
1276void
1278 log_handler = handler;
1279}
1280
1281void
1282coap_log_impl(coap_log_t level, const char *format, ...) {
1283
1284 if (log_handler) {
1285#if COAP_CONSTRAINED_STACK
1286 /* message can be protected by global_lock if needed */
1287 static char message[COAP_DEBUG_BUF_SIZE];
1288#else /* ! COAP_CONSTRAINED_STACK */
1289 char message[COAP_DEBUG_BUF_SIZE];
1290#endif /* ! COAP_CONSTRAINED_STACK */
1291 va_list ap;
1292 va_start(ap, format);
1293
1294#ifdef RIOT_VERSION
1295 flash_vsnprintf(message, sizeof(message), format, ap);
1296#else /* !RIOT_VERSION */
1297 vsnprintf(message, sizeof(message), format, ap);
1298#endif /* !RIOT_VERSION */
1299 va_end(ap);
1300 log_handler(level, message);
1301 } else {
1302 char timebuf[32];
1303 coap_tick_t now;
1304 va_list ap;
1305 FILE *log_fd;
1306 size_t len;
1307
1308 log_fd = level <= COAP_LOG_CRIT ? COAP_ERR_FD : COAP_DEBUG_FD;
1309
1310 coap_ticks(&now);
1311 len = print_timestamp(timebuf,sizeof(timebuf), now);
1312 if (len)
1313 fprintf(log_fd, "%.*s ", (int)len, timebuf);
1314
1315 fprintf(log_fd, "%s ", coap_log_level_desc(level));
1316
1317 va_start(ap, format);
1318#ifdef RIOT_VERSION
1319 flash_vfprintf(log_fd, format, ap);
1320#else /* !RIOT_VERSION */
1321 vfprintf(log_fd, format, ap);
1322#endif /* !RIOT_VERSION */
1323 va_end(ap);
1324 fflush(log_fd);
1325 }
1326}
1327
1328static struct packet_num_interval {
1330 int end;
1333static uint16_t packet_loss_level = 0;
1334static int send_packet_count = 0;
1335
1336int
1337coap_debug_set_packet_loss(const char *loss_level) {
1338 const char *p = loss_level;
1339 char *end = NULL;
1340 int n = (int)strtol(p, &end, 10), i = 0;
1341 if (end == p || n < 0)
1342 return 0;
1343 if (*end == '%') {
1344 if (n > 100)
1345 n = 100;
1346 packet_loss_level = n * 65536 / 100;
1347 coap_log_debug("packet loss level set to %d%%\n", n);
1348 } else {
1349 if (n <= 0)
1350 return 0;
1351 while (i < 10) {
1353 if (*end == '-') {
1354 p = end + 1;
1355 n = (int)strtol(p, &end, 10);
1356 if (end == p || n <= 0)
1357 return 0;
1358 }
1359 packet_loss_intervals[i++].end = n;
1360 if (*end == 0)
1361 break;
1362 if (*end != ',')
1363 return 0;
1364 p = end + 1;
1365 n = (int)strtol(p, &end, 10);
1366 if (end == p || n <= 0)
1367 return 0;
1368 }
1369 if (i == 10)
1370 return 0;
1372 }
1374 return 1;
1375}
1376
1377int
1380 if (num_packet_loss_intervals > 0) {
1381 int i;
1382 for (i = 0; i < num_packet_loss_intervals; i++) {
1383 if (send_packet_count >= packet_loss_intervals[i].start &&
1385 coap_log_debug("Packet %u dropped\n", send_packet_count);
1386 return 0;
1387 }
1388 }
1389 }
1390 if (packet_loss_level > 0) {
1391 uint16_t r = 0;
1392 coap_prng_lkd((uint8_t *)&r, 2);
1393 if (r < packet_loss_level) {
1394 coap_log_debug("Packet %u dropped\n", send_packet_count);
1395 return 0;
1396 }
1397 }
1398 return 1;
1399}
1400
1401void
1403 log_handler = NULL;
1406 memset(&packet_loss_intervals, 0, sizeof(packet_loss_intervals));
1410}
uint16_t coap_address_get_port(const coap_address_t *addr)
Returns the port from addr in host byte order.
Definition: coap_address.c:44
static uint16_t packet_loss_level
Definition: coap_debug.c:1333
static struct packet_num_interval packet_loss_intervals[10]
static int send_packet_count
Definition: coap_debug.c:1334
int coap_debug_set_packet_loss(const char *loss_level)
Set the packet loss level for testing.
Definition: coap_debug.c:1337
static coap_log_t maxlog
Definition: coap_debug.c:61
static coap_log_handler_t log_handler
Definition: coap_debug.c:1274
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:749
static int enable_data_for_show_pdu
Definition: coap_debug.c:69
static const char * msg_code_string(uint16_t c)
Returns a textual description of the method or response code.
Definition: coap_debug.c:573
#define COAP_DO_SHOW_OUTPUT_LINE
Definition: coap_debug.c:757
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:190
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:594
static size_t strnlen(const char *s, size_t maxlen)
A length-safe strlen() fake.
Definition: coap_debug.c:181
static const char * loglevels[]
Definition: coap_debug.c:114
COAP_STATIC_INLINE size_t print_timestamp(char *s, size_t len, coap_tick_t t)
Definition: coap_debug.c:158
#define min(a, b)
Definition: coap_debug.c:228
static const char * msg_type_string(uint16_t t)
Returns a textual description of the message type t.
Definition: coap_debug.c:565
static int use_fprintf_for_show_pdu
Definition: coap_debug.c:68
static int num_packet_loss_intervals
Definition: coap_debug.c:1332
int coap_debug_send_packet(void)
Check to see whether a packet should be sent or not.
Definition: coap_debug.c:1378
void coap_debug_reset(void)
Reset all the defined logging parameters.
Definition: coap_debug.c:1402
static unsigned int print_content_format(unsigned int format_type, unsigned char *result, unsigned int buflen)
Definition: coap_debug.c:689
#define INET6_ADDRSTRLEN
Definition: coap_debug.c:232
Library specific build wrapper for coap_internal.h.
uint8_t coap_opt_t
Use byte-oriented access methods here because sliding a complex struct coap_opt_t over the data buffe...
Definition: coap_option.h:26
#define COAP_OPT_BLOCK_SZX(opt)
Returns the value of the SZX-field of a Block option opt.
Definition: coap_block.h:89
#define COAP_OPT_BLOCK_MORE(opt)
Returns the value of the More-bit of a Block option opt.
Definition: coap_block.h:85
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: coap_block.c:35
uint64_t coap_tick_t
This data type represents internal timer ticks with COAP_TICKS_PER_SECOND resolution.
Definition: coap_time.h:143
coap_time_t coap_ticks_to_rt(coap_tick_t t)
Helper function that converts coap ticks to wallclock time.
uint64_t coap_ticks_to_rt_us(coap_tick_t t)
Helper function that converts coap ticks to POSIX wallclock time in us.
int coap_prng_lkd(void *buf, size_t len)
Fills buf with len random bytes using the default pseudo random number generator.
Definition: coap_prng.c:178
void coap_ticks(coap_tick_t *)
Returns the current value of an internal tick counter.
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:100
@ COAP_TLS_LIBRARY_WOLFSSL
Using wolfSSL library.
Definition: coap_dtls.h:76
@ COAP_TLS_LIBRARY_GNUTLS
Using GnuTLS library.
Definition: coap_dtls.h:74
@ COAP_TLS_LIBRARY_TINYDTLS
Using TinyDTLS library.
Definition: coap_dtls.h:72
@ COAP_TLS_LIBRARY_NOTLS
No DTLS library.
Definition: coap_dtls.h:71
@ COAP_TLS_LIBRARY_OPENSSL
Using OpenSSL library.
Definition: coap_dtls.h:73
@ COAP_TLS_LIBRARY_MBEDTLS
Using Mbed TLS library.
Definition: coap_dtls.h:75
unsigned int coap_decode_var_bytes(const uint8_t *buf, size_t len)
Decodes multiple-length byte sequences.
Definition: coap_encode.c:38
void coap_set_log_handler(coap_log_handler_t handler)
Add a custom log callback handler.
Definition: coap_debug.c:1277
const char * coap_log_level_desc(coap_log_t level)
Get the current logging description.
Definition: coap_debug.c:122
#define coap_log_debug(...)
Definition: coap_debug.h:120
coap_log_t coap_get_log_level(void)
Get the current logging level.
Definition: coap_debug.c:101
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:1143
#define coap_log_alert(...)
Definition: coap_debug.h:84
void coap_show_pdu(coap_log_t level, const coap_pdu_t *pdu)
Display the contents of the specified pdu.
Definition: coap_debug.c:784
void coap_enable_pdu_data_output(int enable_data)
Defines whether the data is to be output or not for the coap_show_pdu() function.
Definition: coap_debug.c:96
char * coap_string_tls_support(char *buffer, size_t bufsize)
Build a string containing the current (D)TLS library support.
Definition: coap_debug.c:1245
#define COAP_MAX_LOGGING_LEVEL
Definition: coap_debug.h:42
#define COAP_ERR_FD
Used for output for COAP_LOG_CRIT to COAP_LOG_EMERG.
Definition: coap_debug.h:38
coap_log_t
Logging type.
Definition: coap_debug.h:50
const char * coap_package_version(void)
Get the library package version.
Definition: coap_debug.c:77
void coap_set_log_level(coap_log_t level)
Sets the log level to the specified value.
Definition: coap_debug.c:106
void coap_log_impl(coap_log_t level, const char *format,...)
Writes the given text to COAP_ERR_FD (for level <= COAP_LOG_CRIT) or COAP_DEBUG_FD (for level >= COAP...
Definition: coap_debug.c:1282
size_t coap_print_addr(const coap_address_t *addr, unsigned char *buf, size_t len)
Print the address into the defined buffer.
Definition: coap_debug.c:239
#define COAP_DEBUG_FD
Used for output for COAP_LOG_OSCORE to COAP_LOG_ERR.
Definition: coap_debug.h:31
const char * coap_package_build(void)
Get the library package build.
Definition: coap_debug.c:82
const char * coap_print_ip_addr(const coap_address_t *addr, char *buf, size_t len)
Print the IP address into the defined buffer.
Definition: coap_debug.c:415
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:1136
void coap_set_show_pdu_output(int use_fprintf)
Defines the output mode for the coap_show_pdu() function.
Definition: coap_debug.c:91
#define coap_log_err(...)
Definition: coap_debug.h:96
const char * coap_package_name(void)
Get the library package name.
Definition: coap_debug.c:72
void(* coap_log_handler_t)(coap_log_t level, const char *message)
Logging callback handler definition.
Definition: coap_debug.h:209
#define coap_log(level,...)
Logging function.
Definition: coap_debug.h:284
@ COAP_LOG_INFO
Definition: coap_debug.h:57
@ COAP_LOG_EMERG
Definition: coap_debug.h:51
@ COAP_LOG_DEBUG
Definition: coap_debug.h:58
@ COAP_LOG_CRIT
Definition: coap_debug.h:53
@ COAP_LOG_ERR
Definition: coap_debug.h:54
@ COAP_LOG_WARN
Definition: coap_debug.h:55
coap_opt_t * coap_option_next(coap_opt_iterator_t *oi)
Updates the iterator oi to point to the next option.
Definition: coap_option.c:153
uint32_t coap_opt_length(const coap_opt_t *opt)
Returns the length of the given option.
Definition: coap_option.c:212
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's option list.
Definition: coap_option.c:117
#define COAP_OPT_ALL
Pre-defined filter that includes all options.
Definition: coap_option.h:108
const uint8_t * coap_opt_value(const coap_opt_t *opt)
Returns a pointer to the value of the given option.
Definition: coap_option.c:249
#define COAP_DEFAULT_VERSION
#define COAP_OPTION_HOP_LIMIT
Definition: coap_pdu.h:133
#define COAP_OPTION_NORESPONSE
Definition: coap_pdu.h:145
#define COAP_OPTION_URI_HOST
Definition: coap_pdu.h:120
#define COAP_OPTION_IF_MATCH
Definition: coap_pdu.h:119
#define COAP_MEDIATYPE_APPLICATION_COSE_MAC
Definition: coap_pdu.h:231
#define COAP_MEDIATYPE_APPLICATION_SENSML_EXI
Definition: coap_pdu.h:243
#define COAP_MEDIATYPE_APPLICATION_CWT
Definition: coap_pdu.h:221
#define COAP_OPTION_BLOCK2
Definition: coap_pdu.h:137
#define COAP_MEDIATYPE_APPLICATION_MB_CBOR_SEQ
Definition: coap_pdu.h:254
#define COAP_MEDIATYPE_APPLICATION_COSE_ENCRYPT
Definition: coap_pdu.h:229
#define COAP_MEDIATYPE_APPLICATION_RDF_XML
Definition: coap_pdu.h:217
#define COAP_OPTION_CONTENT_FORMAT
Definition: coap_pdu.h:128
#define COAP_SIGNALING_OPTION_ALTERNATIVE_ADDRESS
Definition: coap_pdu.h:205
#define COAP_OPTION_SIZE2
Definition: coap_pdu.h:139
#define COAP_MEDIATYPE_APPLICATION_SENSML_XML
Definition: coap_pdu.h:245
#define COAP_MEDIATYPE_APPLICATION_COSE_SIGN
Definition: coap_pdu.h:227
#define COAP_OPTION_BLOCK1
Definition: coap_pdu.h:138
#define COAP_OPTION_Q_BLOCK1
Definition: coap_pdu.h:135
#define COAP_OPTION_PROXY_SCHEME
Definition: coap_pdu.h:142
#define COAP_MEDIATYPE_APPLICATION_COSE_KEY_SET
Definition: coap_pdu.h:235
#define COAP_MEDIATYPE_APPLICATION_OSCORE
Definition: coap_pdu.h:257
#define COAP_MEDIATYPE_APPLICATION_SENML_CBOR
Definition: coap_pdu.h:240
#define COAP_OPTION_URI_QUERY
Definition: coap_pdu.h:132
#define COAP_MEDIATYPE_APPLICATION_COSE_KEY
Definition: coap_pdu.h:234
#define COAP_MEDIATYPE_APPLICATION_COSE_SIGN1
Definition: coap_pdu.h:228
#define COAP_OPTION_IF_NONE_MATCH
Definition: coap_pdu.h:122
#define COAP_MEDIATYPE_APPLICATION_OCTET_STREAM
Definition: coap_pdu.h:216
#define COAP_OPTION_LOCATION_PATH
Definition: coap_pdu.h:125
#define COAP_OPTION_URI_PATH
Definition: coap_pdu.h:127
#define COAP_SIGNALING_OPTION_EXTENDED_TOKEN_LENGTH
Definition: coap_pdu.h:199
#define COAP_MEDIATYPE_APPLICATION_SENML_EXI
Definition: coap_pdu.h:242
#define COAP_OPTION_OSCORE
Definition: coap_pdu.h:126
#define COAP_MEDIATYPE_APPLICATION_CBOR
Definition: coap_pdu.h:220
#define COAP_OPTION_SIZE1
Definition: coap_pdu.h:143
#define COAP_MEDIATYPE_APPLICATION_COSE_ENCRYPT0
Definition: coap_pdu.h:230
#define COAP_SIGNALING_OPTION_BLOCK_WISE_TRANSFER
Definition: coap_pdu.h:198
#define COAP_MEDIATYPE_TEXT_PLAIN
Definition: coap_pdu.h:213
#define COAP_MEDIATYPE_APPLICATION_JSON
Definition: coap_pdu.h:219
#define COAP_OPTION_LOCATION_QUERY
Definition: coap_pdu.h:136
#define COAP_MEDIATYPE_APPLICATION_COSE_MAC0
Definition: coap_pdu.h:232
#define COAP_MEDIATYPE_APPLICATION_ACE_CBOR
Definition: coap_pdu.h:251
#define COAP_OPTION_Q_BLOCK2
Definition: coap_pdu.h:140
#define COAP_MEDIATYPE_APPLICATION_SENML_JSON
Definition: coap_pdu.h:238
#define COAP_MEDIATYPE_APPLICATION_EXI
Definition: coap_pdu.h:218
#define COAP_SIGNALING_OPTION_CUSTODY
Definition: coap_pdu.h:202
int coap_get_data(const coap_pdu_t *pdu, size_t *len, const uint8_t **data)
Retrieves the length and data pointer of specified PDU.
Definition: coap_pdu.c:865
#define COAP_OPTION_RTAG
Definition: coap_pdu.h:146
#define COAP_MEDIATYPE_APPLICATION_COAP_GROUP_JSON
Definition: coap_pdu.h:224
#define COAP_OPTION_URI_PORT
Definition: coap_pdu.h:124
#define COAP_MEDIATYPE_APPLICATION_SENML_XML
Definition: coap_pdu.h:244
#define COAP_OPTION_ACCEPT
Definition: coap_pdu.h:134
#define COAP_MEDIATYPE_APPLICATION_DOTS_CBOR
Definition: coap_pdu.h:248
#define COAP_OPTION_MAXAGE
Definition: coap_pdu.h:131
#define COAP_OPTION_ETAG
Definition: coap_pdu.h:121
#define COAP_MEDIATYPE_APPLICATION_SENSML_JSON
Definition: coap_pdu.h:239
#define COAP_OPTION_PROXY_URI
Definition: coap_pdu.h:141
#define COAP_OPTION_OBSERVE
Definition: coap_pdu.h:123
#define COAP_SIGNALING_OPTION_HOLD_OFF
Definition: coap_pdu.h:206
#define COAP_OPTION_ECHO
Definition: coap_pdu.h:144
#define COAP_MEDIATYPE_APPLICATION_LINK_FORMAT
Definition: coap_pdu.h:214
#define COAP_SIGNALING_OPTION_BAD_CSM_OPTION
Definition: coap_pdu.h:209
#define COAP_SIGNALING_OPTION_MAX_MESSAGE_SIZE
Definition: coap_pdu.h:197
#define COAP_MEDIATYPE_APPLICATION_XML
Definition: coap_pdu.h:215
#define COAP_MEDIATYPE_APPLICATION_SENSML_CBOR
Definition: coap_pdu.h:241
@ COAP_PROTO_WS
Definition: coap_pdu.h:318
@ COAP_PROTO_WSS
Definition: coap_pdu.h:319
@ COAP_SIGNALING_CODE_ABORT
Definition: coap_pdu.h:369
@ COAP_SIGNALING_CODE_CSM
Definition: coap_pdu.h:365
@ COAP_SIGNALING_CODE_PING
Definition: coap_pdu.h:366
@ COAP_SIGNALING_CODE_PONG
Definition: coap_pdu.h:367
@ COAP_SIGNALING_CODE_RELEASE
Definition: coap_pdu.h:368
@ COAP_MESSAGE_CON
Definition: coap_pdu.h:69
@ COAP_SIGNALING_RELEASE
Definition: coap_pdu.h:192
@ COAP_SIGNALING_CSM
Definition: coap_pdu.h:189
@ COAP_SIGNALING_PONG
Definition: coap_pdu.h:191
@ COAP_SIGNALING_PING
Definition: coap_pdu.h:190
@ COAP_SIGNALING_ABORT
Definition: coap_pdu.h:193
#define COAP_PROTO_NOT_RELIABLE(p)
Definition: coap_session.h:37
int coap_dtls_cid_is_supported(void)
Check whether (D)TLS CID is available.
Definition: coap_notls.c:86
int coap_dtls_psk_is_supported(void)
Check whether (D)TLS PSK is available.
Definition: coap_notls.c:50
int coap_tls_is_supported(void)
Check whether TLS is available.
Definition: coap_notls.c:41
int coap_ws_is_supported(void)
Check whether WebSockets is available.
Definition: coap_ws.c:933
int coap_oscore_is_supported(void)
Check whether OSCORE is available.
Definition: coap_oscore.c:2195
int coap_dtls_is_supported(void)
Check whether DTLS is available.
Definition: coap_notls.c:36
int coap_dtls_pki_is_supported(void)
Check whether (D)TLS PKI is available.
Definition: coap_notls.c:59
int coap_dtls_rpk_is_supported(void)
Check whether (D)TLS RPK is available.
Definition: coap_notls.c:77
int coap_dtls_pkcs11_is_supported(void)
Check whether (D)TLS PKCS11 is available.
Definition: coap_notls.c:68
#define COAP_STATIC_INLINE
Definition: libcoap.h:53
Multi-purpose address abstraction.
Definition: coap_address.h:148
struct sockaddr_in sin
Definition: coap_address.h:152
struct coap_sockaddr_un cun
Definition: coap_address.h:154
struct sockaddr_in6 sin6
Definition: coap_address.h:153
struct sockaddr sa
Definition: coap_address.h:151
union coap_address_t::@0 addr
size_t length
length of binary data
Definition: coap_str.h:65
const uint8_t * s
read-only binary data
Definition: coap_str.h:66
Iterator to run through PDU options.
Definition: coap_option.h:168
coap_option_num_t number
decoded option number
Definition: coap_option.h:170
structure for CoAP PDUs
coap_pdu_code_t code
request method (value 1–31) or response code (value 64-255)
coap_bin_const_t actual_token
Actual token in pdu.
coap_mid_t mid
message id, if any, in regular host byte order
coap_session_t * session
Session responsible for PDU or NULL.
coap_pdu_type_t type
message type
coap_proto_t proto
protocol used
char sun_path[COAP_UNIX_PATH_MAX]
Definition: coap_address.h:144
The structure used for returning the underlying (D)TLS library information.
Definition: coap_dtls.h:83
uint64_t built_version
(D)TLS Built against Library Version
Definition: coap_dtls.h:86
coap_tls_library_t type
Library type.
Definition: coap_dtls.h:85
uint64_t version
(D)TLS runtime Library Version
Definition: coap_dtls.h:84