commit 792954eb8ebc389f44c1e651c67e1dee738ba4ae Author: George Kadianakis desnacked@gmail.com Date: Thu Jun 9 23:23:57 2011 +0200
Logging subsystem code. --- src/util.c | 288 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- src/util.h | 66 ++++++++++++-- 2 files changed, 342 insertions(+), 12 deletions(-)
diff --git a/src/util.c b/src/util.c index baebe10..6ff337f 100644 --- a/src/util.c +++ b/src/util.c @@ -9,9 +9,27 @@ #include <stdio.h> #include <stdlib.h>
+#include <assert.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> + +#include "util.h" + #include <event2/util.h> #include <event2/dns.h>
+static const char *sev_to_string(int severity); +static int sev_is_valid(int severity); +static int write_logfile_prologue(int fd); +static int compose_logfile_prologue(char *buf, size_t buflen); +static int string_to_sev(char *string); +static int open_and_set_obfsproxy_logfile(char *filename); + + +/************************ Obfsproxy Network Routines *************************/ + int resolve_address_port(const char *address, int nodns, int passive, @@ -33,7 +51,7 @@ resolve_address_port(const char *address, } else if (default_port) { portstr = default_port; } else { - fprintf(stderr, "Error in address %s: port required.\n", address); + log_debug("Error in address %s: port required.", address); goto done; }
@@ -47,16 +65,16 @@ resolve_address_port(const char *address, ai_hints.ai_flags |= EVUTIL_AI_NUMERICHOST;
if ((ai_res = evutil_getaddrinfo(a, portstr, &ai_hints, &ai))) { - fprintf(stderr, "Error resolving %s (%s) (%s): %s\n", - address, a, portstr, evutil_gai_strerror(ai_res)); + log_warn("Error resolving %s (%s) (%s): %s", + address, a, portstr, evutil_gai_strerror(ai_res)); goto done; } if (ai == NULL) { - fprintf(stderr, "No result for address %s\n", address); + log_warn("No result for address %s", address); goto done; } if (ai->ai_addrlen > sizeof(struct sockaddr_storage)) { - fprintf(stderr, "Result for address %s too long\n", address); + log_warn("Result for address %s too long", address); goto done; }
@@ -85,3 +103,263 @@ init_evdns_base(struct event_base *base) the_evdns_base = evdns_base_new(base, 1); return the_evdns_base == NULL ? -1 : 0; } + +/************************ String Functions *************************/ +/** The functions in this section were carbon copied off tor. Thank you tor! */ + +/** Replacement for snprintf. Differs from platform snprintf in two + * ways: First, always NUL-terminates its output. Second, always + * returns -1 if the result is truncated. (Note that this return + * behavior does <i>not</i> conform to C99; it just happens to be + * easier to emulate "return -1" with conformant implementations than + * it is to emulate "return number that would be written" with + * non-conformant implementations.) */ +int +obfs_snprintf(char *str, size_t size, const char *format, ...) +{ + va_list ap; + int r; + va_start(ap,format); + r = obfs_vsnprintf(str,size,format,ap); + va_end(ap); + return r; +} + +/** Replacement for vsnprintf; behavior differs as obfs_snprintf differs from + * snprintf. + */ +int +obfs_vsnprintf(char *str, size_t size, const char *format, va_list args) +{ + int r; + if (size == 0) + return -1; /* no place for the NUL */ + if (size > SIZE_T_CEILING) + return -1; +#ifdef MS_WINDOWS + r = _vsnprintf(str, size, format, args); +#else + r = vsnprintf(str, size, format, args); +#endif + str[size-1] = '\0'; + if (r < 0 || r >= (ssize_t)size) + return -1; + return r; +} + +/************************ Logging Subsystem *************************/ +/** The code of this section was to a great extend shamelessly copied + off tor. It's basicaly a stripped down version of tor's logging + system. Thank you tor. */ + +/* Size of maximum log entry, including newline and NULL byte. */ +#define MAX_LOG_ENTRY 1024 +/* String to append when a log entry doesn't fit in MAX_LOG_ENTRY. */ +#define TRUNCATED_STR "[...truncated]" +/* strlen(TRUNCATED_STR) */ +#define TRUNCATED_STR_LEN 14 + +/* logging method */ +static int logging_method=LOG_METHOD_STDOUT; +/* minimum logging severity */ +static int logging_min_sev=LOG_SEV_INFO; +/* logfile fd */ +static int logging_logfile=-1; + +/** Helper: map a log severity to descriptive string. */ +static const char * +sev_to_string(int severity) +{ + switch (severity) { + case LOG_SEV_WARN: return "warn"; + case LOG_SEV_INFO: return "info"; + case LOG_SEV_DEBUG: return "debug"; + default: + assert(0); return "UNKNOWN"; + } +} + +/** If 'string' is a valid log severity, return the corresponding + * numeric value. Otherwise, return -1. */ +static int +string_to_sev(char *string) +{ + if (!strcasecmp(string, "warn")) + return LOG_SEV_WARN; + else if (!strcasecmp(string, "info")) + return LOG_SEV_INFO; + else if (!strcasecmp(string, "debug")) + return LOG_SEV_DEBUG; + else + return -1; +} + +/** + Returns True if 'severity' is a valid obfsproxy logging severity. + Otherwise, it returns False. +*/ +static int +sev_is_valid(int severity) +{ + return (severity == LOG_SEV_WARN || + severity == LOG_SEV_INFO || + severity == LOG_SEV_DEBUG); +} + +/** + Sets the global logging 'method' and also sets and open the logfile + 'filename' in case we want to log into a file. + It returns 1 on success and -1 on fail. +*/ +int +log_set_method(int method, char *filename) +{ + + logging_method = method; + if (method == LOG_METHOD_FILE) { + if (open_and_set_obfsproxy_logfile(filename) < 0) + return -1; + if (write_logfile_prologue(logging_logfile) < 0) + return -1; + } + return 1; +} + +/** + Helper: Opens 'filename' and sets it as the obfsproxy logfile. + On success it returns 1, on fail it returns -1. +*/ +static int +open_and_set_obfsproxy_logfile(char *filename) +{ + if (!filename) + return -1; + logging_logfile = open(filename, + O_WRONLY|O_CREAT|O_APPEND, + 0644); + if (logging_logfile < 0) + return -1; + return 1; +} + +/** + Closes the obfsproxy logfile if it exists. + Returns 0 on success or if we weren't using a logfile (that's + close()'s success return value) and -1 on failure. +*/ +int +close_obfsproxy_logfile(void) +{ + if (logging_logfile < 0) /* no logfile. */ + return 0; + else + return close(logging_logfile); +} + +/** + Writes a small prologue in the logfile 'fd' that mentions the + obfsproxy version and helps separate log instances. +*/ +static int +write_logfile_prologue(int logfile) { + char buf[256]; + if (compose_logfile_prologue(buf, sizeof(buf)) < 0) + return -1; + if (write(logfile, buf, strlen(buf)) < 0) + return -1; + return 1; +} + +#define TEMP_PROLOGUE "\nBrand new obfsproxy log:\n" +/** + Helper: Composes the logfile prologue. +*/ +static int +compose_logfile_prologue(char *buf, size_t buflen) +{ + if (obfs_snprintf(buf, buflen, TEMP_PROLOGUE) < 0) { + log_warn("Logfile prologue couldn't be written."); + return -1; + } + return 1; +} +#undef TEMP_PROLOGUE + +/** + Sets the minimum logging severity of obfsproxy to the severity + described by 'sev_string', then it returns 1. If 'sev_string' is + not a valid severity, it returns -1. +*/ +int +log_set_min_severity(char* sev_string) { + int severity = string_to_sev(sev_string); + if (!sev_is_valid(severity)) { + log_warn("Severity '%s' makes no sense.", sev_string); + return -1; + } + logging_min_sev = severity; + return 1; +} + +/** + Logging function of obfsproxy. + Don't call this directly; use the log_* macros defined in util.h + instead. + + It accepts a logging 'severity' and a 'format' string and logs the + message in 'format' according to the configured obfsproxy minimum + logging severity and logging method. +*/ +void +log_fn(int severity, const char *format, ...) +{ + assert(sev_is_valid(severity)); + + if (logging_method == LOG_METHOD_NULL) + return; + + /* See if the user is interested in this log message. */ + if (severity < logging_min_sev) + return; + + size_t n=0; + int r=0; + char buf[MAX_LOG_ENTRY]; + + size_t buflen = MAX_LOG_ENTRY-2; + + va_list ap; + va_start(ap,format); + + r = obfs_snprintf(buf, buflen, "[%s] ", sev_to_string(severity)); + if (r < 0) + n = strlen(buf); + else + n=r; + + r = obfs_vsnprintf(buf+n, buflen-n, format, ap); + if (r < 0) { + if (buflen >= TRUNCATED_STR_LEN) { + size_t offset = buflen-TRUNCATED_STR_LEN; + r = obfs_snprintf(buf+offset, TRUNCATED_STR_LEN+1, + "%s", TRUNCATED_STR); + if (r < 0) assert(0); + } + n = buflen; + } else + n+=r; + + buf[n]='\n'; + buf[n+1]='\0'; + + va_end(ap); + + if (logging_method == LOG_METHOD_STDOUT) + fprintf(stdout, "%s", buf); + else if (logging_method == LOG_METHOD_FILE) { + assert(logging_logfile); + if (write(logging_logfile, buf, strlen(buf)) < 0) + printf("%s(): Terrible write() error!!!\n", __func__); + } else + assert(0); +} diff --git a/src/util.h b/src/util.h index 69bd768..a48f7d8 100644 --- a/src/util.h +++ b/src/util.h @@ -5,10 +5,17 @@ in all redistributed copies and derived works. There is no warranty. */
+/* va_list definition */ +#include <stdarg.h> + #ifndef UTIL_H #define UTIL_H
struct sockaddr_storage; +struct event_base; +struct evdns_base; + +/***** Network functions stuff. *****/
int resolve_address_port(const char *address, int nodns, int passive, @@ -16,16 +23,61 @@ int resolve_address_port(const char *address, int *addrlen_out, const char *default_port);
-#ifdef DEBUG -#define dbg(x) printf x +struct evdns_base *get_evdns_base(void); +int init_evdns_base(struct event_base *base); + +/***** String functions stuff. *****/ + +/* The sizeof a size_t, as computed by sizeof. */ +#ifndef SIZEOF_SIZE_T +#define SIZEOF_SIZE_T 4 +#endif +#ifndef SSIZE_T_MAX +#if (SIZEOF_SIZE_T == 4) +#define SSIZE_T_MAX INT32_MAX +#elif (SIZEOF_SIZE_T == 8) +#define SSIZE_T_MAX INT64_MAX #else -#define dbg(x) ((void)0) +#error "Can't define SSIZE_T_MAX" +#endif #endif +/** Any size_t larger than this amount is likely to be an underflow. */ +#define SIZE_T_CEILING ((size_t)(SSIZE_T_MAX-16))
-struct event_base; -struct evdns_base; -struct evdns_base *get_evdns_base(void); -int init_evdns_base(struct event_base *base); +int obfs_vsnprintf(char *str, size_t size, + const char *format, va_list args); +int obfs_snprintf(char *str, size_t size, + const char *format, ...); + +/***** Logging subsystem stuff. *****/ + +void log_fn(int severity, const char *format, ...); +int log_set_method(int method, char *filename); +int log_set_min_severity(char* sev_string); +int close_obfsproxy_logfile(void); + +#define log_info(args...) log_fn(LOG_SEV_INFO, args) +#define log_warn(args...) log_fn(LOG_SEV_WARN, args) +#define log_debug(args...) log_fn(LOG_SEV_DEBUG, args) + +/** Logging methods */ + +/** Spit log messages on stdout. */ +#define LOG_METHOD_STDOUT 1 +/** Place log messages in a file. */ +#define LOG_METHOD_FILE 2 +/** We don't want no logs. */ +#define LOG_METHOD_NULL 3 + +/** Logging severities */
+/** Warn-level severity: for messages that only appear when something has gone wrong. */ +#define LOG_SEV_WARN 3 +/** Info-level severity: for messages that should be sent to the user + during normal operation. */ +#define LOG_SEV_INFO 2 +/** Debug-level severity: for hyper-verbose messages of no interest to + anybody but developers. */ +#define LOG_SEV_DEBUG 1
#endif
tor-commits@lists.torproject.org