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