Version 0.5.0 of tinydtls
Dependents: tinydtls_test_cellular tinydtls_test_ethernet tiny-dtls
Diff: debug.c
- Revision:
- 0:ff9ebe0cf0e9
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debug.c Fri Oct 18 13:18:30 2013 +0000 @@ -0,0 +1,392 @@ +/* debug.c -- debug utilities + * + * Copyright (C) 2011--2012 Olaf Bergmann <bergmann@tzi.org> + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "config.h" + +#if defined(HAVE_ASSERT_H) && !defined(assert) +#include <assert.h> +#endif + +#include <stdarg.h> +#include <string.h> +#include <stdio.h> + +#ifdef HAVE_ARPA_INET_H +#include <arpa/inet.h> +#endif + +#ifdef HAVE_TIME_H +#include <time.h> +#endif + +#include "global.h" +#include "debug.h" + +#ifdef WITH_CONTIKI +# ifndef DEBUG +# define DEBUG DEBUG_PRINT +# endif /* DEBUG */ +#include "net/uip-debug.h" +#else +#define PRINTF(...) +#endif + +static int maxlog = LOG_WARN; /* default maximum log level */ + +log_t +dtls_get_log_level() { + return maxlog; +} + +void +dtls_set_log_level(log_t level) { + maxlog = level; +} + +/* this array has the same order as the type log_t */ +static char *loglevels[] = { + "EMRG", "ALRT", "CRIT", "WARN", "NOTE", "INFO", "DEBG" +}; + +#ifdef HAVE_TIME_H + +static inline size_t +print_timestamp(char *s, size_t len, time_t t) { + /* + struct tm *tmp; + tmp = localtime(&t); + return strftime(s, len, "%b %d %H:%M:%S", tmp); + */ + return 0; +} + +#else /* alternative implementation: just print the timestamp */ + +static inline size_t +print_timestamp(char *s, size_t len, clock_time_t t) { +#ifdef HAVE_SNPRINTF + return snprintf(s, len, "%u.%03u", + (unsigned int)(t / CLOCK_SECOND), + (unsigned int)(t % CLOCK_SECOND)); +#else /* HAVE_SNPRINTF */ + /* @todo do manual conversion of timestamp */ + return 0; +#endif /* HAVE_SNPRINTF */ +} + +#endif /* HAVE_TIME_H */ + +#ifndef HAVE_STRNLEN +/** + * A length-safe strlen() fake. + * + * @param s The string to count characters != 0. + * @param maxlen The maximum length of @p s. + * + * @return The length of @p s. + */ +static inline size_t +strnlen(const char *s, size_t maxlen) { + size_t n = 0; + while(*s++ && n < maxlen) + ++n; + return n; +} +#endif /* HAVE_STRNLEN */ + +#ifndef min +#define min(a,b) ((a) < (b) ? (a) : (b)) +#endif + +size_t +dsrv_print_addr(const session_t *addr, unsigned char *buf, size_t len) { + snprintf(buf,len,"%s:%d",inet_ntoa(addr->addr.sin.sin_addr),ntohs(addr->addr.sin.sin_port)); +} + +static size_t +dsrv_print_addr_unused(const session_t *addr, char *buf, size_t len) { +#ifdef HAVE_ARPA_INET_H + const void *addrptr = NULL; + in_port_t port; + char *p = buf; + + switch (addr->addr.sa.sa_family) { + case AF_INET: + if (len < INET_ADDRSTRLEN) + return 0; + + addrptr = &addr->addr.sin.sin_addr; + port = ntohs(addr->addr.sin.sin_port); + break; + case AF_INET6: + if (len < INET6_ADDRSTRLEN + 2) + return 0; + + *p++ = '['; + + addrptr = &addr->addr.sin6.sin6_addr; + port = ntohs(addr->addr.sin6.sin6_port); + + break; + default: + memcpy(buf, "(unknown address type)", min(22, len)); + return min(22, len); + } + + if (inet_ntop(addr->addr.sa.sa_family, addrptr, p, len) == 0) { + perror("dsrv_print_addr"); + return 0; + } + + p += strnlen(p, len); + + if (addr->addr.sa.sa_family == AF_INET6) { + if (p < buf + len) { + *p++ = ']'; + } else + return 0; + } + + p += snprintf(p, buf + len - p + 1, ":%d", port); + + return p - buf; +#else /* HAVE_ARPA_INET_H */ +# if WITH_CONTIKI + char *p = buf; + uint8_t i; +# if WITH_UIP6 + const char hex[] = "0123456789ABCDEF"; + + if (len < 41) + return 0; + + *p++ = '['; + + for (i=0; i < 8; i += 4) { + *p++ = hex[(addr->addr.u16[i] & 0xf000) >> 24]; + *p++ = hex[(addr->addr.u16[i] & 0x0f00) >> 16]; + *p++ = hex[(addr->addr.u16[i] & 0x00f0) >> 8]; + *p++ = hex[(addr->addr.u16[i] & 0x000f)]; + *p++ = ':'; + } + *(p-1) = ']'; +# else /* WITH_UIP6 */ +# warning "IPv4 network addresses will not be included in debug output" + + if (len < 21) + return 0; +# endif /* WITH_UIP6 */ + if (buf + len - p < 6) + return 0; + +#ifdef HAVE_SNPRINTF + p += snprintf(p, buf + len - p + 1, ":%d", uip_htons(addr->port)); +#else /* HAVE_SNPRINTF */ + /* @todo manual conversion of port number */ +#endif /* HAVE_SNPRINTF */ + + return p - buf; +# else /* WITH_CONTIKI */ + /* TODO: output addresses manually */ +# warning "inet_ntop() not available, network addresses will not be included in debug output" +# endif /* WITH_CONTIKI */ + return 0; +#endif +} + +#ifndef WITH_CONTIKI +void +dsrv_log(log_t level, char *format, ...) { + static char timebuf[32]; + va_list ap; + FILE *log_fd; + + if (maxlog < level) + return; + + log_fd = level <= LOG_CRIT ? stderr : stdout; + + if (print_timestamp(timebuf,sizeof(timebuf), time(NULL))) + fprintf(log_fd, "%s ", timebuf); + + if (level >= 0 && level <= LOG_DEBUG) + fprintf(log_fd, "%s ", loglevels[level]); + + va_start(ap, format); + vfprintf(log_fd, format, ap); + va_end(ap); + fflush(log_fd); +} +#else /* WITH_CONTIKI */ +void +dsrv_log(log_t level, char *format, ...) { + static char timebuf[32]; + va_list ap; + + if (maxlog < level) + return; +/* + if (print_timestamp(timebuf,sizeof(timebuf), clock_time())) + PRINTF("%s ", timebuf); +*/ + + if (level >= 0 && level <= LOG_DEBUG) + PRINTF("%s ", loglevels[level]); + + va_start(ap, format); +#ifdef HAVE_VPRINTF + vprintf(format, ap); +#else + PRINTF(format, ap); +#endif + va_end(ap); +} +#endif /* WITH_CONTIKI */ + +#ifndef NDEBUG +/** dumps packets in usual hexdump format */ +void hexdump(const unsigned char *packet, int length) { + int n = 0; + + while (length--) { + if (n % 16 == 0) + printf("%08X ",n); + + printf("%02X ", *packet++); + + n++; + if (n % 8 == 0) { + if (n % 16 == 0) + printf("\r\n"); + else + printf(" "); + } + } +} + +/** dump as narrow string of hex digits */ +void dump(unsigned char *buf, size_t len) { + while (len--) + printf("%02x", *buf++); +} + +void dtls_dsrv_log_addr(log_t level, const char *name, const session_t *addr) +{ + char addrbuf[73]; + int len; + + len = dsrv_print_addr(addr, addrbuf, sizeof(addrbuf)); + if (!len) + return; + printf("%s: %s\r\n", name, addrbuf); +} + +#ifndef WITH_CONTIKI +void +dtls_dsrv_hexdump_log(log_t level, const char *name, const unsigned char *buf, size_t length, int extend) { + static char timebuf[32]; + FILE *log_fd; + int n = 0; + + if (maxlog < level) + return; + + log_fd = level <= LOG_CRIT ? stderr : stdout; +/* + if (print_timestamp(timebuf, sizeof(timebuf), time(NULL))) + fprintf(log_fd, "%s ", timebuf); +*/ + + if (level >= 0 && level <= LOG_DEBUG) + fprintf(log_fd, "%s ", loglevels[level]); + + if (extend) { + fprintf(log_fd, "%s: (%zu bytes):\r\n", name, length); + + while (length--) { + if (n % 16 == 0) + fprintf(log_fd, "%08X ", n); + + fprintf(log_fd, "%02X ", *buf++); + + n++; + if (n % 8 == 0) { + if (n % 16 == 0) + fprintf(log_fd, "\r\n"); + else + fprintf(log_fd, " "); + } + } + } else { + fprintf(log_fd, "%s: (%zu bytes): ", name, length); + while (length--) + fprintf(log_fd, "%02X", *buf++); + } + fprintf(log_fd, "\r\n"); + + fflush(log_fd); +} +#else /* WITH_CONTIKI */ +void +dtls_dsrv_hexdump_log(log_t level, const char *name, const unsigned char *buf, size_t length, int extend) { + static char timebuf[32]; + int n = 0; + + if (maxlog < level) + return; +/* + if (print_timestamp(timebuf,sizeof(timebuf), clock_time())) + PRINTF("%s ", timebuf); +*/ + if (level >= 0 && level <= LOG_DEBUG) + PRINTF("%s ", loglevels[level]); + + if (extend) { + PRINTF("%s: (%zu bytes):\r\n", name, length); + + while (length--) { + if (n % 16 == 0) + PRINTF("%08X ", n); + + PRINTF("%02X ", *buf++); + + n++; + if (n % 8 == 0) { + if (n % 16 == 0) + PRINTF("\r\n"); + else + PRINTF(" "); + } + } + } else { + PRINTF("%s: (%zu bytes): ", name, length); + while (length--) + PRINTF("%02X", *buf++); + } + PRINTF("\r\n"); +} +#endif /* WITH_CONTIKI */ + +#endif /* NDEBUG */