1 /* debug.c -- debug utilities
3 * Copyright (C) 2010--2012 Olaf Bergmann <bergmann@tzi.org>
5 * This file is part of the CoAP library libcoap. Please see
6 * README for terms of use.
11 #if defined(HAVE_ASSERT_H) && !defined(assert)
20 #ifdef HAVE_ARPA_INET_H
21 #include <arpa/inet.h>
33 # define DEBUG DEBUG_PRINT
35 #include "net/uip-debug.h"
38 static coap_log_t maxlog = LOG_WARNING; /* default maximum log level */
40 coap_log_t coap_get_log_level()
45 void coap_set_log_level(coap_log_t level)
50 /* this array has the same order as the type log_t */
51 static char *loglevels[] =
52 { "EMRG", "ALRT", "CRIT", "ERR", "WARN", "NOTE", "INFO", "DEBG" };
56 static inline size_t print_timestamp(char *s, size_t len, coap_tick_t t)
59 time_t now = clock_offset + (t / COAP_TICKS_PER_SECOND);
60 tmp = localtime(&now);
61 return strftime(s, len, "%b %d %H:%M:%S", tmp);
64 #else /* alternative implementation: just print the timestamp */
67 print_timestamp(char *s, size_t len, coap_tick_t t)
70 return snprintf(s, len, "%u.%03u",
71 (unsigned int)(clock_offset + (t / COAP_TICKS_PER_SECOND)),
72 (unsigned int)(t % COAP_TICKS_PER_SECOND));
73 #else /* HAVE_SNPRINTF */
74 /* @todo do manual conversion of timestamp */
76 #endif /* HAVE_SNPRINTF */
79 #endif /* HAVE_TIME_H */
85 * A length-safe strlen() fake.
87 * @param s The string to count characters != 0.
88 * @param maxlen The maximum length of @p s.
90 * @return The length of @p s.
93 strnlen(const char *s, size_t maxlen)
96 while(*s++ && n < maxlen)
100 #endif /* HAVE_STRNLEN */
102 unsigned int print_readable(const unsigned char *data, unsigned int len, unsigned char *result,
103 unsigned int buflen, int encode_always)
105 const unsigned char hex[] = "0123456789ABCDEF";
106 unsigned int cnt = 0;
107 assert(data || len == 0);
109 if (buflen == 0 || len == 0)
114 if (!encode_always && isprint(*data))
123 if (cnt + 4 < buflen)
127 *result++ = hex[(*data & 0xf0) >> 4];
128 *result++ = hex[*data & 0x0f];
144 #define min(a,b) ((a) < (b) ? (a) : (b))
147 size_t coap_print_addr(const struct coap_address_t *addr, unsigned char *buf, size_t len)
149 #ifdef HAVE_ARPA_INET_H
150 const void *addrptr = NULL;
151 #if defined(__ANDROID__)
156 unsigned char *p = buf;
158 switch (addr->addr.sa.sa_family)
161 addrptr = &addr->addr.sin.sin_addr;
162 port = ntohs(addr->addr.sin.sin_port);
165 if (len < 7) /* do not proceed if buffer is even too short for [::]:0 */
170 addrptr = &addr->addr.sin6.sin6_addr;
171 port = ntohs(addr->addr.sin6.sin6_port);
175 memcpy(buf, "(unknown address type)", min(22, len));
179 if (inet_ntop(addr->addr.sa.sa_family, addrptr, (char *) p, len) == 0)
181 perror("coap_print_addr");
185 p += strnlen((char *) p, len);
187 if (addr->addr.sa.sa_family == AF_INET6)
197 p += snprintf((char *) p, buf + len - p + 1, ":%d", port);
199 return buf + len - p;
200 #else /* HAVE_ARPA_INET_H */
202 unsigned char *p = buf;
205 const unsigned char hex[] = "0123456789ABCDEF";
212 for (i=0; i < 16; i += 2)
218 *p++ = hex[(addr->addr.u8[i] & 0xf0) >> 4];
219 *p++ = hex[(addr->addr.u8[i] & 0x0f)];
220 *p++ = hex[(addr->addr.u8[i+1] & 0xf0) >> 4];
221 *p++ = hex[(addr->addr.u8[i+1] & 0x0f)];
224 # else /* WITH_UIP6 */
225 # warning "IPv4 network addresses will not be included in debug output"
229 # endif /* WITH_UIP6 */
230 if (buf + len - p < 6)
234 p += snprintf((char *)p, buf + len - p + 1, ":%d", uip_htons(addr->port));
235 #else /* HAVE_SNPRINTF */
236 /* @todo manual conversion of port number */
237 #endif /* HAVE_SNPRINTF */
240 # else /* WITH_CONTIKI */
241 /* TODO: output addresses manually */
242 # warning "inet_ntop() not available, network addresses will not be included in debug output"
243 # endif /* WITH_CONTIKI */
249 void coap_show_pdu(const coap_pdu_t *pdu)
251 unsigned char buf[COAP_MAX_PDU_SIZE]; /* need some space for output creation */
252 int encode = 0, have_options = 0;
253 coap_opt_iterator_t opt_iter;
256 fprintf(COAP_DEBUG_FD, "v:%d t:%d tkl:%d c:%d id:%u", pdu->hdr->version, pdu->hdr->type,
257 pdu->hdr->token_length, pdu->hdr->code, ntohs(pdu->hdr->id));
259 /* show options, if any */
260 coap_option_iterator_init((coap_pdu_t *) pdu, &opt_iter, COAP_OPT_ALL);
262 while ((option = coap_option_next(&opt_iter)))
267 fprintf(COAP_DEBUG_FD, " o: [");
271 fprintf(COAP_DEBUG_FD, ",");
274 if (opt_iter.type == COAP_OPTION_URI_PATH || opt_iter.type == COAP_OPTION_PROXY_URI
275 || opt_iter.type == COAP_OPTION_URI_HOST
276 || opt_iter.type == COAP_OPTION_LOCATION_PATH
277 || opt_iter.type == COAP_OPTION_LOCATION_QUERY
278 || opt_iter.type == COAP_OPTION_URI_PATH || opt_iter.type == COAP_OPTION_URI_QUERY)
287 if (print_readable(COAP_OPT_VALUE(option), COAP_OPT_LENGTH(option), buf, sizeof(buf),
289 fprintf(COAP_DEBUG_FD, " %d:'%s'", opt_iter.type, buf);
293 fprintf(COAP_DEBUG_FD, " ]");
297 assert(pdu->data < (unsigned char *) pdu->hdr + pdu->length);
298 print_readable(pdu->data, (unsigned char *) pdu->hdr + pdu->length - pdu->data, buf,
300 fprintf(COAP_DEBUG_FD, " d:%s", buf);
302 fprintf(COAP_DEBUG_FD, "\n");
303 fflush(COAP_DEBUG_FD);
306 #else /* WITH_CONTIKI */
309 coap_show_pdu(const coap_pdu_t *pdu)
311 unsigned char buf[80]; /* need some space for output creation */
313 PRINTF("v:%d t:%d oc:%d c:%d id:%u",
314 pdu->hdr->version, pdu->hdr->type,
315 pdu->hdr->optcnt, pdu->hdr->code, uip_ntohs(pdu->hdr->id));
317 /* show options, if any */
318 if (pdu->hdr->optcnt)
320 coap_opt_iterator_t opt_iter;
322 coap_option_iterator_init((coap_pdu_t *)pdu, &opt_iter, COAP_OPT_ALL);
325 while ((option = coap_option_next(&opt_iter)))
328 if (print_readable(COAP_OPT_VALUE(option),
329 COAP_OPT_LENGTH(option),
330 buf, sizeof(buf), 0))
331 PRINTF(" %d:%s", opt_iter.type, buf);
335 if (pdu->data < (unsigned char *)pdu->hdr + pdu->length)
337 print_readable(pdu->data,
338 (unsigned char *)pdu->hdr + pdu->length - pdu->data,
339 buf, sizeof(buf), 0 );
340 PRINTF(" d:%s", buf);
344 #endif /* WITH_CONTIKI */
349 void coap_log_impl(coap_log_t level, const char *format, ...)
351 //TODO: Implement logging functionalities for Arduino
357 void coap_log_impl(coap_log_t level, const char *format, ...)
367 log_fd = level <= LOG_CRIT ? COAP_ERR_FD : COAP_DEBUG_FD;
370 if (print_timestamp(timebuf, sizeof(timebuf), now))
371 fprintf(log_fd, "%s ", timebuf);
373 if (level <= LOG_DEBUG)
374 fprintf(log_fd, "%s ", loglevels[level]);
376 va_start(ap, format);
377 vfprintf(log_fd, format, ap);
381 #else /* WITH_CONTIKI */
383 coap_log_impl(coap_log_t level, const char *format, ...)
393 if (print_timestamp(timebuf,sizeof(timebuf), now))
394 PRINTF("%s ", timebuf);
396 if (level <= LOG_DEBUG)
397 PRINTF("%s ", loglevels[level]);
399 va_start(ap, format);
403 #endif /* WITH_CONTIKI */