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;
152 unsigned char *p = buf;
154 switch (addr->addr.sa.sa_family)
157 addrptr = &addr->addr.sin.sin_addr;
158 port = ntohs(addr->addr.sin.sin_port);
161 if (len < 7) /* do not proceed if buffer is even too short for [::]:0 */
166 addrptr = &addr->addr.sin6.sin6_addr;
167 port = ntohs(addr->addr.sin6.sin6_port);
171 memcpy(buf, "(unknown address type)", min(22, len));
175 if (inet_ntop(addr->addr.sa.sa_family, addrptr, (char *) p, len) == 0)
177 perror("coap_print_addr");
181 p += strnlen((char *) p, len);
183 if (addr->addr.sa.sa_family == AF_INET6)
193 p += snprintf((char *) p, buf + len - p + 1, ":%d", port);
195 return buf + len - p;
196 #else /* HAVE_ARPA_INET_H */
198 unsigned char *p = buf;
201 const unsigned char hex[] = "0123456789ABCDEF";
208 for (i=0; i < 16; i += 2)
214 *p++ = hex[(addr->addr.u8[i] & 0xf0) >> 4];
215 *p++ = hex[(addr->addr.u8[i] & 0x0f)];
216 *p++ = hex[(addr->addr.u8[i+1] & 0xf0) >> 4];
217 *p++ = hex[(addr->addr.u8[i+1] & 0x0f)];
220 # else /* WITH_UIP6 */
221 # warning "IPv4 network addresses will not be included in debug output"
225 # endif /* WITH_UIP6 */
226 if (buf + len - p < 6)
230 p += snprintf((char *)p, buf + len - p + 1, ":%d", uip_htons(addr->port));
231 #else /* HAVE_SNPRINTF */
232 /* @todo manual conversion of port number */
233 #endif /* HAVE_SNPRINTF */
236 # else /* WITH_CONTIKI */
237 /* TODO: output addresses manually */
238 # warning "inet_ntop() not available, network addresses will not be included in debug output"
239 # endif /* WITH_CONTIKI */
245 void coap_show_pdu(const coap_pdu_t *pdu)
247 unsigned char buf[COAP_MAX_PDU_SIZE]; /* need some space for output creation */
248 int encode = 0, have_options = 0;
249 coap_opt_iterator_t opt_iter;
252 fprintf(COAP_DEBUG_FD, "v:%d t:%d tkl:%d c:%d id:%u", pdu->hdr->version, pdu->hdr->type,
253 pdu->hdr->token_length, pdu->hdr->code, ntohs(pdu->hdr->id));
255 /* show options, if any */
256 coap_option_iterator_init((coap_pdu_t *) pdu, &opt_iter, COAP_OPT_ALL);
258 while ((option = coap_option_next(&opt_iter)))
263 fprintf(COAP_DEBUG_FD, " o: [");
267 fprintf(COAP_DEBUG_FD, ",");
270 if (opt_iter.type == COAP_OPTION_URI_PATH || opt_iter.type == COAP_OPTION_PROXY_URI
271 || opt_iter.type == COAP_OPTION_URI_HOST
272 || opt_iter.type == COAP_OPTION_LOCATION_PATH
273 || opt_iter.type == COAP_OPTION_LOCATION_QUERY
274 || opt_iter.type == COAP_OPTION_URI_PATH || opt_iter.type == COAP_OPTION_URI_QUERY)
283 if (print_readable(COAP_OPT_VALUE(option), COAP_OPT_LENGTH(option), buf, sizeof(buf),
285 fprintf(COAP_DEBUG_FD, " %d:'%s'", opt_iter.type, buf);
289 fprintf(COAP_DEBUG_FD, " ]");
293 assert(pdu->data < (unsigned char *) pdu->hdr + pdu->length);
294 print_readable(pdu->data, (unsigned char *) pdu->hdr + pdu->length - pdu->data, buf,
296 fprintf(COAP_DEBUG_FD, " d:%s", buf);
298 fprintf(COAP_DEBUG_FD, "\n");
299 fflush(COAP_DEBUG_FD);
302 #else /* WITH_CONTIKI */
305 coap_show_pdu(const coap_pdu_t *pdu)
307 unsigned char buf[80]; /* need some space for output creation */
309 PRINTF("v:%d t:%d oc:%d c:%d id:%u",
310 pdu->hdr->version, pdu->hdr->type,
311 pdu->hdr->optcnt, pdu->hdr->code, uip_ntohs(pdu->hdr->id));
313 /* show options, if any */
314 if (pdu->hdr->optcnt)
316 coap_opt_iterator_t opt_iter;
318 coap_option_iterator_init((coap_pdu_t *)pdu, &opt_iter, COAP_OPT_ALL);
321 while ((option = coap_option_next(&opt_iter)))
324 if (print_readable(COAP_OPT_VALUE(option),
325 COAP_OPT_LENGTH(option),
326 buf, sizeof(buf), 0))
327 PRINTF(" %d:%s", opt_iter.type, buf);
331 if (pdu->data < (unsigned char *)pdu->hdr + pdu->length)
333 print_readable(pdu->data,
334 (unsigned char *)pdu->hdr + pdu->length - pdu->data,
335 buf, sizeof(buf), 0 );
336 PRINTF(" d:%s", buf);
340 #endif /* WITH_CONTIKI */
345 void coap_log_impl(coap_log_t level, const char *format, ...)
347 //TODO: Implement logging functionalities for Arduino
353 void coap_log_impl(coap_log_t level, const char *format, ...)
363 log_fd = level <= LOG_CRIT ? COAP_ERR_FD : COAP_DEBUG_FD;
366 if (print_timestamp(timebuf, sizeof(timebuf), now))
367 fprintf(log_fd, "%s ", timebuf);
369 if (level <= LOG_DEBUG)
370 fprintf(log_fd, "%s ", loglevels[level]);
372 va_start(ap, format);
373 vfprintf(log_fd, format, ap);
377 #else /* WITH_CONTIKI */
379 coap_log_impl(coap_log_t level, const char *format, ...)
389 if (print_timestamp(timebuf,sizeof(timebuf), now))
390 PRINTF("%s ", timebuf);
392 if (level <= LOG_DEBUG)
393 PRINTF("%s ", loglevels[level]);
395 va_start(ap, format);
399 #endif /* WITH_CONTIKI */