[tor-commits] [obfsproxy/master] Logging subsystem code.

nickm at torproject.org nickm at torproject.org
Fri Jun 10 19:43:17 UTC 2011


commit 792954eb8ebc389f44c1e651c67e1dee738ba4ae
Author: George Kadianakis <desnacked at 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





More information about the tor-commits mailing list