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