Coverage Report

Created: 2026-08-31 06:41

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libcoap/src/coap_debug.c
Line
Count
Source
1
/* coap_debug.c -- debug utilities
2
 *
3
 * Copyright (C) 2010--2012,2014--2026 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
11
/**
12
 * @file coap_debug.c
13
 * @brief Debug utilities
14
 */
15
16
#include "coap3/coap_libcoap_build.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
#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
53
static coap_log_t maxlog = LOG_CONF_LEVEL_COAP == 0 ? /* = LOG_LEVEL_NONE */
54
                           COAP_LOG_EMERG :
55
                           (LOG_CONF_LEVEL_COAP == 1 ?  /* = LOG_LEVEL_ERR */
56
                            COAP_LOG_ERR :
57
                            (LOG_CONF_LEVEL_COAP == 2 ?  /* = LOG_LEVEL_WARN */
58
                             COAP_LOG_WARN :
59
                             (LOG_CONF_LEVEL_COAP == 3 ? /* = LOG_LEVEL_INFO */
60
                              COAP_LOG_INFO :
61
                              COAP_LOG_DEBUG)));
62
#else /* !WITH_CONTIKI */
63
static 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
70
static int use_fprintf_for_show_pdu = 1; /* non zero to output with fprintf */
71
static int enable_data_for_show_pdu = 1; /* By default show PDU data for coap_show_pdu() */
72
73
const char *
74
0
coap_package_name(void) {
75
0
  return PACKAGE_NAME;
76
0
}
77
78
const char *
79
0
coap_package_version(void) {
80
0
  return PACKAGE_STRING;
81
0
}
82
83
const char *
84
0
coap_package_build(void) {
85
0
#ifdef LIBCOAP_PACKAGE_BUILD
86
0
  return LIBCOAP_PACKAGE_BUILD;
87
#else /* !LIBCOAP_PACKAGE_BUILD */
88
  return PACKAGE_STRING;
89
#endif /* !LIBCOAP_PACKAGE_BUILD */
90
0
}
91
92
void
93
0
coap_set_show_pdu_output(int use_fprintf) {
94
0
  use_fprintf_for_show_pdu = use_fprintf;
95
0
}
96
97
void
98
0
coap_enable_pdu_data_output(int enable_data) {
99
0
  enable_data_for_show_pdu = enable_data;
100
0
}
101
102
coap_log_t
103
7.20k
coap_get_log_level(void) {
104
7.20k
  return maxlog;
105
7.20k
}
106
107
void
108
60
coap_set_log_level(coap_log_t level) {
109
60
  if (level > COAP_MAX_LOGGING_LEVEL)
110
0
    level = COAP_MAX_LOGGING_LEVEL;
111
60
  maxlog = level;
112
60
}
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 */
116
static 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
123
const char *
124
0
coap_log_level_desc(coap_log_t level) {
125
0
  static char bad[8];
126
0
  if (level >= sizeof(loglevels)/sizeof(loglevels[0])) {
127
0
    snprintf(bad, sizeof(bad), "%4d", level);
128
0
    return bad;
129
0
  } else {
130
0
    return loglevels[level];
131
0
  }
132
0
}
133
134
#ifdef WITH_CONTIKI
135
void
136
coap_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
143
COAP_STATIC_INLINE size_t
144
0
print_timestamp(char *s, size_t len, coap_tick_t t) {
145
0
  struct tm *tmp;
146
0
  size_t lensofar;
147
0
  time_t now = coap_ticks_to_rt(t);
148
0
  tmp = localtime(&now);
149
0
  lensofar = strftime(s, len, "%b %d %H:%M:%S", tmp);
150
0
  if (len > lensofar + 4) {
151
0
    lensofar += snprintf(&s[lensofar], len-lensofar, ".%03u",
152
0
                         (unsigned int)((coap_ticks_to_rt_us(t) % 1000000)/1000));
153
0
  }
154
0
  return lensofar;
155
0
}
156
157
#else /* alternative implementation: just print the timestamp */
158
159
COAP_STATIC_INLINE size_t
160
print_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__)
174
/**
175
 * A length-safe strlen() fake.
176
 *
177
 * @param s      The string to count characters != 0.
178
 * @param maxlen The maximum length of @p s.
179
 *
180
 * @return The length of @p s.
181
 */
