df9ae7b0d1bd3c5e932870aab4d56933dbcdaf00
[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 #if defined(__ANDROID__)
152     __uint16_t port;
153 #else
154     in_port_t port;
155 #endif
156     unsigned char *p = buf;
157
158     switch (addr->addr.sa.sa_family)
159     {
160         case AF_INET:
161             addrptr = &addr->addr.sin.sin_addr;
162             port = ntohs(addr->addr.sin.sin_port);
163             break;
164         case AF_INET6:
165             if (len < 7) /* do not proceed if buffer is even too short for [::]:0 */
166                 return 0;
167
168             *p++ = '[';
169
170             addrptr = &addr->addr.sin6.sin6_addr;
171             port = ntohs(addr->addr.sin6.sin6_port);
172
173             break;
174         default:
175             memcpy(buf, "(unknown address type)", min(22, len));
176             return min(22, len);
177     }
178
179     if (inet_ntop(addr->addr.sa.sa_family, addrptr, (char *) p, len) == 0)
180     {
181         perror("coap_print_addr");
182         return 0;
183     }
184
185     p += strnlen((char *) p, len);
186
187     if (addr->addr.sa.sa_family == AF_INET6)
188     {
189         if (p < buf + len)
190         {
191             *p++ = ']';
192         }
193         else
194             return 0;
195     }
196
197     p += snprintf((char *) p, buf + len - p + 1, ":%d", port);
198
199     return buf + len - p;
200 #else /* HAVE_ARPA_INET_H */
201 # if WITH_CONTIKI
202     unsigned char *p = buf;
203     uint8_t i;
204 #  if WITH_UIP6
205     const unsigned char hex[] = "0123456789ABCDEF";
206
207     if (len < 41)
208     return 0;
209
210     *p++ = '[';
211
212     for (i=0; i < 16; i += 2)
213     {
214         if (i)
215         {
216             *p++ = ':';
217         }
218         *p++ = hex[(addr->addr.u8[i] & 0xf0) >> 4];
219         *p++ = hex[(addr->addr.u8[i] & 0x0f)];
220         *p++ = hex[(addr->addr.u8[i+1] & 0xf0) >> 4];
221         *p++ = hex[(addr->addr.u8[i+1] & 0x0f)];
222     }
223     *p++ = ']';
224 #  else /* WITH_UIP6 */
225 #   warning "IPv4 network addresses will not be included in debug output"
226
227     if (len < 21)
228     return 0;
229 #  endif /* WITH_UIP6 */
230     if (buf + len - p < 6)
231     return 0;
232
233 #ifdef HAVE_SNPRINTF
234     p += snprintf((char *)p, buf + len - p + 1, ":%d", uip_htons(addr->port));
235 #else /* HAVE_SNPRINTF */
236     /* @todo manual conversion of port number */
237 #endif /* HAVE_SNPRINTF */
238
239     return p - buf;
240 # else /* WITH_CONTIKI */
241     /* TODO: output addresses manually */
242 #   warning "inet_ntop() not available, network addresses will not be included in debug output"
243 # endif /* WITH_CONTIKI */
244     return 0;
245 #endif
246 }
247
248 #ifndef WITH_CONTIKI
249 void coap_show_pdu(const coap_pdu_t *pdu)
250 {
251     unsigned char buf[COAP_MAX_PDU_SIZE]; /* need some space for output creation */
252     int encode = 0, have_options = 0;
253     coap_opt_iterator_t opt_iter;
254     coap_opt_t *option;
255
256     fprintf(COAP_DEBUG_FD, "v:%d t:%d tkl:%d c:%d id:%u", pdu->hdr->version, pdu->hdr->type,
257             pdu->hdr->token_length, pdu->hdr->code, ntohs(pdu->hdr->id));
258
259     /* show options, if any */
260     coap_option_iterator_init((coap_pdu_t *) pdu, &opt_iter, COAP_OPT_ALL);
261
262     while ((option = coap_option_next(&opt_iter)))
263     {
264         if (!have_options)
265         {
266             have_options = 1;
267             fprintf(COAP_DEBUG_FD, " o: [");
268         }
269         else
270         {
271             fprintf(COAP_DEBUG_FD, ",");
272         }
273
274         if (opt_iter.type == COAP_OPTION_URI_PATH || opt_iter.type == COAP_OPTION_PROXY_URI
275                 || opt_iter.type == COAP_OPTION_URI_HOST
276                 || opt_iter.type == COAP_OPTION_LOCATION_PATH
277                 || opt_iter.type == COAP_OPTION_LOCATION_QUERY
278                 || opt_iter.type == COAP_OPTION_URI_PATH || opt_iter.type == COAP_OPTION_URI_QUERY)
279         {
280             encode = 0;
281         }
282         else
283         {
284             encode = 1;
285         }
286
287         if (print_readable(COAP_OPT_VALUE(option), COAP_OPT_LENGTH(option), buf, sizeof(buf),
288                 encode))
289             fprintf(COAP_DEBUG_FD, " %d:'%s'", opt_iter.type, buf);
290     }
291
292     if (have_options)
293         fprintf(COAP_DEBUG_FD, " ]");
294
295     if (pdu->data)
296     {
297         assert(pdu->data < (unsigned char *) pdu->hdr + pdu->length);
298         print_readable(pdu->data, (unsigned char *) pdu->hdr + pdu->length - pdu->data, buf,
299                 sizeof(buf), 0);
300         fprintf(COAP_DEBUG_FD, " d:%s", buf);
301     }
302     fprintf(COAP_DEBUG_FD, "\n");
303     fflush(COAP_DEBUG_FD);
304 }
305
306 #else /* WITH_CONTIKI */
307
308 void
309 coap_show_pdu(const coap_pdu_t *pdu)
310 {
311     unsigned char buf[80]; /* need some space for output creation */
312
313     PRINTF("v:%d t:%d oc:%d c:%d id:%u",
314             pdu->hdr->version, pdu->hdr->type,
315             pdu->hdr->optcnt, pdu->hdr->code, uip_ntohs(pdu->hdr->id));
316
317     /* show options, if any */
318     if (pdu->hdr->optcnt)
319     {
320         coap_opt_iterator_t opt_iter;
321         coap_opt_t *option;
322         coap_option_iterator_init((coap_pdu_t *)pdu, &opt_iter, COAP_OPT_ALL);
323
324         PRINTF(" o:");
325         while ((option = coap_option_next(&opt_iter)))
326         {
327
328             if (print_readable(COAP_OPT_VALUE(option),
329                             COAP_OPT_LENGTH(option),
330                             buf, sizeof(buf), 0))
331             PRINTF(" %d:%s", opt_iter.type, buf);
332         }
333     }
334
335     if (pdu->data < (unsigned char *)pdu->hdr + pdu->length)
336     {
337         print_readable(pdu->data,
338                 (unsigned char *)pdu->hdr + pdu->length - pdu->data,
339                 buf, sizeof(buf), 0 );
340         PRINTF(" d:%s", buf);
341     }
342     PRINTF("\r\n");
343 }
344 #endif /* WITH_CONTIKI */
345
346 #endif /* NDEBUG */
347
348 #ifdef WITH_ARDUINO
349 void coap_log_impl(coap_log_t level, const char *format, ...)
350 {
351     //TODO: Implement logging functionalities for Arduino
352 }
353 #endif
354
355 #ifndef WITH_ARDUINO
356 #ifndef WITH_CONTIKI
357 void coap_log_impl(coap_log_t level, const char *format, ...)
358 {
359     char timebuf[32];
360     coap_tick_t now;
361     va_list ap;
362     FILE *log_fd;
363
364     if (maxlog < level)
365         return;
366
367     log_fd = level <= LOG_CRIT ? COAP_ERR_FD : COAP_DEBUG_FD;
368
369     coap_ticks(&now);
370     if (print_timestamp(timebuf, sizeof(timebuf), now))
371         fprintf(log_fd, "%s ", timebuf);
372
373     if (level <= LOG_DEBUG)
374         fprintf(log_fd, "%s ", loglevels[level]);
375
376     va_start(ap, format);
377     vfprintf(log_fd, format, ap);
378     va_end(ap);
379     fflush(log_fd);
380 }
381 #else /* WITH_CONTIKI */
382 void
383 coap_log_impl(coap_log_t level, const char *format, ...)
384 {
385     char timebuf[32];
386     coap_tick_t now;
387     va_list ap;
388
389     if (maxlog < level)
390     return;
391
392     coap_ticks(&now);
393     if (print_timestamp(timebuf,sizeof(timebuf), now))
394     PRINTF("%s ", timebuf);
395
396     if (level <= LOG_DEBUG)
397     PRINTF("%s ", loglevels[level]);
398
399     va_start(ap, format);
400     PRINTF(format, ap);
401     va_end(ap);
402 }
403 #endif /* WITH_CONTIKI */
404 #endif