coap_debug.c 27 KB

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