1 /* debug.c -- debug utilities
2  *
3  * Copyright (C) 2011--2012 Olaf Bergmann <bergmann@tzi.org>
4  *
5  * Permission is hereby granted, free of charge, to any person
6  * obtaining a copy of this software and associated documentation
7  * files (the "Software"), to deal in the Software without
8  * restriction, including without limitation the rights to use, copy,
9  * modify, merge, publish, distribute, sublicense, and/or sell copies
10  * of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be
14  * included in all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
20  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
21  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23  * SOFTWARE.
24  */
25 
26 #include "tinydtls.h"
27 #include "dtls_config.h"
28 
29 #if defined(HAVE_ASSERT_H) && !defined(assert)
30 #include <assert.h>
31 #endif
32 
33 #include <stdarg.h>
34 #include <stdio.h>
35 
36 #ifdef HAVE_ARPA_INET_H
37 #include <arpa/inet.h>
38 #endif
39 
40 #ifdef HAVE_TIME_H
41 #include <time.h>
42 #endif
43 
44 #include "global.h"
45 #include "debug.h"
46 
47 static int maxlog = DTLS_LOG_WARN;	/* default maximum log level */
48 
dtls_package_name()49 const char *dtls_package_name() {
50   return PACKAGE_NAME;
51 }
52 
dtls_package_version()53 const char *dtls_package_version() {
54   return PACKAGE_VERSION;
55 }
56 
57 log_t
dtls_get_log_level()58 dtls_get_log_level() {
59   return maxlog;
60 }
61 
62 void
dtls_set_log_level(log_t level)63 dtls_set_log_level(log_t level) {
64   maxlog = level;
65 }
66 
67 /* this array has the same order as the type log_t */
68 static char *loglevels[] = {
69   "EMRG", "ALRT", "CRIT", "WARN", "NOTE", "INFO", "DEBG"
70 };
71 
72 #ifdef HAVE_TIME_H
73 
74 static inline size_t
print_timestamp(char * s,size_t len,time_t t)75 print_timestamp(char *s, size_t len, time_t t) {
76   struct tm *tmp;
77   tmp = localtime(&t);
78   return strftime(s, len, "%b %d %H:%M:%S", tmp);
79 }
80 
81 #else /* alternative implementation: just print the timestamp */
82 
83 static inline size_t
print_timestamp(char * s,size_t len,clock_time_t t)84 print_timestamp(char *s, size_t len, clock_time_t t) {
85 #ifdef HAVE_SNPRINTF
86   return snprintf(s, len, "%u.%03u",
87 		  (unsigned int)(t / CLOCK_SECOND),
88 		  (unsigned int)(t % CLOCK_SECOND));
89 #else /* HAVE_SNPRINTF */
90   /* @todo do manual conversion of timestamp */
91   return 0;
92 #endif /* HAVE_SNPRINTF */
93 }
94 
95 #endif /* HAVE_TIME_H */
96 
97 /**
98  * A length-safe strlen() fake.
99  *
100  * @param s      The string to count characters != 0.
101  * @param maxlen The maximum length of @p s.
102  *
103  * @return The length of @p s.
104  */
105 static inline size_t
dtls_strnlen(const char * s,size_t maxlen)106 dtls_strnlen(const char *s, size_t maxlen) {
107   size_t n = 0;
108   while(*s++ && n < maxlen)
109     ++n;
110   return n;
111 }
112 
113 #ifndef min
114 #define min(a,b) ((a) < (b) ? (a) : (b))
115 #endif
116 
117 static size_t
dsrv_print_addr(const session_t * addr,char * buf,size_t len)118 dsrv_print_addr(const session_t *addr, char *buf, size_t len) {
119 #ifdef HAVE_ARPA_INET_H
120   const void *addrptr = NULL;
121   in_port_t port;
122   char *p = buf;
123 
124   switch (addr->addr.sa.sa_family) {
125   case AF_INET:
126     if (len < INET_ADDRSTRLEN)
127       return 0;
128 
129     addrptr = &addr->addr.sin.sin_addr;
130     port = ntohs(addr->addr.sin.sin_port);
131     break;
132   case AF_INET6:
133     if (len < INET6_ADDRSTRLEN + 2)
134       return 0;
135 
136     *p++ = '[';
137 
138     addrptr = &addr->addr.sin6.sin6_addr;
139     port = ntohs(addr->addr.sin6.sin6_port);
140 
141     break;
142   default:
143     memcpy(buf, "(unknown address type)", min(22, len));
144     return min(22, len);
145   }
146 
147   if (inet_ntop(addr->addr.sa.sa_family, addrptr, p, len) == 0) {
148     perror("dsrv_print_addr");
149     return 0;
150   }
151 
152   p += dtls_strnlen(p, len);
153 
154   if (addr->addr.sa.sa_family == AF_INET6) {
155     if (p < buf + len) {
156       *p++ = ']';
157     } else
158       return 0;
159   }
160 
161   p += snprintf(p, buf + len - p + 1, ":%d", port);
162 
163   return p - buf;
164 #else /* HAVE_ARPA_INET_H */
165 # if WITH_CONTIKI
166   char *p = buf;
167 #  ifdef UIP_CONF_IPV6
168   uint8_t i;
169   const char hex[] = "0123456789ABCDEF";
170 
171   if (len < 41)
172     return 0;
173 
174   *p++ = '[';
175 
176   for (i=0; i < 16; i += 2) {
177     if (i) {
178       *p++ = ':';
179     }
180     *p++ = hex[(addr->addr.u8[i] & 0xf0) >> 4];
181     *p++ = hex[(addr->addr.u8[i] & 0x0f)];
182     *p++ = hex[(addr->addr.u8[i+1] & 0xf0) >> 4];
183     *p++ = hex[(addr->addr.u8[i+1] & 0x0f)];
184   }
185   *p++ = ']';
186 #  else /* UIP_CONF_IPV6 */
187 #   warning "IPv4 network addresses will not be included in debug output"
188 
189   if (len < 21)
190     return 0;
191 #  endif /* UIP_CONF_IPV6 */
192   if (buf + len - p < 6)
193     return 0;
194 
195   p += sprintf(p, ":%d", uip_htons(addr->port));
196 
197   return p - buf;
198 # else /* WITH_CONTIKI */
199   /* TODO: output addresses manually */
200 #   warning "inet_ntop() not available, network addresses will not be included in debug output"
201 # endif /* WITH_CONTIKI */
202   return 0;
203 #endif
204 }
205 
206 #ifndef WITH_CONTIKI
207 void
dsrv_log(log_t level,char * format,...)208 dsrv_log(log_t level, char *format, ...) {
209   static char timebuf[32];
210   va_list ap;
211   FILE *log_fd;
212 
213   if (maxlog < level)
214     return;
215 
216   log_fd = level <= DTLS_LOG_CRIT ? stderr : stdout;
217 
218   if (print_timestamp(timebuf,sizeof(timebuf), time(NULL)))
219     fprintf(log_fd, "%s ", timebuf);
220 
221   if (level <= DTLS_LOG_DEBUG)
222     fprintf(log_fd, "%s ", loglevels[level]);
223 
224   va_start(ap, format);
225   vfprintf(log_fd, format, ap);
226   va_end(ap);
227   fflush(log_fd);
228 }
229 #elif defined (HAVE_VPRINTF) /* WITH_CONTIKI */
230 void
dsrv_log(log_t level,char * format,...)231 dsrv_log(log_t level, char *format, ...) {
232   static char timebuf[32];
233   va_list ap;
234 
235   if (maxlog < level)
236     return;
237 
238   if (print_timestamp(timebuf,sizeof(timebuf), clock_time()))
239     PRINTF("%s ", timebuf);
240 
241   if (level <= DTLS_LOG_DEBUG)
242     PRINTF("%s ", loglevels[level]);
243 
244   va_start(ap, format);
245   vprintf(format, ap);
246   va_end(ap);
247 }
248 #endif /* WITH_CONTIKI */
249 
250 #ifndef NDEBUG
251 /** dumps packets in usual hexdump format */
hexdump(const unsigned char * packet,int length)252 void hexdump(const unsigned char *packet, int length) {
253   int n = 0;
254 
255   while (length--) {
256     if (n % 16 == 0)
257       printf("%08X ",n);
258 
259     printf("%02X ", *packet++);
260 
261     n++;
262     if (n % 8 == 0) {
263       if (n % 16 == 0)
264 	printf("\n");
265       else
266 	printf(" ");
267     }
268   }
269 }
270 
271 /** dump as narrow string of hex digits */
dump(unsigned char * buf,size_t len)272 void dump(unsigned char *buf, size_t len) {
273   while (len--)
274     printf("%02x", *buf++);
275 }
276 
dtls_dsrv_log_addr(log_t level,const char * name,const session_t * addr)277 void dtls_dsrv_log_addr(log_t level, const char *name, const session_t *addr)
278 {
279   char addrbuf[73];
280   int len;
281 
282   len = dsrv_print_addr(addr, addrbuf, sizeof(addrbuf));
283   if (!len)
284     return;
285   dsrv_log(level, "%s: %s\n", name, addrbuf);
286 }
287 
288 #ifndef WITH_CONTIKI
289 void
dtls_dsrv_hexdump_log(log_t level,const char * name,const unsigned char * buf,size_t length,int extend)290 dtls_dsrv_hexdump_log(log_t level, const char *name, const unsigned char *buf, size_t length, int extend) {
291   static char timebuf[32];
292   FILE *log_fd;
293   int n = 0;
294 
295   if (maxlog < level)
296     return;
297 
298   log_fd = level <= DTLS_LOG_CRIT ? stderr : stdout;
299 
300   if (print_timestamp(timebuf, sizeof(timebuf), time(NULL)))
301     fprintf(log_fd, "%s ", timebuf);
302 
303   if (level <= DTLS_LOG_DEBUG)
304     fprintf(log_fd, "%s ", loglevels[level]);
305 
306   if (extend) {
307     fprintf(log_fd, "%s: (%zu bytes):\n", name, length);
308 
309     while (length--) {
310       if (n % 16 == 0)
311 	fprintf(log_fd, "%08X ", n);
312 
313       fprintf(log_fd, "%02X ", *buf++);
314 
315       n++;
316       if (n % 8 == 0) {
317 	if (n % 16 == 0)
318 	  fprintf(log_fd, "\n");
319 	else
320 	  fprintf(log_fd, " ");
321       }
322     }
323   } else {
324     fprintf(log_fd, "%s: (%zu bytes): ", name, length);
325     while (length--)
326       fprintf(log_fd, "%02X", *buf++);
327   }
328   fprintf(log_fd, "\n");
329 
330   fflush(log_fd);
331 }
332 #else /* WITH_CONTIKI */
333 void
dtls_dsrv_hexdump_log(log_t level,const char * name,const unsigned char * buf,size_t length,int extend)334 dtls_dsrv_hexdump_log(log_t level, const char *name, const unsigned char *buf, size_t length, int extend) {
335   static char timebuf[32];
336   int n = 0;
337 
338   if (maxlog < level)
339     return;
340 
341   if (print_timestamp(timebuf,sizeof(timebuf), clock_time()))
342     PRINTF("%s ", timebuf);
343 
344   if (level >= 0 && level <= DTLS_LOG_DEBUG)
345     PRINTF("%s ", loglevels[level]);
346 
347   if (extend) {
348     PRINTF("%s: (%zu bytes):\n", name, length);
349 
350     while (length--) {
351       if (n % 16 == 0)
352 	PRINTF("%08X ", n);
353 
354       PRINTF("%02X ", *buf++);
355 
356       n++;
357       if (n % 8 == 0) {
358 	if (n % 16 == 0)
359 	  PRINTF("\n");
360 	else
361 	  PRINTF(" ");
362       }
363     }
364   } else {
365     PRINTF("%s: (%zu bytes): ", name, length);
366     while (length--)
367       PRINTF("%02X", *buf++);
368   }
369   PRINTF("\n");
370 }
371 #endif /* WITH_CONTIKI */
372 
373 #endif /* NDEBUG */
374