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 */
41 coap_get_log_level() {
46 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"
58 print_timestamp(char *s, size_t len, coap_tick_t t) {
60 time_t now = clock_offset + (t / COAP_TICKS_PER_SECOND);
61 tmp = localtime(&now);
62 return strftime(s, len, "%b %d %H:%M:%S", tmp);
65 #else /* alternative implementation: just print the timestamp */
68 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) {
95 while(*s++ && n < maxlen)
99 #endif /* HAVE_STRNLEN */
102 print_readable( const unsigned char *data, unsigned int len,
103 unsigned char *result, unsigned int buflen, int encode_always ) {
104 const unsigned char hex[] = "0123456789ABCDEF";
105 unsigned int cnt = 0;
106 assert(data || len == 0);
108 if (buflen == 0 || len == 0)
112 if (!encode_always && isprint(*data)) {
118 if (cnt+4 < buflen) {
121 *result++ = hex[(*data & 0xf0) >> 4];
122 *result++ = hex[*data & 0x0f];
136 #define min(a,b) ((a) < (b) ? (a) : (b))
140 coap_print_addr(const struct coap_address_t *addr, unsigned char *buf, size_t len) {
146 #ifdef HAVE_ARPA_INET_H
147 const void *addrptr = NULL;
149 unsigned char *p = buf;
151 switch (addr->addr.sa.sa_family) {
153 addrptr = &addr->addr.sin.sin_addr;
154 port = ntohs(addr->addr.sin.sin_port);
157 if (len < 7) /* do not proceed if buffer is even too short for [::]:0 */
162 addrptr = &addr->addr.sin6.sin6_addr;
163 port = ntohs(addr->addr.sin6.sin6_port);
167 memcpy(buf, "(unknown address type)", min(22, len));
171 if (inet_ntop(addr->addr.sa.sa_family, addrptr, (char *)p, len) == 0) {
172 perror("coap_print_addr");
176 p += strnlen((char *)p, len);
178 if (addr->addr.sa.sa_family == AF_INET6) {
185 p += snprintf((char *)p, buf + len - p + 1, ":%d", port);
187 return buf + len - p;
188 #else /* HAVE_ARPA_INET_H */
190 unsigned char *p = buf;
193 const unsigned char hex[] = "0123456789ABCDEF";
200 for (i=0; i < 16; i += 2) {
204 *p++ = hex[(addr->addr.u8[i] & 0xf0) >> 4];
205 *p++ = hex[(addr->addr.u8[i] & 0x0f)];
206 *p++ = hex[(addr->addr.u8[i+1] & 0xf0) >> 4];
207 *p++ = hex[(addr->addr.u8[i+1] & 0x0f)];
210 # else /* WITH_UIP6 */
211 # warning "IPv4 network addresses will not be included in debug output"
215 # endif /* WITH_UIP6 */
216 if (buf + len - p < 6)
220 p += snprintf((char *)p, buf + len - p + 1, ":%d", uip_htons(addr->port));
221 #else /* HAVE_SNPRINTF */
222 /* @todo manual conversion of port number */
223 #endif /* HAVE_SNPRINTF */
226 # else /* WITH_CONTIKI */
227 /* TODO: output addresses manually */
228 # warning "inet_ntop() not available, network addresses will not be included in debug output"
229 # endif /* WITH_CONTIKI */
237 coap_show_pdu(const coap_pdu_t *pdu) {
238 unsigned char buf[COAP_MAX_PDU_SIZE]; /* need some space for output creation */
239 int encode = 0, have_options = 0;
240 coap_opt_iterator_t opt_iter;
243 fprintf(COAP_DEBUG_FD, "v:%d t:%d tkl:%d c:%d id:%u",
244 pdu->hdr->version, pdu->hdr->type,
245 pdu->hdr->token_length,
246 pdu->hdr->code, ntohs(pdu->hdr->id));
248 /* show options, if any */
249 coap_option_iterator_init((coap_pdu_t *)pdu, &opt_iter, COAP_OPT_ALL);
251 while ((option = coap_option_next(&opt_iter))) {
254 fprintf(COAP_DEBUG_FD, " o: [");
256 fprintf(COAP_DEBUG_FD, ",");
259 if (opt_iter.type == COAP_OPTION_URI_PATH ||
260 opt_iter.type == COAP_OPTION_PROXY_URI ||
261 opt_iter.type == COAP_OPTION_URI_HOST ||
262 opt_iter.type == COAP_OPTION_LOCATION_PATH ||
263 opt_iter.type == COAP_OPTION_LOCATION_QUERY ||
264 opt_iter.type == COAP_OPTION_URI_PATH ||
265 opt_iter.type == COAP_OPTION_URI_QUERY) {
271 if (print_readable(COAP_OPT_VALUE(option),
272 COAP_OPT_LENGTH(option),
273 buf, sizeof(buf), encode ))
274 fprintf(COAP_DEBUG_FD, " %d:'%s'", opt_iter.type, buf);
278 fprintf(COAP_DEBUG_FD, " ]");
281 assert(pdu->data < (unsigned char *)pdu->hdr + pdu->length);
282 print_readable(pdu->data,
283 (unsigned char *)pdu->hdr + pdu->length - pdu->data,
284 buf, sizeof(buf), 0 );
285 fprintf(COAP_DEBUG_FD, " d:%s", buf);
287 fprintf(COAP_DEBUG_FD, "\n");
288 fflush(COAP_DEBUG_FD);
291 #else /* WITH_CONTIKI */
294 coap_show_pdu(const coap_pdu_t *pdu) {
295 unsigned char buf[80]; /* need some space for output creation */
297 PRINTF("v:%d t:%d oc:%d c:%d id:%u",
298 pdu->hdr->version, pdu->hdr->type,
299 pdu->hdr->optcnt, pdu->hdr->code, uip_ntohs(pdu->hdr->id));
301 /* show options, if any */
302 if (pdu->hdr->optcnt) {
303 coap_opt_iterator_t opt_iter;
305 coap_option_iterator_init((coap_pdu_t *)pdu, &opt_iter, COAP_OPT_ALL);
308 while ((option = coap_option_next(&opt_iter))) {
310 if (print_readable(COAP_OPT_VALUE(option),
311 COAP_OPT_LENGTH(option),
312 buf, sizeof(buf), 0))
313 PRINTF(" %d:%s", opt_iter.type, buf);
317 if (pdu->data < (unsigned char *)pdu->hdr + pdu->length) {
318 print_readable(pdu->data,
319 (unsigned char *)pdu->hdr + pdu->length - pdu->data,
320 buf, sizeof(buf), 0 );
321 PRINTF(" d:%s", buf);
325 #endif /* WITH_CONTIKI */
331 coap_log_impl(coap_log_t level, const char *format, ...) {
340 log_fd = level <= LOG_CRIT ? COAP_ERR_FD : COAP_DEBUG_FD;
343 if (print_timestamp(timebuf,sizeof(timebuf), now))
344 fprintf(log_fd, "%s ", timebuf);
346 if (level <= LOG_DEBUG)
347 fprintf(log_fd, "%s ", loglevels[level]);
349 va_start(ap, format);
350 vfprintf(log_fd, format, ap);
354 #else /* WITH_CONTIKI */
356 coap_log_impl(coap_log_t level, const char *format, ...) {
365 if (print_timestamp(timebuf,sizeof(timebuf), now))
366 PRINTF("%s ", timebuf);
368 if (level <= LOG_DEBUG)
369 PRINTF("%s ", loglevels[level]);
371 va_start(ap, format);
375 #endif /* WITH_CONTIKI */