libcoap  4.1.1
 All Data Structures Files Functions Variables Typedefs 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_WARNING; /* 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", "ERR", "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 < 16; i += 2) {
196  if (i) {
197  *p++ = ':';
198  }
199  *p++ = hex[(addr->addr.u8[i] & 0xf0) >> 4];
200  *p++ = hex[(addr->addr.u8[i] & 0x0f)];
201  *p++ = hex[(addr->addr.u8[i+1] & 0xf0) >> 4];
202  *p++ = hex[(addr->addr.u8[i+1] & 0x0f)];
203  }
204  *p++ = ']';
205 # else /* WITH_UIP6 */
206 # warning "IPv4 network addresses will not be included in debug output"
207 
208  if (len < 21)
209  return 0;
210 # endif /* WITH_UIP6 */
211  if (buf + len - p < 6)
212  return 0;
213 
214 #ifdef HAVE_SNPRINTF
215  p += snprintf((char *)p, buf + len - p + 1, ":%d", uip_htons(addr->port));
216 #else /* HAVE_SNPRINTF */
217  /* @todo manual conversion of port number */
218 #endif /* HAVE_SNPRINTF */
219 
220  return p - buf;
221 # else /* WITH_CONTIKI */
222  /* TODO: output addresses manually */
223 # warning "inet_ntop() not available, network addresses will not be included in debug output"
224 # endif /* WITH_CONTIKI */
225  return 0;
226 #endif
227 }
228 
229 #ifndef WITH_CONTIKI
230 void
232  unsigned char buf[COAP_MAX_PDU_SIZE]; /* need some space for output creation */
233  int encode = 0, have_options = 0;
234  coap_opt_iterator_t opt_iter;
235  coap_opt_t *option;
236 
237  fprintf(COAP_DEBUG_FD, "v:%d t:%d tkl:%d c:%d id:%u",
238  pdu->hdr->version, pdu->hdr->type,
239  pdu->hdr->token_length,
240  pdu->hdr->code, ntohs(pdu->hdr->id));
241 
242  /* show options, if any */
244 
245  while ((option = coap_option_next(&opt_iter))) {
246  if (!have_options) {
247  have_options = 1;
248  fprintf(COAP_DEBUG_FD, " o: [");
249  } else {
250  fprintf(COAP_DEBUG_FD, ",");
251  }
252 
253  if (opt_iter.type == COAP_OPTION_URI_PATH ||
254  opt_iter.type == COAP_OPTION_PROXY_URI ||
255  opt_iter.type == COAP_OPTION_URI_HOST ||
256  opt_iter.type == COAP_OPTION_LOCATION_PATH ||
257  opt_iter.type == COAP_OPTION_LOCATION_QUERY ||
258  opt_iter.type == COAP_OPTION_URI_PATH ||
259  opt_iter.type == COAP_OPTION_URI_QUERY) {
260  encode = 0;
261  } else {
262  encode = 1;
263  }
264 
265  if (print_readable(COAP_OPT_VALUE(option),
266  COAP_OPT_LENGTH(option),
267  buf, sizeof(buf), encode ))
268  fprintf(COAP_DEBUG_FD, " %d:'%s'", opt_iter.type, buf);
269  }
270 
271  if (have_options)
272  fprintf(COAP_DEBUG_FD, " ]");
273 
274  if (pdu->data) {
275  assert(pdu->data < (unsigned char *)pdu->hdr + pdu->length);
276  print_readable(pdu->data,
277  (unsigned char *)pdu->hdr + pdu->length - pdu->data,
278  buf, sizeof(buf), 0 );
279  fprintf(COAP_DEBUG_FD, " d:%s", buf);
280  }
281  fprintf(COAP_DEBUG_FD, "\n");
282  fflush(COAP_DEBUG_FD);
283 }
284 
285 #else /* WITH_CONTIKI */
286 
287 void
288 coap_show_pdu(const coap_pdu_t *pdu) {
289  unsigned char buf[80]; /* need some space for output creation */
290 
291  PRINTF("v:%d t:%d oc:%d c:%d id:%u",
292  pdu->hdr->version, pdu->hdr->type,
293  pdu->hdr->optcnt, pdu->hdr->code, uip_ntohs(pdu->hdr->id));
294 
295  /* show options, if any */
296  if (pdu->hdr->optcnt) {
297  coap_opt_iterator_t opt_iter;
298  coap_opt_t *option;
300 
301  PRINTF(" o:");
302  while ((option = coap_option_next(&opt_iter))) {
303 
304  if (print_readable(COAP_OPT_VALUE(option),
305  COAP_OPT_LENGTH(option),
306  buf, sizeof(buf), 0))
307  PRINTF(" %d:%s", opt_iter.type, buf);
308  }
309  }
310 
311  if (pdu->data < (unsigned char *)pdu->hdr + pdu->length) {
312  print_readable(pdu->data,
313  (unsigned char *)pdu->hdr + pdu->length - pdu->data,
314  buf, sizeof(buf), 0 );
315  PRINTF(" d:%s", buf);
316  }
317  PRINTF("\r\n");
318 }
319 #endif /* WITH_CONTIKI */
320 
321 #endif /* NDEBUG */
322 
323 #ifndef WITH_CONTIKI
324 void
325 coap_log_impl(coap_log_t level, const char *format, ...) {
326  char timebuf[32];
327  coap_tick_t now;
328  va_list ap;
329  FILE *log_fd;
330 
331  if (maxlog < level)
332  return;
333 
334  log_fd = level <= LOG_CRIT ? COAP_ERR_FD : COAP_DEBUG_FD;
335 
336  coap_ticks(&now);
337  if (print_timestamp(timebuf,sizeof(timebuf), now))
338  fprintf(log_fd, "%s ", timebuf);
339 
340  if (level <= LOG_DEBUG)
341  fprintf(log_fd, "%s ", loglevels[level]);
342 
343  va_start(ap, format);
344  vfprintf(log_fd, format, ap);
345  va_end(ap);
346  fflush(log_fd);
347 }
348 #else /* WITH_CONTIKI */
349 void
350 coap_log_impl(coap_log_t level, const char *format, ...) {
351  char timebuf[32];
352  coap_tick_t now;
353  va_list ap;
354 
355  if (maxlog < level)
356  return;
357 
358  coap_ticks(&now);
359  if (print_timestamp(timebuf,sizeof(timebuf), now))
360  PRINTF("%s ", timebuf);
361 
362  if (level <= LOG_DEBUG)
363  PRINTF("%s ", loglevels[level]);
364 
365  va_start(ap, format);
366  PRINTF(format, ap);
367  va_end(ap);
368 }
369 #endif /* WITH_CONTIKI */
#define COAP_DEBUG_FD
Definition: debug.h:15
#define COAP_ERR_FD
Definition: debug.h:19
#define COAP_OPTION_PROXY_URI
Definition: pdu.h:70
static char * loglevels[]
Definition: debug.c:51
void coap_show_pdu(const coap_pdu_t *pdu)
Definition: debug.c:231
unsigned short id
Definition: pdu.h:173
unsigned short length
PDU length (including header, options, data)
Definition: pdu.h:211
#define COAP_OPT_ALL
Pre-defined filter that includes all options.
Definition: option.h:96
#define min(a, b)
Definition: debug.c:136
short coap_log_t
Definition: debug.h:24
coap_opt_t * coap_option_next(coap_opt_iterator_t *oi)
Updates the iterator oi to point to the next option.
Definition: option.c:157
coap_log_t coap_get_log_level()
Returns the current log level.
Definition: debug.c:41
coap_hdr_t * hdr
Definition: pdu.h:209
#define COAP_OPTION_LOCATION_QUERY
Definition: pdu.h:69
size_t coap_print_addr(const struct coap_address_t *addr, unsigned char *buf, size_t len)
Definition: debug.c:140
void coap_ticks(coap_tick_t *)
Returns the current value of an internal tick counter.
unsigned int code
Definition: pdu.h:172
Header structure for CoAP PDUs.
Definition: pdu.h:206
coap_opt_iterator_t * coap_option_iterator_init(coap_pdu_t *pdu, coap_opt_iterator_t *oi, const coap_opt_filter_t filter)
Initializes the given option iterator oi to point to the beginning of the pdu's option list...
Definition: option.c:118
static coap_log_t maxlog
Definition: debug.c:38
unsigned int print_readable(const unsigned char *data, unsigned int len, unsigned char *result, unsigned int buflen, int encode_always)
Definition: debug.c:102
Iterator to run through PDU options.
Definition: option.h:169
#define COAP_MAX_PDU_SIZE
Definition: pdu.h:27
unsigned short type
decoded option type
Definition: option.h:171
void coap_log_impl(coap_log_t level, const char *format,...)
Writes the given text to COAP_ERR_FD (for level <= LOG_CRIT) or COAP_DEBUG_FD (for level >= LOG_WARNI...
Definition: debug.c:325
#define COAP_OPTION_LOCATION_PATH
Definition: pdu.h:62
#define COAP_OPT_LENGTH(opt)
Definition: option.h:305
unsigned int token_length
Definition: pdu.h:169
#define COAP_OPTION_URI_PATH
Definition: pdu.h:63
unsigned int version
Definition: pdu.h:171
static size_t print_timestamp(char *s, size_t len, coap_tick_t t)
Definition: debug.c:58
void coap_set_log_level(coap_log_t level)
Sets the log level to the specified value.
Definition: debug.c:46
#define COAP_OPTION_URI_QUERY
Definition: pdu.h:67
unsigned int type
Definition: pdu.h:170
unsigned char coap_opt_t
Use byte-oriented access methods here because sliding a complex struct coap_opt_t over the data buffe...
Definition: option.h:26
#define COAP_OPTION_URI_HOST
Definition: pdu.h:58
unsigned char * data
payload
Definition: pdu.h:212
#define COAP_OPT_VALUE(opt)
Definition: option.h:318