eedf247633be73042696b9206a4d918bacdeadcb
[platform/upstream/iotivity.git] / resource / csdk / connectivity / lib / libcoap-4.1.1 / debug.c
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
40 coap_log_t coap_get_log_level()
41 {
42     return maxlog;
43 }
44
45 void coap_set_log_level(coap_log_t level)
46 {
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 #ifdef HAVE_TIME_H
55
56 static inline size_t print_timestamp(char *s, size_t len, coap_tick_t t)
57 {
58     struct tm *tmp;
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);
62 }
63
64 #else /* alternative implementation: just print the timestamp */
65
66 static inline size_t
67 print_timestamp(char *s, size_t len, coap_tick_t t)
68 {
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 /** 
85  * A length-safe strlen() fake. 
86  * 
87  * @param s      The string to count characters != 0.
88  * @param maxlen The maximum length of @p s.
89  * 
90  * @return The length of @p s.
91  */
92 static inline size_t
93 strnlen(const char *s, size_t maxlen)
94 {
95     size_t n = 0;
96     while(*s++ && n < maxlen)
97     ++n;
98     return n;
99 }
100 #endif /* HAVE_STRNLEN */
101
102 unsigned int print_readable(const unsigned char *data, unsigned int len, unsigned char *result,
103         unsigned int buflen, int encode_always)
104 {
105     const unsigned char hex[] = "0123456789ABCDEF";
106     unsigned int cnt = 0;
107     assert(data || len == 0);
108
109     if (buflen == 0 || len == 0)
110         return 0;
111
112     while (len)
113     {
114         if (!encode_always && isprint(*data))
115         {
116             if (cnt == buflen)
117                 break;
118             *result++ = *data;
119             ++cnt;
120         }
121         else
122         {
123             if (cnt + 4 < buflen)
124             {
125                 *result++ = '\\';
126                 *result++ = 'x';
127                 *result++ = hex[(*data & 0xf0) >> 4];
128                 *result++ = hex[*data & 0x0f];
129                 cnt += 4;
130             }
131             else
132                 break;
133         }
134
135         ++data;
136         --len;
137     }
138
139     *result = '\0';
140     return cnt;
141 }
142
143 #ifndef min
144 #define min(a,b) ((a) < (b) ? (a) : (b))
145 #endif
146
147 size_t coap_print_addr(const struct coap_address_t *addr, unsigned char *buf, size_t len)
148 {
149 #ifdef HAVE_ARPA_INET_H
150     const void *addrptr = NULL;
151     in_port_t port;
152     unsigned char *p = buf;
153
154     switch (addr->addr.sa.sa_family)
155     {
156         case AF_INET:
157             addrptr = &addr->addr.sin.sin_addr;
158             port = ntohs(addr->addr.sin.sin_port);
159             break;
160         case AF_INET6:
161             if (len < 7) /* do not proceed if buffer is even too short for [::]:0 */
162                 return 0;
163
164             *p++ = '[';
165
166             addrptr = &addr->addr.sin6.sin6_addr;
167             port = ntohs(addr->addr.sin6.sin6_port);
168
169             break;
170         default:
171             memcpy(buf, "(unknown address type)", min(22, len));
172             return min(22, len);
173     }
174
175     if (inet_ntop(addr->addr.sa.sa_family, addrptr, (char *) p, len) == 0)
176     {
177         perror("coap_print_addr");
178         return 0;
179     }
180
181     p += strnlen((char *) p, len);
182
183     if (addr->addr.sa.sa_family == AF_INET6)
184     {
185         if (p < buf + len)
186         {
187             *p++ = ']';
188         }
189         else
190             return 0;
191     }
192
193     p += snprintf((char *) p, buf + len - p + 1, ":%d", port);
194
195     return buf + len - p;
196 #else /* HAVE_ARPA_INET_H */
197 # if WITH_CONTIKI
198     unsigned char *p = buf;
199     uint8_t i;
200 #  if WITH_UIP6
201     const unsigned char hex[] = "0123456789ABCDEF";
202
203     if (len < 41)
204     return 0;
205
206     *p++ = '[';
207
208     for (i=0; i < 16; i += 2)
209     {
210         if (i)
211         {
212             *p++ = ':';
213         }
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)];
218     }
219     *p++ = ']';
220 #  else /* WITH_UIP6 */
221 #   warning "IPv4 network addresses will not be included in debug output"
222
223     if (len < 21)
224     return 0;
225 #  endif /* WITH_UIP6 */
226     if (buf + len - p < 6)
227     return 0;
228
229 #ifdef HAVE_SNPRINTF
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 */
234
235     return p - buf;
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 */
240     return 0;
241 #endif
242 }
243
244 #ifndef WITH_CONTIKI
245 void coap_show_pdu(const coap_pdu_t *pdu)
246 {
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;
250     coap_opt_t *option;
251
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));
254
255     /* show options, if any */
256     coap_option_iterator_init((coap_pdu_t *) pdu, &opt_iter, COAP_OPT_ALL);
257
258     while ((option = coap_option_next(&opt_iter)))
259     {
260         if (!have_options)
261         {
262             have_options = 1;
263             fprintf(COAP_DEBUG_FD, " o: [");
264         }
265         else
266         {
267             fprintf(COAP_DEBUG_FD, ",");
268         }
269
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)
275         {
276             encode = 0;
277         }
278         else
279         {
280             encode = 1;
281         }
282
283         if (print_readable(COAP_OPT_VALUE(option), COAP_OPT_LENGTH(option), buf, sizeof(buf),
284                 encode))
285             fprintf(COAP_DEBUG_FD, " %d:'%s'", opt_iter.type, buf);
286     }
287
288     if (have_options)
289         fprintf(COAP_DEBUG_FD, " ]");
290
291     if (pdu->data)
292     {
293         assert(pdu->data < (unsigned char *) pdu->hdr + pdu->length);
294         print_readable(pdu->data, (unsigned char *) pdu->hdr + pdu->length - pdu->data, buf,
295                 sizeof(buf), 0);
296         fprintf(COAP_DEBUG_FD, " d:%s", buf);
297     }
298     fprintf(COAP_DEBUG_FD, "\n");
299     fflush(COAP_DEBUG_FD);
300 }
301
302 #else /* WITH_CONTIKI */
303
304 void
305 coap_show_pdu(const coap_pdu_t *pdu)
306 {
307     unsigned char buf[80]; /* need some space for output creation */
308
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));
312
313     /* show options, if any */
314     if (pdu->hdr->optcnt)
315     {
316         coap_opt_iterator_t opt_iter;
317         coap_opt_t *option;
318         coap_option_iterator_init((coap_pdu_t *)pdu, &opt_iter, COAP_OPT_ALL);
319
320         PRINTF(" o:");
321         while ((option = coap_option_next(&opt_iter)))
322         {
323
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);
328         }
329     }
330
331     if (pdu->data < (unsigned char *)pdu->hdr + pdu->length)
332     {
333         print_readable(pdu->data,
334                 (unsigned char *)pdu->hdr + pdu->length - pdu->data,
335                 buf, sizeof(buf), 0 );
336         PRINTF(" d:%s", buf);
337     }
338     PRINTF("\r\n");
339 }
340 #endif /* WITH_CONTIKI */
341
342 #endif /* NDEBUG */
343
344 #ifndef WITH_CONTIKI
345 void coap_log_impl(coap_log_t level, const char *format, ...)
346 {
347     char timebuf[32];
348     coap_tick_t now;
349     va_list ap;
350     FILE *log_fd;
351
352     if (maxlog < level)
353         return;
354
355     log_fd = level <= LOG_CRIT ? COAP_ERR_FD : COAP_DEBUG_FD;
356
357     coap_ticks(&now);
358     if (print_timestamp(timebuf, sizeof(timebuf), now))
359         fprintf(log_fd, "%s ", timebuf);
360
361     if (level <= LOG_DEBUG)
362         fprintf(log_fd, "%s ", loglevels[level]);
363
364     va_start(ap, format);
365     vfprintf(log_fd, format, ap);
366     va_end(ap);
367     fflush(log_fd);
368 }
369 #else /* WITH_CONTIKI */
370 void
371 coap_log_impl(coap_log_t level, const char *format, ...)
372 {
373     char timebuf[32];
374     coap_tick_t now;
375     va_list ap;
376
377     if (maxlog < level)
378     return;
379
380     coap_ticks(&now);
381     if (print_timestamp(timebuf,sizeof(timebuf), now))
382     PRINTF("%s ", timebuf);
383
384     if (level <= LOG_DEBUG)
385     PRINTF("%s ", loglevels[level]);
386
387     va_start(ap, format);
388     PRINTF(format, ap);
389     va_end(ap);
390 }
391 #endif /* WITH_CONTIKI */