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