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