libcoap  4.0.3
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
debug.c
Go to the documentation of this file.
1 /* debug.c -- debug utilities
2  *
3  * Copyright (C) 2010--2012 Olaf Bergmann <bergmann@tzi.org>
4  *
5  * This file is part of the CoAP library libcoap. Please see
6  * README for terms of use.
7  */
8 
9 #include "config.h"
10 
11 #if defined(HAVE_ASSERT_H) && !defined(assert)
12 # include <assert.h>
13 #endif
14 
15 #include <stdarg.h>
16 #include <stdio.h>
17 #include <string.h>
18 #include <ctype.h>
19 
20 #ifdef HAVE_ARPA_INET_H
21 #include <arpa/inet.h>
22 #endif
23 
24 #ifdef HAVE_TIME_H
25 #include <time.h>
26 #endif
27 
28 #include "debug.h"
29 #include "net.h"
30 
31 #ifdef WITH_CONTIKI
32 # ifndef DEBUG
33 # define DEBUG DEBUG_PRINT
34 # endif /* DEBUG */
35 #include "net/uip-debug.h"
36 #endif
37 
38 static coap_log_t maxlog = LOG_WARN; /* default maximum log level */
39 
42  return maxlog;
43 }
44 
45 void
47  maxlog = level;
48 }
49 
50 /* this array has the same order as the type log_t */
51 static char *loglevels[] = {
52  "EMRG", "ALRT", "CRIT", "WARN", "NOTE", "INFO", "DEBG"
53 };
54 
55 #ifdef HAVE_TIME_H
56 
57 static inline size_t
58 print_timestamp(char *s, size_t len, coap_tick_t t) {
59  struct tm *tmp;
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);
63 }
64 
65 #else /* alternative implementation: just print the timestamp */
66 
67 static inline size_t
68 print_timestamp(char *s, size_t len, coap_tick_t t) {
69 #ifdef HAVE_SNPRINTF
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 */
75  return 0;
76 #endif /* HAVE_SNPRINTF */
77 }
78 
79 #endif /* HAVE_TIME_H */
80 
81 #ifndef NDEBUG
82 
83 #ifndef HAVE_STRNLEN
84 
92 static inline size_t
93 strnlen(const char *s, size_t maxlen) {
94  size_t n = 0;
95  while(*s++ && n < maxlen)
96  ++n;
97  return n;
98 }
99 #endif /* HAVE_STRNLEN */
100 
101 unsigned int
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);
107 
108  if (buflen == 0 || len == 0)
109  return 0;
110 
111  while (len) {
112  if (!encode_always && isprint(*data)) {
113  if (cnt == buflen)
114  break;
115  *result++ = *data;
116  ++cnt;
117  } else {
118  if (cnt+4 < buflen) {
119  *result++ = '\\';
120  *result++ = 'x';
121  *result++ = hex[(*data & 0xf0) >> 4];
122  *result++ = hex[*data & 0x0f];
123  cnt += 4;
124  } else
125  break;
126  }
127 
128  ++data; --len;
129  }
130 
131  *result = '\0';
132  return cnt;
133 }
134 
135 #ifndef min
136 #define min(a,b) ((a) < (b) ? (a) : (b))
137 #endif
138 
139 size_t
140 coap_print_addr(const struct __coap_address_t *addr, unsigned char *buf, size_t len) {
141 #ifdef HAVE_ARPA_INET_H
142  const void *addrptr = NULL;
143  in_port_t port;
144  unsigned char *p = buf;
145 
146  switch (addr->addr.sa.sa_family) {
147  case AF_INET:
148  addrptr = &addr->addr.sin.sin_addr;
149  port = ntohs(addr->addr.sin.sin_port);
150  break;
151  case AF_INET6:
152  if (len < 7) /* do not proceed if buffer is even too short for [::]:0 */
153  return 0;
154 
155  *p++ = '[';
156 
157  addrptr = &addr->addr.sin6.sin6_addr;
158  port = ntohs(addr->addr.sin6.sin6_port);
159 
160  break;
161  default:
162  memcpy(buf, "(unknown address type)", min(22, len));
163  return min(22, len);
164  }
165 
166  if (inet_ntop(addr->addr.sa.sa_family, addrptr, (char *)p, len) == 0) {
167  perror("coap_print_addr");
168  return 0;
169  }
170 
171  p += strnlen((char *)p, len);
172 
173  if (addr->addr.sa.sa_family == AF_INET6) {
174  if (p < buf + len) {
175  *p++ = ']';
176  } else
177  return 0;
178  }
179 
180  p += snprintf((char *)p, buf + len - p + 1, ":%d", port);
181 
182  return buf + len - p;
183 #else /* HAVE_ARPA_INET_H */
184 # if WITH_CONTIKI
185  unsigned char *p = buf;
186  uint8_t i;
187 # if WITH_UIP6
188  const unsigned char hex[] = "0123456789ABCDEF";
189 
190  if (len < 41)
191  return 0;
192 
193  *p++ = '[';
194 
195  for (i=0; i < 8; i += 4) {
196  *p++ = hex[(addr->addr.u16[i] & 0xf000) >> 24];
197  *p++ = hex[(addr->addr.u16[i] & 0x0f00) >> 16];
198  *p++ = hex[(addr->addr.u16[i] & 0x00f0) >> 8];
199  *p++ = hex[(addr->addr.u16[i] & 0x000f)];
200  *p++ = ':';
201  }
202  *(p-1) = ']';
203 # else /* WITH_UIP6 */
204 # warning "IPv4 network addresses will not be included in debug output"
205 
206  if (len < 21)
207  return 0;
208 # endif /* WITH_UIP6 */
209  if (buf + len - p < 6)
210  return 0;
211 
212 #ifdef HAVE_SNPRINTF
213  p += snprintf((char *)p, buf + len - p + 1, ":%d", uip_htons(addr->port));
214 #else /* HAVE_SNPRINTF */
215  /* @todo manual conversion of port number */
216 #endif /* HAVE_SNPRINTF */
217 
218  return buf + len - p;
219 # else /* WITH_CONTIKI */
220  /* TODO: output addresses manually */
221 # warning "inet_ntop() not available, network addresses will not be included in debug output"
222 # endif /* WITH_CONTIKI */
223  return 0;
224 #endif
225 }
226 
227 #ifndef WITH_CONTIKI
228 void
230  unsigned char buf[COAP_MAX_PDU_SIZE]; /* need some space for output creation */
231  int encode = 0, have_options = 0;
232  coap_opt_iterator_t opt_iter;
233  coap_opt_t *option;
234 
235  fprintf(COAP_DEBUG_FD, "v:%d t:%d tkl:%d c:%d id:%u",
236  pdu->hdr->version, pdu->hdr->type,
237  pdu->hdr->token_length,
238  pdu->hdr->code, ntohs(pdu->hdr->id));
239 
240  /* show options, if any */
242 
243  while ((option = coap_option_next(&opt_iter))) {
244  if (!have_options) {
245  have_options = 1;
246  fprintf(COAP_DEBUG_FD, " o: [");
247  } else {
248  fprintf(COAP_DEBUG_FD, ",");
249  }
250 
251  if (opt_iter.type == COAP_OPTION_URI_PATH ||
252  opt_iter.type == COAP_OPTION_PROXY_URI ||
253  opt_iter.type == COAP_OPTION_URI_HOST ||
254  opt_iter.type == COAP_OPTION_LOCATION_PATH ||
255  opt_iter.type == COAP_OPTION_LOCATION_QUERY ||
256  opt_iter.type == COAP_OPTION_URI_PATH ||
257  opt_iter.type == COAP_OPTION_URI_QUERY) {
258  encode = 0;
259  } else {
260  encode = 1;
261  }
262 
263  if (print_readable(COAP_OPT_VALUE(option),
264  COAP_OPT_LENGTH(option),
265  buf, sizeof(buf), encode ))
266  fprintf(COAP_DEBUG_FD, " %d:'%s'", opt_iter.type, buf);
267  }
268 
269  if (have_options)
270  fprintf(COAP_DEBUG_FD, " ]");
271 
272  if (pdu->data) {
273  assert(pdu->data < (unsigned char *)pdu->hdr + pdu->length);
274  print_readable(pdu->data,
275  (unsigned char *)pdu->hdr + pdu->length - pdu->data,
276  buf, sizeof(buf), 0 );
277  fprintf(COAP_DEBUG_FD, " d:%s", buf);
278  }
279  fprintf(COAP_DEBUG_FD, "\n");
280  fflush(COAP_DEBUG_FD);
281 }
282 
283 #else /* WITH_CONTIKI */
284 
285 void
286 coap_show_pdu(const coap_pdu_t *pdu) {
287  unsigned char buf[80]; /* need some space for output creation */
288 
289  PRINTF("v:%d t:%d oc:%d c:%d id:%u",
290  pdu->hdr->version, pdu->hdr->type,
291  pdu->hdr->optcnt, pdu->hdr->code, uip_ntohs(pdu->hdr->id));
292 
293  /* show options, if any */
294  if (pdu->hdr->optcnt) {
295  coap_opt_iterator_t opt_iter;
296  coap_opt_t *option;
298 
299  PRINTF(" o:");
300  while ((option = coap_option_next(&opt_iter))) {
301 
302  if (print_readable(COAP_OPT_VALUE(option),
303  COAP_OPT_LENGTH(option),
304  buf, sizeof(buf), 0))
305  PRINTF(" %d:%s", opt_iter.type, buf);
306  }
307  }
308 
309  if (pdu->data < (unsigned char *)pdu->hdr + pdu->length) {
310  print_readable(pdu->data,
311  (unsigned char *)pdu->hdr + pdu->length - pdu->data,
312  buf, sizeof(buf), 0 );
313  PRINTF(" d:%s", buf);
314  }
315  PRINTF("\r\n");
316 }
317 #endif /* WITH_CONTIKI */
318 
319 #endif /* NDEBUG */
320 
321 #ifndef WITH_CONTIKI
322 void
323 coap_log_impl(coap_log_t level, const char *format, ...) {
324  char timebuf[32];
325  coap_tick_t now;
326  va_list ap;
327  FILE *log_fd;
328 
329  if (maxlog < level)
330  return;
331 
332  log_fd = level <= LOG_CRIT ? COAP_ERR_FD : COAP_DEBUG_FD;
333 
334  coap_ticks(&now);
335  if (print_timestamp(timebuf,sizeof(timebuf), now))
336  fprintf(log_fd, "%s ", timebuf);
337 
338  if (level <= LOG_DEBUG)
339  fprintf(log_fd, "%s ", loglevels[level]);
340 
341  va_start(ap, format);
342  vfprintf(log_fd, format, ap);
343  va_end(ap);
344  fflush(log_fd);
345 }
346 #else /* WITH_CONTIKI */
347 void
348 coap_log_impl(coap_log_t level, const char *format, ...) {
349  char timebuf[32];
350  coap_tick_t now;
351  va_list ap;
352 
353  if (maxlog < level)
354  return;
355 
356  coap_ticks(&now);
357  if (print_timestamp(timebuf,sizeof(timebuf), now))
358  PRINTF("%s ", timebuf);
359 
360  if (level <= LOG_DEBUG)
361  PRINTF("%s ", loglevels[level]);
362 
363  va_start(ap, format);
364  PRINTF(format, ap);
365  va_end(ap);
366 }
367 #endif /* WITH_CONTIKI */