182
static inline size_t
183
strnlen(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
191
static size_t
192
print_readable(const uint8_t *data, size_t len,
193
0
               unsigned char *result, size_t buflen, int encode_always) {
194
0
  const uint8_t hex[] = "0123456789ABCDEF";
195
0
  size_t cnt = 0;
196
0
  assert(data || len == 0);
197
198
0
  if (buflen == 0) { /* there is nothing we can do here but return */
199
0
    return 0;
200
0
  }
201
202
0
  while (len) {
203
0
    if (!encode_always && isprint(*data)) {
204
0
      if (cnt+1 < buflen) { /* keep one byte for terminating zero */
205
0
        *result++ = *data;
206
0
        ++cnt;
207
0
      } else {
208
0
        break;
209
0
      }
210
0
    } else {
211
0
      if (cnt+4 < buflen) { /* keep one byte for terminating zero */
212
0
        *result++ = '\\';
213
0
        *result++ = 'x';
214
0
        *result++ = hex[(*data & 0xf0) >> 4];
215
0
        *result++ = hex[*data & 0x0f];
216
0
        cnt += 4;
217
0
      } else
218
0
        break;
219
0
    }
220
221
0
    ++data;
222
0
    --len;
223
0
  }
224
225
0
  *result = '\0'; /* add a terminating zero */
226
0
  return cnt;
227
0
}
228
229
#ifndef min
230
0
#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
 */
240
size_t
241
0
coap_print_addr(const coap_address_t *addr, unsigned char *buf, size_t len) {
242
0
#if (defined( HAVE_ARPA_INET_H ) || defined( HAVE_WS2TCPIP_H )) && !defined(RIOT_VERSION) || defined(__ZEPHYR__)
243
0
  char scratch[INET6_ADDRSTRLEN];
244
245
0
  assert(buf);
246
0
  assert(len);
247
0
  buf[0] = '\000';
248
249
0
  switch (addr->addr.sa.sa_family) {
250
0
#if COAP_IPV4_SUPPORT
251
0
  case AF_INET:
252
0
    snprintf((char *)buf, len, "%s:%d",
253
0
             coap_print_ip_addr(addr, scratch, sizeof(scratch)),
254
0
             coap_address_get_port(addr));
255
0
    break;
256
0
#endif /* COAP_IPV4_SUPPORT */
257
0
#if COAP_IPV6_SUPPORT
258
0
  case AF_INET6:
259
0
    snprintf((char *)buf, len, "[%s]:%d",
260
0
             coap_print_ip_addr(addr, scratch, sizeof(scratch)),
261
0
             coap_address_get_port(addr));
262
0
    break;
263
0
#endif /* COAP_IPV6_SUPPORT */
264
0
#if COAP_AF_UNIX_SUPPORT
265
0
  case AF_UNIX:
266
0
    snprintf((char *)buf, len, "%s", addr->addr.cun.sun_path);
267
0
    break;
268
0
#endif /* COAP_AF_UNIX_SUPPORT */
269
0
#if COAP_AF_LLC_SUPPORT
270
0
  case AF_LLC:
271
0
    snprintf((char *)buf, len, "%s:%02x",
272
0
             coap_print_ip_addr(addr, scratch, sizeof(scratch)),
273
0
             coap_address_get_port(addr));
274
0
    break;
275
0
#endif /* COAP_AF_LLC_SUPPORT */
276
0
  default:
277
    /* Include trailing NULL if possible */
278
0
    memcpy(buf, "(unknown address type)", min(22+1, len));
279
0
    buf[len-1] = '\000';
280
0
    break;
281
0
  }
282
0
  return strlen((char *)buf);
283
284
#else /* HAVE_ARPA_INET_H */
285
286
# if defined(RIOT_VERSION)
287
  char scratch[INET6_ADDRSTRLEN];
288
289
  assert(buf);
290
  assert(len);
291
  buf[0] = '\000';
292
293
  switch (addr->riot.family) {
294
#if COAP_IPV4_SUPPORT
295
  case AF_INET:
296
    snprintf((char *)buf, len, "%s:%d",
297
             coap_print_ip_addr(addr, scratch, sizeof(scratch)),
298
             coap_address_get_port(addr));
299
    break;
300
#endif /* COAP_IPV4_SUPPORT */
301
#if COAP_IPV6_SUPPORT
302
  case AF_INET6:
303
    snprintf((char *)buf, len, "[%s]:%d",
304
             coap_print_ip_addr(addr, scratch, sizeof(scratch)),
305
             coap_address_get_port(addr));
306
    break;
307
#endif /* COAP_IPV6_SUPPORT */
308
  default:
309
    /* Include trailing NULL if possible */
310
    memcpy(buf, "(unknown address type)", min(22+1, len));
311
    buf[len-1] = '\000';
312
    break;
313
  }
314
  return strlen((char *)buf);
315
316
# elif WITH_CONTIKI
317
318
  char scratch[INET6_ADDRSTRLEN];
319
#ifdef HAVE_SNPRINTF
320
321
  snprintf((char *)buf, len, "[%s]:%d",
322
           coap_print_ip_addr(addr, scratch, sizeof(scratch)),
323
           coap_address_get_port(addr));
324
  return strlen((char *)buf);
325
#else /* HAVE_SNPRINTF */
326
  unsigned char *p = buf;
327
#  if NETSTACK_CONF_WITH_IPV6
328
329
  assert(buf);
330
  assert(len);
331
  buf[0] = '\000';
332
  if (len < 40 + 2 + 6)
333
    return 0;
334
335
  *p++ = '[';
336
  memcpy(p, coap_print_ip_addr(addr, scratch, sizeof(scratch)), 40);
337
  p += 40 - 1;
338
  *p++ = ']';
339
#  else /* WITH_UIP6 */
340
#   warning "IPv4 network addresses will not be included in debug output"
341
342
  if (len < 21) {
343
    *p = '\000';
344
    return 0;
345
  }
346
#  endif /* WITH_UIP6 */
347
348
  *p++ = ':';
349
  *p++ = '0' + (coap_address_get_port(addr) / 10000) % 10;
350
  *p++ = '0' + (coap_address_get_port(addr) / 1000) % 10;
351
  *p++ = '0' + (coap_address_get_port(addr) / 100) % 10;
352
  *p++ = '0' + (coap_address_get_port(addr) / 10) % 10;
353
  *p++ = '0' + coap_address_get_port(addr) % 10;
354
  *p = '\000';
355
356
  return strlen((char *)buf);
357
#endif /* HAVE_SNPRINTF */
358
359
# elif WITH_LWIP
360
361
  char scratch[INET6_ADDRSTRLEN];
362
#ifdef HAVE_SNPRINTF
363
364
  snprintf((char *)buf, len, "[%s]:%d",
365
           coap_print_ip_addr(addr, scratch, sizeof(scratch)),
366
           addr->port);
367
  return strlen((char *)buf);
368
#else /* HAVE_SNPRINTF */
369
  unsigned char *p = buf;
370
371
  assert(buf);
372
  assert(len);
373
  buf[0] = '\000';
374
375
  switch (IP_GET_TYPE(addr->addr)) {
376
  case IPADDR_TYPE_V4:
377
    if (len < IP4ADDR_STRLEN_MAX + 6)
378
      return 0;
379
    memcpy(buf, coap_print_ip_addr(addr, scratch, sizeof(scratch)), IP4ADDR_STRLEN_MAX);
380
    p += strlen((char *)buf);
381
    break;
382
#if LWIP_IPV6
383
  case IPADDR_TYPE_V6:
384
  case IPADDR_TYPE_ANY:
385
    if (len < 40 + 2 + 6)
386
      return 0;
387
    *p++ = '[';
388
    memcpy(p, coap_print_ip_addr(addr, scratch, sizeof(scratch)), 40);
389
    p += strlen((char *)buf);
390
    *p++ = ']';
391
    break;
392
#endif /* LWIP_IPV6 */
393
  }
394
395
  *p++ = ':';
396
  *p++ = '0' + (addr->port / 10000) % 10;
397
  *p++ = '0' + (addr->port / 1000) % 10;
398
  *p++ = '0' + (addr->port / 100) % 10;
399
  *p++ = '0' + (addr->port / 10) % 10;
400
  *p++ = '0' + addr->port % 10;
401
  *p = '\000';
402
403
  return strlen((char *)buf);
404
#endif /* HAVE_SNPRINTF */
405
406
# else /* ! WITH_CONTIKI && ! WITH_LWIP */
407
408
  (void)addr;
409
  (void)len;
410
411
  /* TODO: output addresses manually */
412
#   warning "inet_ntop() not available, network addresses will not be included in debug output"
413
# endif /* ! WITH_CONTIKI  && ! WITH_LWIP */
414
  buf[0] = '\000';
415
  return 0;
416
#endif
417
0
}
418
419
/*
420
 * Returned buf is always NULL terminated with as much as possible of the
421
 * IP address filled in.
422
 */
423
const char *
424
0
coap_print_ip_addr(const coap_address_t *addr, char *buf, size_t len) {
425
0
#if (defined( HAVE_ARPA_INET_H ) || defined( HAVE_WS2TCPIP_H )) && !defined(RIOT_VERSION) || defined(__ZEPHYR__)
426
0
  const void *addrptr = NULL;
427
428
0
  assert(buf);
429
0
  assert(len);
430
0
  buf[0] = '\000';
431
432
0
  switch (addr->addr.sa.sa_family) {
433
0
#if COAP_IPV4_SUPPORT
434
0
  case AF_INET:
435
0
    if (len < INET_ADDRSTRLEN)
436
0
      return buf;
437
0
    addrptr = &addr->addr.sin.sin_addr;
438
0
    break;
439
0
#endif /* COAP_IPV4_SUPPORT */
440
0
#if COAP_IPV6_SUPPORT
441
0
  case AF_INET6:
442
0
    if (len < INET6_ADDRSTRLEN)
443
0
      return buf;
444
0
    addrptr = &addr->addr.sin6.sin6_addr;
445
0
    break;
446
0
#endif /* COAP_IPV6_SUPPORT */
447
0
#if COAP_AF_UNIX_SUPPORT
448
0
  case AF_UNIX:
449
0
    snprintf(buf, len, "%s", addr->addr.cun.sun_path);
450
0
    return buf;
451
0
#endif /* COAP_AF_UNIX_SUPPORT */
452
0
#if COAP_AF_LLC_SUPPORT
453
0
  case AF_LLC:
454
0
    snprintf((char *)buf, len, "llc[%02x:%02x:%02x:%02x:%02x:%02x]",
455
0
             addr->addr.llc.sllc_mac[0],
456
0
             addr->addr.llc.sllc_mac[1],
457
0
             addr->addr.llc.sllc_mac[2],
458
0
             addr->addr.llc.sllc_mac[3],
459
0
             addr->addr.llc.sllc_mac[4],
460
0
             addr->addr.llc.sllc_mac[5]);
461
0
    return buf;
462
0
#endif /* COAP_AF_LLC_SUPPORT */
463
0
  default:
464
    /* Include trailing NULL if possible */
465
0
    memcpy(buf, "(unknown address type)", min(22+1, len));
466
0
    buf[len-1] = '\000';
467
0
    return buf;
468
0
  }
469
470
  /* Cast needed for Windows, since it doesn't have the correct API signature. */
471
0
  if (inet_ntop(addr->addr.sa.sa_family, addrptr, (char *)buf, len) == 0) {
472
0
    coap_log_err("coap_print_ip_addr: inet_ntop\n");
473
0
    buf[0] = '\000';
474
0
    return buf;
475
0
  }
476
0
  return buf;
477
478
#else /* HAVE_ARPA_INET_H */
479
480
# if defined(RIOT_VERSION)
481
  assert(buf);
482
  assert(len);
483
  buf[0] = '\000';
484
485
  switch (addr->riot.family) {
486
#if COAP_IPV4_SUPPORT
487
  case AF_INET:
488
    if (ipv4_addr_to_str(buf, (ipv4_addr_t *)&addr->riot.addr.ipv4, (size_t)len) == NULL) {
489
      goto error;
490
    }
491
    break;
492
#endif /* COAP_IPV4_SUPPORT */
493
#if COAP_IPV6_SUPPORT
494
  case AF_INET6:
495
    if (ipv6_addr_to_str(buf, (ipv6_addr_t *)&addr->riot.addr.ipv6, (size_t)len) == NULL) {
496
      goto error;
497
    }
498
    break;
499
#endif /* COAP_IPV6_SUPPORT */
500
  default:
501
    goto error;
502
  }
503
  return buf;
504
505
error:
506
  coap_log_err("coap_print_ip_addr: inet_ntop\n");
507
  buf[0] = '\000';
508
  return buf;
509
510
# elif WITH_CONTIKI
511
  char *p = buf;
512
  uint8_t i;
513
#  if NETSTACK_CONF_WITH_IPV6
514
  const char hex[] = "0123456789ABCDEF";
515
516
  assert(buf);
517
  assert(len);
518
  buf[0] = '\000';
519
  if (len < 40)
520
    return 0;
521
522
  for (i=0; i < 16; i += 2) {
523
    if (i) {
524
      *p++ = ':';
525
    }
526
    *p++ = hex[(addr->addr.u8[i] & 0xf0) >> 4];
527
    *p++ = hex[(addr->addr.u8[i] & 0x0f)];
528
    *p++ = hex[(addr->addr.u8[i+1] & 0xf0) >> 4];
529
    *p++ = hex[(addr->addr.u8[i+1] & 0x0f)];
530
  }
531
  *p = '\000';
532
#  else /* WITH_UIP6 */
533
#   warning "IPv4 network addresses will not be included in debug output"
534
535
  if (len < 21) {
536
    return buf;
537
  }
538
#  endif /* WITH_UIP6 */
539
  return buf;
540
541
# elif WITH_LWIP
542
543
  assert(buf);
544
  assert(len);
545
  buf[0] = '\000';
546
547
  switch (IP_GET_TYPE(&addr->addr)) {
548
#if LWIP_IPV4
549
  case IPADDR_TYPE_V4:
550
    if (len < IP4ADDR_STRLEN_MAX)
551
      return buf;
552
    memcpy(buf, ip4addr_ntoa(ip_2_ip4(&addr->addr)), IP4ADDR_STRLEN_MAX);
553
    break;
554
#endif /* LWIP_IPV4 */
555
#if LWIP_IPV6
556
  case IPADDR_TYPE_V6:
557
  case IPADDR_TYPE_ANY:
558
    if (len < 40)
559
      return buf;
560
#if LWIP_IPV4
561
    memcpy(buf, ip6addr_ntoa(&addr->addr.u_addr.ip6), 40);
562
#else /* LWIP_IPV4 */
563
    memcpy(buf, ip6addr_ntoa(&addr->addr), 40);
564
#endif /* LWIP_IPV4 */
565
    break;
566
#endif /* LWIP_IPV6 */
567
  }
568
  return buf;
569
570
# else /* ! WITH_CONTIKI && ! WITH_LWIP */
571
572
  (void)addr;
573
  (void)len;
574
575
  /* TODO: output addresses manually */
576
#   warning "inet_ntop() not available, network addresses will not be included in debug output"
577
# endif /* WITH_CONTIKI */
578
  buf[0] = '\000';
579
  return buf;
580
#endif
581
0
}
582
583
/** Returns a textual description of the message type @p t. */
584
static const char *
585
0
msg_type_string(uint16_t t) {
586
0
  static const char *types[] = { "CON", "NON", "ACK", "RST", "???" };
587
588
0
  return types[min(t, sizeof(types)/sizeof(char *) - 1)];
589
0
}
590
591
/** Returns a textual description of the method or response code. */
592
static const char *
593
0
msg_code_string(uint16_t c) {
594
0
  static const char *methods[] = { "0.00", "GET", "POST", "PUT", "DELETE",
595
0
                                   "FETCH", "PATCH", "iPATCH"
596
0
                                 };
597
0
  static const char *signals[] = { "7.00", "CSM", "Ping", "Pong", "Release",
598
0
                                   "Abort"
599
0
                                 };
600
0
  static char buf[5];
601
602
0
  if (c < sizeof(methods)/sizeof(const char *)) {
603
0
    return methods[c];
604
0
  } else if (c >= 224 && c - 224 < (int)(sizeof(signals)/sizeof(const char *))) {
605
0
    return signals[c-224];
606
0
  } else {
607
0
    snprintf(buf, sizeof(buf), "%u.%02u", (c >> 5) & 0x7, c & 0x1f);
608
0
    return buf;
609
0
  }
610
0
}
611
612
/** Returns a textual description of the option name. */
613
const char *
614
0
coap_option_string(coap_pdu_code_t code, coap_option_num_t number) {
615
0
  struct option_desc_t {
616
0
    uint16_t value;
617
0
    const char *name;
618
0
  };
619
620
0
  static struct option_desc_t options[] = {
621
0
    { COAP_OPTION_IF_MATCH, "If-Match" },
622
0
    { COAP_OPTION_URI_HOST, "Uri-Host" },
623
0
    { COAP_OPTION_ETAG, "ETag" },
624
0
    { COAP_OPTION_IF_NONE_MATCH, "If-None-Match" },
625
0
    { COAP_OPTION_OBSERVE, "Observe" },
626
0
    { COAP_OPTION_URI_PORT, "Uri-Port" },
627
0
    { COAP_OPTION_LOCATION_PATH, "Location-Path" },
628
0
    { COAP_OPTION_OSCORE, "Oscore" },
629
0
    { COAP_OPTION_URI_PATH, "Uri-Path" },
630
0
    { COAP_OPTION_CONTENT_FORMAT, "Content-Format" },
631
0
    { COAP_OPTION_URI_PATH_ABB, "Uri-Path-Abbrev" },
632
0
    { COAP_OPTION_MAXAGE, "Max-Age" },
633
0
    { COAP_OPTION_URI_QUERY, "Uri-Query" },
634
0
    { COAP_OPTION_HOP_LIMIT, "Hop-Limit" },
635
0
    { COAP_OPTION_ACCEPT, "Accept" },
636
0
    { COAP_OPTION_LOCATION_QUERY, "Location-Query" },
637
0
    { COAP_OPTION_BLOCK2, "Block2" },
638
0
    { COAP_OPTION_BLOCK1, "Block1" },
639
0
    { COAP_OPTION_SIZE2, "Size2" },
640
0
    { COAP_OPTION_PROXY_URI, "Proxy-Uri" },
641
0
    { COAP_OPTION_PROXY_SCHEME, "Proxy-Scheme" },
642
0
    { COAP_OPTION_SIZE1, "Size1" },
643
0
    { COAP_OPTION_ECHO, "Echo" },
644
0
    { COAP_OPTION_NORESPONSE, "No-Response" },
645
0
    { COAP_OPTION_RTAG, "Request-Tag" },
646
0
    { COAP_OPTION_Q_BLOCK1, "Q-Block1" },
647
0
    { COAP_OPTION_Q_BLOCK2, "Q-Block2" }
648
0
  };
649
650
0
  static struct option_desc_t options_csm[] = {
651
0
    { COAP_SIG_OPT_MAX_MESSAGE_SIZE, "Max-Message-Size" },
652
0
    { COAP_SIG_OPT_BLOCK_WISE_TRANSFER, "Block-Wise-Transfer" },
653
0
    { COAP_SIG_OPT_EXTENDED_TOKEN_LENGTH, "Extended-Token-Length" }
654
0
  };
655
656
0
  static struct option_desc_t options_pingpong[] = {
657
0
    { COAP_SIG_OPT_CUSTODY, "Custody" }
658
0
  };
659
660
0
  static struct option_desc_t options_release[] = {
661
0
    { COAP_SIG_OPT_ALTERNATIVE_ADDRESS, "Alternative-Address" },
662
0
    { COAP_SIG_OPT_HOLD_OFF, "Hold-Off" }
663
0
  };
664
665
0
  static struct option_desc_t options_abort[] = {
666
0
    { COAP_SIG_OPT_BAD_CSM_OPTION, "Bad-CSM-Option" }
667
0
  };
668
669
0
  static char buf[6];
670
0
  size_t i;
671
672
0
  if (code == COAP_SIGNALING_CODE_CSM) {
673
0
    for (i = 0; i < sizeof(options_csm)/sizeof(struct option_desc_t); i++) {
674
0
      if (number == options_csm[i].value) {
675
0
        return options_csm[i].name;
676
0
      }
677
0
    }
678
0
  } else if (code == COAP_SIGNALING_CODE_PING || code == COAP_SIGNALING_CODE_PONG) {
679
0
    for (i = 0; i < sizeof(options_pingpong)/sizeof(struct option_desc_t); i++) {
680
0
      if (number == options_pingpong[i].value) {
681
0
        return options_pingpong[i].name;
682
0
      }
683
0
    }
684
0
  } else if (code == COAP_SIGNALING_CODE_RELEASE) {
685
0
    for (i = 0; i < sizeof(options_release)/sizeof(struct option_desc_t); i++) {
686
0
      if (number == options_release[i].value) {
687
0
        return options_release[i].name;
688
0
      }
689
0
    }
690
0
  } else if (code == COAP_SIGNALING_CODE_ABORT) {
691
0
    for (i = 0; i < sizeof(options_abort)/sizeof(struct option_desc_t); i++) {
692
0
      if (number == options_abort[i].value) {
693
0
        return options_abort[i].name;
694
0
      }
695
0
    }
696
0
  } else {
697
    /* search option_type in list of known options */
698
0
    for (i = 0; i < sizeof(options)/sizeof(struct option_desc_t); i++) {
699
0
      if (number == options[i].value) {
700
0
        return options[i].name;
701
0
      }
702
0
    }
703
0
  }
704
  /* unknown option type, just print to buf */
705
0
  snprintf(buf, sizeof(buf), "%u", number);
706
0
  return buf;
707
0
}
708
709
static unsigned int
710
print_content_format(unsigned int format_type,
711
0
                     unsigned char *result, unsigned int buflen) {
712
0
  struct desc_t {
713
0
    unsigned int type;
714
0
    const char *name;
715
0
  };
716
717
0
  static struct desc_t formats[] = {
718
0
    { COAP_MEDIATYPE_TEXT_PLAIN, "text/plain" },
719
0
    { COAP_MEDIATYPE_APPLICATION_LINK_FORMAT, "application/link-format" },
720
0
    { COAP_MEDIATYPE_APPLICATION_XML, "application/xml" },
721
0
    { COAP_MEDIATYPE_APPLICATION_OCTET_STREAM, "application/octet-stream" },
722
0
    { COAP_MEDIATYPE_APPLICATION_RDF_XML, "application/rdf+xml" },
723
0
    { COAP_MEDIATYPE_APPLICATION_EXI, "application/exi" },
724
0
    { COAP_MEDIATYPE_APPLICATION_JSON, "application/json" },
725
0
    { COAP_MEDIATYPE_APPLICATION_CBOR, "application/cbor" },
726
0
    { COAP_MEDIATYPE_APPLICATION_CWT, "application/cwt" },
727
0
    { COAP_MEDIATYPE_APPLICATION_COAP_GROUP_JSON, "application/coap-group+json" },
728
0
    { COAP_MEDIATYPE_APPLICATION_COSE_SIGN, "application/cose; cose-type=\"cose-sign\"" },
729
0
    { COAP_MEDIATYPE_APPLICATION_COSE_SIGN1, "application/cose; cose-type=\"cose-sign1\"" },
730
0
    { COAP_MEDIATYPE_APPLICATION_COSE_ENCRYPT, "application/cose; cose-type=\"cose-encrypt\"" },
731
0
    { COAP_MEDIATYPE_APPLICATION_COSE_ENCRYPT0, "application/cose; cose-type=\"cose-encrypt0\"" },
732
0
    { COAP_MEDIATYPE_APPLICATION_COSE_MAC, "application/cose; cose-type=\"cose-mac\"" },
733
0
    { COAP_MEDIATYPE_APPLICATION_COSE_MAC0, "application/cose; cose-type=\"cose-mac0\"" },
734
0
    { COAP_MEDIATYPE_APPLICATION_COSE_KEY, "application/cose-key" },
735
0
    { COAP_MEDIATYPE_APPLICATION_COSE_KEY_SET, "application/cose-key-set" },
736
0
    { COAP_MEDIATYPE_APPLICATION_SENML_JSON, "application/senml+json" },
737
0
    { COAP_MEDIATYPE_APPLICATION_SENSML_JSON, "application/sensml+json" },
738
0
    { COAP_MEDIATYPE_APPLICATION_SENML_CBOR, "application/senml+cbor" },
739
0
    { COAP_MEDIATYPE_APPLICATION_SENSML_CBOR, "application/sensml+cbor" },
740
0
    { COAP_MEDIATYPE_APPLICATION_SENML_EXI, "application/senml-exi" },
741
0
    { COAP_MEDIATYPE_APPLICATION_SENSML_EXI, "application/sensml-exi" },
742
0
    { COAP_MEDIATYPE_APPLICATION_SENML_XML, "application/senml+xml" },
743
0
    { COAP_MEDIATYPE_APPLICATION_SENSML_XML, "application/sensml+xml" },
744
0
    { COAP_MEDIATYPE_APPLICATION_DOTS_CBOR, "application/dots+cbor" },
745
0
    { COAP_MEDIATYPE_APPLICATION_ACE_CBOR, "application/ace+cbor" },
746
0
    { COAP_MEDIATYPE_APPLICATION_MB_CBOR_SEQ, "application/missing-blocks+cbor-seq" },
747
0
    { COAP_MEDIATYPE_APPLICATION_OSCORE, "application/oscore" },
748
0
    { 75, "application/dcaf+cbor" }
749
0
  };
750
751
0
  size_t i;
752
753
  /* search format_type in list of known content formats */
754
0
  for (i = 0; i < sizeof(formats)/sizeof(struct desc_t); i++) {
755
0
    if (format_type == formats[i].type) {
756
0
      return snprintf((char *)result, buflen, "%s", formats[i].name);
757
0
    }
758
0
  }
759
760
  /* unknown content format, just print numeric value to buf */
761
0
  return snprintf((char *)result, buflen, "%d", format_type);
762
0
}
763
764
/**
765
 * Returns 1 if the given @p content_format is either unknown or known
766
 * to carry binary data. The return value @c 0 hence indicates
767
 * printable data which is also assumed if @p content_format is @c 01.
768
 */
769
COAP_STATIC_INLINE int
770
0
is_binary(int content_format) {
771
0
  return !(content_format == -1 ||
772
0
           content_format == COAP_MEDIATYPE_TEXT_PLAIN ||
773
0
           content_format == COAP_MEDIATYPE_APPLICATION_LINK_FORMAT ||
774
0
           content_format == COAP_MEDIATYPE_APPLICATION_XML ||
775
0
           content_format == COAP_MEDIATYPE_APPLICATION_JSON);
776
0
}
777
778
#define COAP_DO_SHOW_OUTPUT_LINE           \
779
0
  do {                                      \
780
0
    if (use_fprintf_for_show_pdu) {         \
781
0
      fprintf(COAP_DEBUG_FD, "%s", outbuf); \
782
0
    }                                       \
783
0
    else {                                  \
784
0
      coap_log(level, "%s", outbuf);        \
785
0
    }                                       \
786
0
  } while (0)
787
788
/*
789
 * It is possible to override the output debug buffer size and hence control
790
 * the amount of information printed out about a CoAP PDU.
791
 * Note: Adding a byte may be insufficient to output the next byte of the PDU.
792
 *
793
 * This is done by the adding of a -DCOAP_DEBUG_BUF_SIZE=nnnn option to the
794
 * CPPFLAGS parameter that is optionally used on the ./configure command line.
795
 *
796
 * E.g.  ./configure CPPFLAGS="-DCOAP_DEBUG_BUF_SIZE=4096"
797
 *
798
 */
799
800
#if COAP_DEBUG_BUF_SIZE < 5
801
#error "COAP_DEBUG_BUF_SIZE must be at least 5, should be >= 32 to be useful"
802
#endif /* COAP_DEBUG_BUF_SIZE < 5 */
803
804
/* Proxy-Uri: can be 1034 bytes long */
805
#if COAP_DEBUG_BUF_SIZE < 1035
806
#define USE_BUF_SIZE COAP_DEBUG_BUF_SIZE
807
#else
808
#define USE_BUF_SIZE 1035
809
#endif
810
811
void
812
0
coap_show_pdu(coap_log_t level, const coap_pdu_t *pdu) {
813
#if COAP_CONSTRAINED_STACK
814
  /* Proxy-Uri: can be 1034 bytes long */
815
  /* buf and outbuf can be protected by m_show_pdu if needed */
816
  static unsigned char buf[USE_BUF_SIZE];
817
  static char outbuf[COAP_DEBUG_BUF_SIZE];
818
#else /* ! COAP_CONSTRAINED_STACK */
819
  /* Proxy-Uri: can be 1034 bytes long */
820
0
  unsigned char buf[USE_BUF_SIZE];
821
0
  char outbuf[COAP_DEBUG_BUF_SIZE];
822
0
#endif /* ! COAP_CONSTRAINED_STACK */
823
0
  size_t buf_len = 0; /* takes the number of bytes written to buf */
824
0
  int have_options = 0;
825
0
  uint32_t i;
826
0
  coap_opt_iterator_t opt_iter;
827
0
  coap_opt_t *option;
828
0
  int content_format = -1;
829
0
  size_t data_len;
830
0
  const uint8_t *data;
831
0
  uint32_t opt_len;
832
0
  const uint8_t *opt_val;
833
0
  size_t outbuflen = 0;
834
0
  int is_oscore_payload = 0;
835
0
  const char *exp;
836
0
  uint32_t value;
837
838
  /* Save time if not needed */
839
0
  if (level > coap_get_log_level())
840
0
    return;
841
842
#if COAP_THREAD_SAFE
843
  coap_mutex_lock(&m_show_pdu);
844
#endif /* COAP_THREAD_SAFE */
845
0
  if (!pdu->session || COAP_PROTO_NOT_RELIABLE(pdu->session->proto)) {
846
0
    snprintf(outbuf, sizeof(outbuf), "v:%d t:%s c:%s i:%04x {",
847
0
             COAP_DEFAULT_VERSION, msg_type_string(pdu->type),
848
0
             msg_code_string(pdu->code), pdu->mid);
849
0
  } else if (pdu->session->proto == COAP_PROTO_WS ||
850
0
             pdu->session->proto == COAP_PROTO_WSS) {
851
0
    if (pdu->type != COAP_MESSAGE_CON)
852
0
      coap_log_alert("WebSocket: type != CON\n");
853
0
    snprintf(outbuf, sizeof(outbuf), "v:WebSocket c:%s {",
854
0
             msg_code_string(pdu->code));
855
0
  } else {
856
0
    if (pdu->type != COAP_MESSAGE_CON)
857
0
      coap_log_alert("Reliable: type != CON\n");
858
0
    snprintf(outbuf, sizeof(outbuf), "v:Reliable c:%s {",
859
0
             msg_code_string(pdu->code));
860
0
  }
861
862
0
  for (i = 0; i < pdu->actual_token.length; i++) {
863
0
    outbuflen = strlen(outbuf);
864
0
    snprintf(&outbuf[outbuflen], sizeof(outbuf)-outbuflen,
865
0
             "%02x", pdu->actual_token.s[i]);
866
0
  }
867
0
  outbuflen = strlen(outbuf);
868
0
  snprintf(&outbuf[outbuflen], sizeof(outbuf)-outbuflen,  "}");
869
870
  /* show options, if any */
871
0
  coap_option_iterator_init(pdu, &opt_iter, COAP_OPT_ALL);
872
873
0
  outbuflen = strlen(outbuf);
874
0
  snprintf(&outbuf[outbuflen], sizeof(outbuf)-outbuflen,  " [");
875
0
  while ((option = coap_option_next(&opt_iter))) {
876
0
    buf[0] = '\000';
877
0
    if (!have_options) {
878
0
      have_options = 1;
879
0
    } else {
880
0
      outbuflen = strlen(outbuf);
881
0
      snprintf(&outbuf[outbuflen], sizeof(outbuf)-outbuflen,  ",");
882
0
    }
883
884
0
    if (pdu->code == COAP_SIGNALING_CODE_CSM) {
885
0
      switch ((coap_sig_csm_opt_t)opt_iter.number) {
886
0
      case COAP_SIG_OPT_EXTENDED_TOKEN_LENGTH:
887
0
      case COAP_SIG_OPT_MAX_MESSAGE_SIZE:
888
0
        buf_len = snprintf((char *)buf, sizeof(buf), "%u",
889
0
                           coap_decode_var_bytes(coap_opt_value(option),
890
0
                                                 coap_opt_length(option)));
891
0
        break;
892
0
      case COAP_SIG_OPT_BLOCK_WISE_TRANSFER:
893
0
      default:
894
0
        buf_len = 0;
895
0
        break;
896
0
      }
897
0
    } else if (pdu->code == COAP_SIGNALING_CODE_PING ||
898
0
               pdu->code == COAP_SIGNALING_CODE_PONG) {
899
0
      switch ((coap_sig_ping_opt_t)opt_iter.number) {
900
0
      case COAP_SIG_OPT_CUSTODY:
901
0
      default:
902
0
        buf_len = 0;
903
0
      }
904
0
    } else if (pdu->code == COAP_SIGNALING_CODE_RELEASE) {
905
0
      switch ((coap_sig_release_opt_t)opt_iter.number) {
906
0
      case COAP_SIG_OPT_ALTERNATIVE_ADDRESS:
907
0
        buf_len = print_readable(coap_opt_value(option),
908
0
                                 coap_opt_length(option),
909
0
                                 buf, sizeof(buf), 0);
910
0
        break;
911
0
      case COAP_SIG_OPT_HOLD_OFF:
912
0
        buf_len = snprintf((char *)buf, sizeof(buf), "%u",
913
0
                           coap_decode_var_bytes(coap_opt_value(option),
914
0
                                                 coap_opt_length(option)));
915
0
        break;
916
0
      default:
917
0
        buf_len = 0;
918
0
        break;
919
0
      }
920
0
    } else if (pdu->code == COAP_SIGNALING_CODE_ABORT) {
921
0
      switch ((coap_sig_abort_opt_t)opt_iter.number) {
922
0
      case COAP_SIG_OPT_BAD_CSM_OPTION:
923
0
        buf_len = snprintf((char *)buf, sizeof(buf), "%u",
924
0
                           coap_decode_var_bytes(coap_opt_value(option),
925
0
                                                 coap_opt_length(option)));
926
0
        break;
927
0
      default:
928
0
        buf_len = 0;
929
0
        break;
930
0
      }
931
0
    } else {
932
0
      switch ((coap_code_opt_num_t)opt_iter.number) {
933
0
      case COAP_OPTION_CONTENT_FORMAT:
934
0
      case COAP_OPTION_ACCEPT:
935
0
        content_format = (int)coap_decode_var_bytes(coap_opt_value(option),
936
0
                                                    coap_opt_length(option));
937
938
0
        buf_len = print_content_format(content_format, buf, sizeof(buf));
939
0
        break;
940
941
0
      case COAP_OPTION_BLOCK1:
942
0
      case COAP_OPTION_BLOCK2:
943
0
      case COAP_OPTION_Q_BLOCK1:
944
0
      case COAP_OPTION_Q_BLOCK2:
945
        /* split block option into number/more/size where more is the
946
         * letter M if set, the _ otherwise */
947
0
        if (COAP_OPT_BLOCK_SZX(option) == 7) {
948
0
          if (coap_get_data(pdu, &data_len, &data))
949
0
            buf_len = snprintf((char *)buf, sizeof(buf), "%u/%c/BERT(%" PRIuS ")",
950
0
                               coap_opt_block_num(option), /* block number */
951
0
                               COAP_OPT_BLOCK_MORE(option) ? 'M' : '_', /* M bit */
952
0
                               data_len);
953
0
          else
954
0
            buf_len = snprintf((char *)buf, sizeof(buf), "%u/%c/BERT",
955
0
                               coap_opt_block_num(option), /* block number */
956
0
                               COAP_OPT_BLOCK_MORE(option) ? 'M' : '_'); /* M bit */
957
0
        } else {
958
0
          buf_len = snprintf((char *)buf, sizeof(buf), "%u/%c/%u",
959
0
                             coap_opt_block_num(option), /* block number */
960
0
                             COAP_OPT_BLOCK_MORE(option) ? 'M' : '_', /* M bit */
961
0
                             (1 << (COAP_OPT_BLOCK_SZX(option) + 4))); /* block size */
962
0
        }
963
964
0
        break;
965
966
0
      case COAP_OPTION_OSCORE:
967
0
        opt_len = coap_opt_length(option);
968
0
        buf[0] = '\000';
969
0
        if (opt_len) {
970
0
          size_t ofs = 1;
971
0
          size_t cnt;
972
973
0
          opt_val = coap_opt_value(option);
974
0
          if (opt_val[0] & 0x20) {
975
            /* Group Flag */
976
0
            snprintf((char *)buf, sizeof(buf), "grp");
977
0
          }
978
0
          if (opt_val[0] & 0x07) {
979
            /* Partial IV */
980
0
            cnt = opt_val[0] & 0x07;
981
0
            if (cnt > opt_len - ofs)
982
0
              goto no_more;
983
0
            buf_len = strlen((char *)buf);
984
0
            snprintf((char *)&buf[buf_len], sizeof(buf)-buf_len, "%spIV=0x",
985
0
                     buf_len ? "," : "");
986
0
            for (i = 0; (uint32_t)i < cnt; i++) {
987
0
              buf_len = strlen((char *)buf);
988
0
              snprintf((char *)&buf[buf_len], sizeof(buf)-buf_len,
989
0
                       "%02x", opt_val[ofs + i]);
990
0
            }
991
0
            ofs += cnt;
992
0
          }
993
0
          if (opt_val[0] & 0x10) {
994
            /* kid context */
995
0
            if (ofs >= opt_len)
996
0
              goto no_more;
997
0
            cnt = opt_val[ofs];
998
0
            if (cnt > opt_len - ofs - 1)
999
0
              goto no_more;
1000
0
            ofs++;
1001
0
            buf_len = strlen((char *)buf);
1002
0
            snprintf((char *)&buf[buf_len], sizeof(buf)-buf_len, "%skc=0x",
1003
0
                     buf_len ? "," : "");
1004
0
            for (i = 0; (uint32_t)i < cnt; i++) {
1005
0
              buf_len = strlen((char *)buf);
1006
0
              snprintf((char *)&buf[buf_len], sizeof(buf)-buf_len,
1007
0
                       "%02x", opt_val[ofs + i]);
1008
0
            }
1009
0
            ofs += cnt;
1010
0
          }
1011
0
          if (opt_val[0] & 0x08) {
1012
            /* kid */
1013
0
            if (ofs >= opt_len)
1014
0
              goto no_more;
1015
0
            cnt = opt_len - ofs;
1016
0
            buf_len = strlen((char *)buf);
1017
0
            snprintf((char *)&buf[buf_len], sizeof(buf)-buf_len, "%skid=0x",
1018
0
                     buf_len ? "," : "");
1019
0
            for (i = 0; (uint32_t)i < cnt; i++) {
1020
0
              buf_len = strlen((char *)buf);
1021
0
              snprintf((char *)&buf[buf_len], sizeof(buf)-buf_len,
1022
0
                       "%02x", opt_val[ofs + i]);
1023
0
            }
1024
0
          }
1025
0
        }
1026
0
no_more:
1027
0
        buf_len = strlen((char *)buf);
1028
0
        is_oscore_payload = 1;
1029
0
        break;
1030
1031
0
      case COAP_OPTION_URI_PORT:
1032
0
      case COAP_OPTION_MAXAGE:
1033
0
      case COAP_OPTION_OBSERVE:
1034
0
      case COAP_OPTION_SIZE1:
1035
0
      case COAP_OPTION_SIZE2:
1036
0
      case COAP_OPTION_HOP_LIMIT:
1037
0
        if (coap_opt_length(option)) {
1038
          /* show values as unsigned decimal value */
1039
0
          buf_len = snprintf((char *)buf, sizeof(buf), "%u",
1040
0
                             coap_decode_var_bytes(coap_opt_value(option),
1041
0
                                                   coap_opt_length(option)));
1042
0
        }
1043
0
        break;
1044
1045
0
      case COAP_OPTION_IF_MATCH:
1046
0
      case COAP_OPTION_ETAG:
1047
0
      case COAP_OPTION_ECHO:
1048
0
      case COAP_OPTION_NORESPONSE:
1049
0
      case COAP_OPTION_RTAG:
1050
0
        opt_len = coap_opt_length(option);
1051
0
        opt_val = coap_opt_value(option);
1052
0
        snprintf((char *)buf, sizeof(buf), "0x");
1053
0
        for (i = 0; (uint32_t)i < opt_len; i++) {
1054
0
          buf_len = strlen((char *)buf);
1055
0
          snprintf((char *)&buf[buf_len], sizeof(buf)-buf_len,
1056
0
                   "%02x", opt_val[i]);
1057
0
        }
1058
0
        buf_len = strlen((char *)buf);
1059
0
        break;
1060
0
      case COAP_OPTION_URI_PATH_ABB:
1061
0
        value = coap_decode_var_bytes(coap_opt_value(option),
1062
0
                                      coap_opt_length(option));
1063
0
        exp = coap_map_abbrev_uri_path(coap_upa_server_mapping_chain, value);
1064
0
        if (!exp) {
1065
0
          exp = coap_map_abbrev_uri_path(coap_upa_client_fallback_chain, value);
1066
0
        }
1067
0
        if (exp) {
1068
0
          snprintf((char *)&buf, sizeof(buf), "%s", exp);
1069
0
        } else {
1070
0
          snprintf((char *)&buf, sizeof(buf), "(%" PRIu32 ")", value);
1071
0
        }
1072
0
        buf_len = strlen((char *)buf);
1073
0
        break;
1074
0
      case COAP_OPTION_URI_PATH:
1075
0
      case COAP_OPTION_PROXY_URI:
1076
0
      case COAP_OPTION_URI_HOST:
1077
0
      case COAP_OPTION_LOCATION_PATH:
1078
0
      case COAP_OPTION_LOCATION_QUERY:
1079
0
      case COAP_OPTION_PROXY_SCHEME:
1080
0
      case COAP_OPTION_URI_QUERY:
1081
0
        buf_len = print_readable(coap_opt_value(option),
1082
0
                                 coap_opt_length(option),
1083
0
                                 buf, sizeof(buf), 0);
1084
0
        break;
1085
0
      case COAP_OPTION_IF_NONE_MATCH:
1086
0
      case COAP_OPTION_EDHOC:
1087
0
      default:
1088
0
        buf_len = print_readable(coap_opt_value(option),
1089
0
                                 coap_opt_length(option),
1090
0
                                 buf, sizeof(buf), 1);
1091
0
      }
1092
0
    }
1093
0
    outbuflen = strlen(outbuf);
1094
0
    snprintf(&outbuf[outbuflen], sizeof(outbuf)-outbuflen,
1095
0
             " %s:%.*s", coap_option_string(pdu->code, opt_iter.number),
1096
0
             (int)buf_len, buf);
1097
0
  }
1098
1099
0
  outbuflen = strlen(outbuf);
1100
0
  snprintf(&outbuf[outbuflen], sizeof(outbuf)-outbuflen,  " ]");
1101
1102
0
  if (coap_get_data(pdu, &data_len, &data)) {
1103
0
    if (!enable_data_for_show_pdu) {
1104
      /* Only output data if wanted */
1105
0
      outbuflen = strlen(outbuf);
1106
0
      snprintf(&outbuf[outbuflen], sizeof(outbuf)-outbuflen,  " :: ");
1107
0
      outbuflen = strlen(outbuf);
1108
0
      snprintf(&outbuf[outbuflen], sizeof(outbuf)-outbuflen,
1109
0
               "data length %"PRIuS " (data suppressed)\n", data_len);
1110
0
      COAP_DO_SHOW_OUTPUT_LINE;
1111
#if COAP_THREAD_SAFE
1112
      coap_mutex_unlock(&m_show_pdu);
1113
#endif /* COAP_THREAD_SAFE */
1114
0
      return;
1115
0
    }
1116
1117
0
    outbuflen = strlen(outbuf);
1118
0
    snprintf(&outbuf[outbuflen], sizeof(outbuf)-outbuflen,  " :: ");
1119
1120
0
    if (is_binary(content_format) || !isprint(data[0]) || is_oscore_payload) {
1121
0
      size_t keep_data_len = data_len;
1122
0
      const uint8_t *keep_data = data;
1123
1124
0
      outbuflen = strlen(outbuf);
1125
0
      snprintf(&outbuf[outbuflen], sizeof(outbuf)-outbuflen,
1126
0
               "binary data length %"PRIuS "\n", data_len);
1127
0
      COAP_DO_SHOW_OUTPUT_LINE;
1128
      /*
1129
       * Output hex dump of binary data as a continuous entry
1130
       */
1131
0
      outbuf[0] = '\000';
1132
0
      snprintf(outbuf, sizeof(outbuf),  "<<");
1133
0
      while (data_len--) {
1134
0
        outbuflen = strlen(outbuf);
1135
0
        snprintf(&outbuf[outbuflen], sizeof(outbuf)-outbuflen,
1136
0
                 "%02x", *data++);
1137
0
      }
1138
0
      outbuflen = strlen(outbuf);
1139
0
      snprintf(&outbuf[outbuflen], sizeof(outbuf)-outbuflen,  ">>");
1140
0
      data_len = keep_data_len;
1141
0
      data = keep_data;
1142
0
      outbuflen = strlen(outbuf);
1143
0
      if (outbuflen == sizeof(outbuf)-1)
1144
0
        outbuflen--;
1145
0
      snprintf(&outbuf[outbuflen], sizeof(outbuf)-outbuflen,  "\n");
1146
0
      COAP_DO_SHOW_OUTPUT_LINE;
1147
      /*
1148
       * Output ascii readable (if possible), immediately under the
1149
       * hex value of the character output above to help binary debugging
1150
       */
1151
0
      outbuf[0] = '\000';
1152
0
      snprintf(outbuf, sizeof(outbuf),  "<<");
1153
0
      while (data_len--) {
1154
0
        outbuflen = strlen(outbuf);
1155
0
        snprintf(&outbuf[outbuflen], sizeof(outbuf)-outbuflen,
1156
0
                 "%c ", isprint(*data) ? *data : '.');
1157
0
        data++;
1158
0
      }
1159
0
      outbuflen = strlen(outbuf);
1160
0
      snprintf(&outbuf[outbuflen], sizeof(outbuf)-outbuflen,  ">>");
1161
0
    } else {
1162
0
      size_t max_length;
1163
1164
0
      outbuflen = strlen(outbuf);
1165
0
      max_length = sizeof(outbuf)-outbuflen;
1166
0
      if (max_length > 1) {
1167
0
        outbuf[outbuflen++] = '\'';
1168
0
        outbuf[outbuflen] = '\000';
1169
0
        max_length--;
1170
0
      }
1171
0
      if (max_length > 1) {
1172
0
        outbuflen += print_readable(data, data_len,
1173
0
                                    (unsigned char *)&outbuf[outbuflen],
1174
0
                                    max_length, 0);
1175
0
      }
1176
      /* print_readable may be handling unprintables - hence headroom of 4 */
1177
0
      if (outbuflen < sizeof(outbuf)-4-1) {
1178
0
        outbuf[outbuflen++] = '\'';
1179
0
        outbuf[outbuflen] = '\000';
1180
0
      }
1181
0
    }
1182
0
  }
1183
1184
0
  outbuflen = strlen(outbuf);
1185
0
  if (outbuflen == sizeof(outbuf)-1)
1186
0
    outbuflen--;
1187
0
  snprintf(&outbuf[outbuflen], sizeof(outbuf)-outbuflen,  "\n");
1188
0
  COAP_DO_SHOW_OUTPUT_LINE;
1189
1190
#if COAP_THREAD_SAFE
1191
  coap_mutex_unlock(&m_show_pdu);
1192
#endif /* COAP_THREAD_SAFE */
1193
0
}
1194
1195
void
1196
0
coap_show_tls_version(coap_log_t level) {
1197
0
  char buffer[128];
1198
0
  coap_string_tls_version(buffer, sizeof(buffer));
1199
0
  coap_log(level, "%s\n", buffer);
1200
0
}
1201
1202
char *
1203
0
coap_string_tls_version(char *buffer, size_t bufsize) {
1204
0
  coap_tls_version_t *tls_version = coap_get_tls_library_version();
1205
0
  char beta[8];
1206
0
  char sub[2];
1207
0
  char b_beta[8];
1208
0
  char b_sub[2];
1209
1210
0
  switch (tls_version->type) {
1211
0
  case COAP_TLS_LIBRARY_NOTLS:
1212
0
    snprintf(buffer, bufsize, "TLS Library: None");
1213
0
    break;
1214
0
  case COAP_TLS_LIBRARY_TINYDTLS:
1215
0
    snprintf(buffer, bufsize, "TLS Library: TinyDTLS - runtime %lu.%lu.%lu, "
1216
0
             "libcoap built for %lu.%lu.%lu",
1217
0
             (unsigned long)(tls_version->version >> 16),
1218
0
             (unsigned long)((tls_version->version >> 8) & 0xff),
1219
0
             (unsigned long)(tls_version->version & 0xff),
1220
0
             (unsigned long)(tls_version->built_version >> 16),
1221
0
             (unsigned long)((tls_version->built_version >> 8) & 0xff),
1222
0
             (unsigned long)(tls_version->built_version & 0xff));
1223
0
    break;
1224
0
  case COAP_TLS_LIBRARY_OPENSSL:
1225
0
    switch (tls_version->version &0xf) {
1226
0
    case 0:
1227
0
      strcpy(beta, "-dev");
1228
0
      break;
1229
0
    case 0xf:
1230
0
      strcpy(beta, "");
1231
0
      break;
1232
0
    default:
1233
0
      strcpy(beta, "-beta");
1234
0
      beta[5] = (tls_version->version &0xf) + '0';
1235
0
      beta[6] = '\000';
1236
0
      break;
1237
0
    }
1238
0
    sub[0] = ((tls_version->version >> 4) & 0xff) ?
1239
0
             ((tls_version->version >> 4) & 0xff) + 'a' -1 : '\000';
1240
0
    sub[1] = '\000';
1241
0
    switch (tls_version->built_version &0xf) {
1242
0
    case 0:
1243
0
      strcpy(b_beta, "-dev");
1244
0
      break;
1245
0
    case 0xf:
1246
0
      strcpy(b_beta, "");
1247
0
      break;
1248
0
    default:
1249
0
      strcpy(b_beta, "-beta");
1250
0
      b_beta[5] = (tls_version->built_version &0xf) + '0';
1251
0
      b_beta[6] = '\000';
1252
0
      break;
1253
0
    }
1254
0
    b_sub[0] = ((tls_version->built_version >> 4) & 0xff) ?
1255
0
               ((tls_version->built_version >> 4) & 0xff) + 'a' -1 : '\000';
1256
0
    b_sub[1] = '\000';
1257
0
    snprintf(buffer, bufsize, "TLS Library: OpenSSL - runtime "
1258
0
             "%lu.%lu.%lu%s%s, libcoap built for %lu.%lu.%lu%s%s",
1259
0
             (unsigned long)(tls_version->version >> 28),
1260
0
             (unsigned long)((tls_version->version >> 20) & 0xff),
1261
0
             (unsigned long)((tls_version->version >> 12) & 0xff), sub, beta,
1262
0
             (unsigned long)(tls_version->built_version >> 28),
1263
0
             (unsigned long)((tls_version->built_version >> 20) & 0xff),
1264
0
             (unsigned long)((tls_version->built_version >> 12) & 0xff),
1265
0
             b_sub, b_beta);
1266
0
    break;
1267
0
  case COAP_TLS_LIBRARY_GNUTLS:
1268
0
    snprintf(buffer, bufsize, "TLS Library: GnuTLS - runtime %lu.%lu.%lu, "
1269
0
             "libcoap built for %lu.%lu.%lu",
1270
0
             (unsigned long)(tls_version->version >> 16),
1271
0
             (unsigned long)((tls_version->version >> 8) & 0xff),
1272
0
             (unsigned long)(tls_version->version & 0xff),
1273
0
             (unsigned long)(tls_version->built_version >> 16),
1274
0
             (unsigned long)((tls_version->built_version >> 8) & 0xff),
1275
0
             (unsigned long)(tls_version->built_version & 0xff));
1276
0
    break;
1277
0
  case COAP_TLS_LIBRARY_MBEDTLS:
1278
0
    snprintf(buffer, bufsize, "TLS Library: Mbed TLS - runtime %lu.%lu.%lu, "
1279
0
             "libcoap built for %lu.%lu.%lu",
1280
0
             (unsigned long)(tls_version->version >> 24),
1281
0
             (unsigned long)((tls_version->version >> 16) & 0xff),
1282
0
             (unsigned long)((tls_version->version >> 8) & 0xff),
1283
0
             (unsigned long)(tls_version->built_version >> 24),
1284
0
             (unsigned long)((tls_version->built_version >> 16) & 0xff),
1285
0
             (unsigned long)((tls_version->built_version >> 8) & 0xff));
1286
0
    break;
1287
0
  case COAP_TLS_LIBRARY_WOLFSSL:
1288
0
    snprintf(buffer, bufsize, "TLS Library: wolfSSL - runtime %lu.%lu.%lu, "
1289
0
             "libcoap built for %lu.%lu.%lu",
1290
0
             (unsigned long)(tls_version->version >> 24),
1291
0
             (unsigned long)((tls_version->version >> 12) & 0xfff),
1292
0
             (unsigned long)((tls_version->version >> 0) & 0xfff),
1293
0
             (unsigned long)(tls_version->built_version >> 24),
1294
0
             (unsigned long)((tls_version->built_version >> 12) & 0xfff),
1295
0
             (unsigned long)((tls_version->built_version >> 0) & 0xfff));
1296
0
    break;
1297
0
  case COAP_TLS_LIBRARY_OPENHITLS:
1298
0
    snprintf(buffer, bufsize, "TLS Library: openHiTLS - runtime %lu.%lu.%lu, "
1299
0
             "libcoap built for %lu.%lu.%lu",
1300
0
             (unsigned long)((tls_version->version >> 28) & 0x0f),
1301
0
             (unsigned long)((tls_version->version >> 20) & 0xff),
1302
0
             (unsigned long)((tls_version->version >> 16) & 0x0f),
1303
0
             (unsigned long)((tls_version->built_version >> 28) & 0x0f),
1304
0
             (unsigned long)((tls_version->built_version >> 20) & 0xff),
1305
0
             (unsigned long)((tls_version->built_version >> 16) & 0x0f));
1306
0
    break;
1307
0
  default:
1308
0
    snprintf(buffer, bufsize, "Library type %d unknown", tls_version->type);
1309
0
    break;
1310
0
  }
1311
0
  return buffer;
1312
0
}
1313
1314
char *
1315
0
coap_string_tls_support(char *buffer, size_t bufsize) {
1316
0
  const int have_tls = coap_tls_is_supported();
1317
0
  const int have_dtls = coap_dtls_is_supported();
1318
0
  const int have_psk = coap_dtls_psk_is_supported();
1319
0
  const int have_pki = coap_dtls_pki_is_supported();
1320
0
  const int have_pkcs11 = coap_dtls_pkcs11_is_supported();
1321
0
  const int have_rpk = coap_dtls_rpk_is_supported();
1322
0
  const int have_cid = coap_dtls_cid_is_supported();
1323
0
  const int have_oscore = coap_oscore_is_supported();
1324
0
  const int have_ws = coap_ws_is_supported();
1325
1326
0
  if (have_dtls == 0 && have_tls == 0) {
1327
0
    snprintf(buffer, bufsize, "(No DTLS or TLS support)\n(%sOSCORE)\n(%sWebSockets)",
1328
0
             have_oscore ? "Have " : "No ",
1329
0
             have_ws ? "Have " : "No ");
1330
0
    return buffer;
1331
0
  }
1332
0
  snprintf(buffer, bufsize,
1333
0
           "(%sDTLS and %sTLS support; %sPSK, %sPKI, %sPKCS11, %sRPK and %sCID support)\n(%sOSCORE)\n(%sWebSockets)",
1334
0
           have_dtls ? "" : "No ",
1335
0
           have_tls ? "" : "no ",
1336
0
           have_psk ? "" : "no ",
1337
0
           have_pki ? "" : "no ",
1338
0
           have_pkcs11 ? "" : "no ",
1339
0
           have_rpk ? "" : "no ",
1340
0
           have_cid ? "" : "no ",
1341
0
           have_oscore ? "Have " : "No ",
1342
0
           have_ws ? "Have " : "No ");
1343
0
  return buffer;
1344
0
}
1345
1346
static coap_log_handler_t log_handler = NULL;
1347
1348
void
1349
0
coap_set_log_handler(coap_log_handler_t handler) {
1350
0
  log_handler = handler;
1351
0
}
1352
1353
#if COAP_THREAD_SAFE && COAP_THREAD_NUM_LOGGING
1354
/* Visible to only this thread */
1355
extern COAP_THREAD_LOCAL_VAR uint32_t thread_no;
1356
/* Visible across all threads */
1357
extern uint32_t max_thread_no;
1358
#endif /* COAP_THREAD_SAFE && COAP_THREAD_NUM_LOGGING */
1359
1360
void
1361
0
coap_log_impl(coap_log_t level, const char *format, ...) {
1362
1363
#if COAP_THREAD_SAFE
1364
  coap_mutex_lock(&m_log_impl);
1365
#endif /* COAP_THREAD_SAFE */
1366
1367
0
  if (log_handler) {
1368
#if COAP_CONSTRAINED_STACK
1369
    /* message can be protected by m_log_impl if needed */
1370
    static char message[COAP_DEBUG_BUF_SIZE];
1371
#else /* ! COAP_CONSTRAINED_STACK */
1372
0
    char message[COAP_DEBUG_BUF_SIZE];
1373
0
#endif /* ! COAP_CONSTRAINED_STACK */
1374
0
    va_list ap;
1375
0
    va_start(ap, format);
1376
1377
#ifdef RIOT_VERSION
1378
    flash_vsnprintf(message, sizeof(message), format, ap);
1379
#else /* !RIOT_VERSION */
1380
0
    vsnprintf(message, sizeof(message), format, ap);
1381
0
#endif /* !RIOT_VERSION */
1382
0
    va_end(ap);
1383
0
    log_handler(level, message);
1384
0
  } else {
1385
0
    char timebuf[32];
1386
0
    coap_tick_t now;
1387
0
    va_list ap;
1388
0
    FILE *log_fd;
1389
0
    size_t len;
1390
1391
0
    log_fd = level <= COAP_LOG_CRIT ? COAP_ERR_FD : COAP_DEBUG_FD;
1392
1393
0
    coap_ticks(&now);
1394
0
    len = print_timestamp(timebuf,sizeof(timebuf), now);
1395
0
    if (len)
1396
0
      fprintf(log_fd, "%.*s ", (int)len, timebuf);
1397
1398
#if COAP_THREAD_SAFE && COAP_THREAD_NUM_LOGGING
1399
    if (thread_no == 0) {
1400
      /*
1401
       * All other call to coap_mutex_lock(&m_io_threads) immediately
1402
       * by setting thread_no if 0. So deadlock should never occur.
1403
       */
1404
      coap_mutex_lock(&m_io_threads);
1405
      thread_no = ++max_thread_no;
1406
      coap_mutex_unlock(&m_io_threads);
1407
    }
1408
    fprintf(log_fd, "%2d ", thread_no);
1409
#endif /* COAP_THREAD_SAFE && COAP_THREAD_NUM_LOGGING */
1410
1411
0
    fprintf(log_fd, "%s ", coap_log_level_desc(level));
1412
1413
0
    va_start(ap, format);
1414
#ifdef RIOT_VERSION
1415
    flash_vfprintf(log_fd, format, ap);
1416
#else /* !RIOT_VERSION */
1417
0
    vfprintf(log_fd, format, ap);
1418
0
#endif /* !RIOT_VERSION */
1419
0
    va_end(ap);
1420
0
    fflush(log_fd);
1421
0
  }
1422
1423
#if COAP_THREAD_SAFE
1424
  coap_mutex_unlock(&m_log_impl);
1425
#endif /* COAP_THREAD_SAFE */
1426
0
}
1427
1428
#ifndef COAP_DEBUG_INTERVAL_COUNT
1429
0
#define COAP_DEBUG_INTERVAL_COUNT 10
1430
#endif
1431
1432
static struct packet_num_interval {
1433
  size_t start;
1434
  size_t end;
1435
} packet_loss_intervals[COAP_DEBUG_INTERVAL_COUNT];
1436
static int num_packet_loss_intervals = 0;
1437
static uint16_t packet_loss_level = 0;
1438
static size_t send_packet_count = 0;
1439
struct packet_num_interval packet_fail_intervals[COAP_DEBUG_INTERVAL_COUNT];
1440
static int num_packet_fail_intervals = 0;
1441
static uint16_t packet_fail_level = 0;
1442
static size_t recv_packet_count = 0;
1443
struct packet_num_interval packet_drop_intervals[COAP_DEBUG_INTERVAL_COUNT];
1444
static int num_packet_drop_intervals = 0;
1445
static uint16_t packet_drop_level = 0;
1446
1447
static int
1448
coap_debug_set_packet_common(const char *loss_level, struct packet_num_interval *intervals,
1449
0
                             int *num_intervals, uint16_t *level, size_t *count) {
1450
0
  const char *p = loss_level;
1451
0
  char *end = NULL;
1452
0
  int n = (int)strtol(p, &end, 10), i = 0;
1453
1454
0
  *level = 0;
1455
0
  *num_intervals = 0;
1456
1457
0
  if (end == p || n < 0)
1458
0
    return 0;
1459
0
  if (*end == '%') {
1460
0
    if (n > 100)
1461
0
      n = 100;
1462
0
    *level = n * 0xffff / 100;
1463
0
    coap_log_debug("packet loss level set to %d%%\n", n);
1464
0
  } else {
1465
0
    if (n <= 0)
1466
0
      return 0;
1467
0
    while (i < COAP_DEBUG_INTERVAL_COUNT) {
1468
0
      intervals[i].start = n;
1469
0
      if (*end == '-') {
1470
0
        p = end + 1;
1471
0
        n = (int)strtol(p, &end, 10);
1472
0
        if (end == p || n <= 0)
1473
0
          return 0;
1474
0
      }
1475
0
      intervals[i++].end = n;
1476
0
      if (*end == 0)
1477
0
        break;
1478
0
      if (*end != ',')
1479
0
        return 0;
1480
0
      p = end + 1;
1481
0
      n = (int)strtol(p, &end, 10);
1482
0
      if (end == p || n <= 0)
1483
0
        return 0;
1484
0
    }
1485
0
    if (i == COAP_DEBUG_INTERVAL_COUNT)
1486
0
      return 0;
1487
0
    *num_intervals = i;
1488
0
  }
1489
0
  *count = 0;
1490
0
  return 1;
1491
0
}
1492
1493
int
1494
0
coap_debug_set_packet_loss(const char *loss_level) {
1495
0
  return coap_debug_set_packet_common(loss_level, packet_loss_intervals,
1496
0
                                      &num_packet_loss_intervals, &packet_loss_level, &send_packet_count);
1497
0
}
1498
1499
int
1500
0
coap_debug_send_packet(void) {
1501
0
  ++send_packet_count;
1502
0
  if (num_packet_loss_intervals > 0) {
1503
0
    int i;
1504
0
    for (i = 0; i < num_packet_loss_intervals; i++) {
1505
0
      if (send_packet_count >= packet_loss_intervals[i].start &&
1506
0
          send_packet_count <= packet_loss_intervals[i].end) {
1507
0
        coap_log_debug("Following packet no %" PRIuS " dropped\n", send_packet_count);
1508
0
        return 0;
1509
0
      }
1510
0
    }
1511
0
  }
1512
0
  if (packet_loss_level > 0) {
1513
0
    uint16_t r = 0;
1514
0
    coap_prng_lkd((uint8_t *)&r, 2);
1515
0
    if (r < packet_loss_level) {
1516
0
      coap_log_debug("Following packet no %"PRIuS " dropped\n", send_packet_count);
1517
0
      return 0;
1518
0
    }
1519
0
  }
1520
0
  if (num_packet_fail_intervals > 0) {
1521
0
    int i;
1522
0
    for (i = 0; i < num_packet_fail_intervals; i++) {
1523
0
      if (send_packet_count >= packet_fail_intervals[i].start &&
1524
0
          send_packet_count <= packet_fail_intervals[i].end) {
1525
0
        coap_log_debug("Following packet no %"PRIuS " failed\n", send_packet_count);
1526
0
        errno = ECONNREFUSED;
1527
0
        return -1;
1528
0
      }
1529
0
    }
1530
0
  }
1531
0
  if (packet_fail_level > 0) {
1532
0
    uint16_t r = 0;
1533
0
    coap_prng_lkd((uint8_t *)&r, 2);
1534
0
    if (r < packet_fail_level) {
1535
0
      coap_log_debug("Following packet no %"PRIuS " failed\n", send_packet_count);
1536
0
      errno = ECONNREFUSED;
1537
0
      return -1;
1538
0
    }
1539
0
  }
1540
0
  return 1;
1541
0
}
1542
1543
int
1544
0
coap_debug_set_packet_fail(const char *fail_level) {
1545
0
  return coap_debug_set_packet_common(fail_level, packet_fail_intervals,
1546
0
                                      &num_packet_fail_intervals, &packet_fail_level, &send_packet_count);
1547
0
}
1548
1549
int
1550
0
coap_debug_set_packet_drop(const char *drop_level) {
1551
0
  return coap_debug_set_packet_common(drop_level, packet_drop_intervals,
1552
0
                                      &num_packet_drop_intervals, &packet_drop_level, &recv_packet_count);
1553
0
}
1554
1555
int
1556
0
coap_debug_recv_packet(void) {
1557
0
  ++recv_packet_count;
1558
0
  if (num_packet_drop_intervals > 0) {
1559
0
    int i;
1560
0
    for (i = 0; i < num_packet_drop_intervals; i++) {
1561
0
      if (recv_packet_count >= packet_drop_intervals[i].start &&
1562
0
          recv_packet_count <= packet_drop_intervals[i].end) {
1563
0
        coap_log_debug("Incoming packet no %" PRIuS " dropped\n", recv_packet_count);
1564
0
        return 0;
1565
0
      }
1566
0
    }
1567
0
  }
1568
0
  if (packet_drop_level > 0) {
1569
0
    uint16_t r = 0;
1570
0
    coap_prng_lkd((uint8_t *)&r, 2);
1571
0
    if (r < packet_drop_level) {
1572
0
      coap_log_debug("Incoming packet no %"PRIuS " dropped\n", recv_packet_count);
1573
0
      return 0;
1574
0
    }
1575
0
  }
1576
0
  return 1;
1577
0
}
1578
1579
1580
void
1581
0
coap_debug_reset(void) {
1582
  log_handler = NULL;
1583
0
  maxlog = COAP_LOG_WARN;
1584
0
  use_fprintf_for_show_pdu = 1;
1585
0
  num_packet_loss_intervals = 0;
1586
0
  packet_loss_level = 0;
1587
0
  num_packet_fail_intervals = 0;
1588
0
  packet_fail_level = 0;
1589
0
  send_packet_count = 0;
1590
0
  num_packet_drop_intervals = 0;
1591
0
  packet_drop_level = 0;
1592
0
  recv_packet_count = 0;
1593
0
}