expand GNUNET_OS_ProjectData API to also enable de-duplcation of logic for --help
[oweals/gnunet.git] / src / util / common_logging.c
index 82878a02abd90e2c270b27595845d0fd6280fb76..0cefa194d128bebe8311614e53f0e14f4061f124 100644 (file)
@@ -1,10 +1,10 @@
 /*
      This file is part of GNUnet.
 /*
      This file is part of GNUnet.
-     (C) 2006, 2008, 2009 Christian Grothoff (and other contributing authors)
+     Copyright (C) 2006-2013 GNUnet e.V.
 
      GNUnet is free software; you can redistribute it and/or modify
      it under the terms of the GNU General Public License as published
 
      GNUnet is free software; you can redistribute it and/or modify
      it under the terms of the GNU General Public License as published
-     by the Free Software Foundation; either version 2, or (at your
+     by the Free Software Foundation; either version 3, or (at your
      option) any later version.
 
      GNUnet is distributed in the hope that it will be useful, but
      option) any later version.
 
      GNUnet is distributed in the hope that it will be useful, but
 
      You should have received a copy of the GNU General Public License
      along with GNUnet; see the file COPYING.  If not, write to the
 
      You should have received a copy of the GNU General Public License
      along with GNUnet; see the file COPYING.  If not, write to the
-     Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-     Boston, MA 02111-1307, USA.
+     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+     Boston, MA 02110-1301, USA.
 */
 
 /**
  * @file util/common_logging.c
  * @brief error handling API
 */
 
 /**
  * @file util/common_logging.c
  * @brief error handling API
- *
  * @author Christian Grothoff
  */
 #include "platform.h"
  * @author Christian Grothoff
  */
 #include "platform.h"
-#include "gnunet_common.h"
 #include "gnunet_crypto_lib.h"
 #include "gnunet_strings_lib.h"
 #include "gnunet_crypto_lib.h"
 #include "gnunet_strings_lib.h"
-#include "gnunet_time_lib.h"
-
 #include <regex.h>
 
 #include <regex.h>
 
+
 /**
  * After how many milliseconds do we always print
  * that "message X was repeated N times"?  Use 12h.
  */
 /**
  * After how many milliseconds do we always print
  * that "message X was repeated N times"?  Use 12h.
  */
-#define BULK_DELAY_THRESHOLD (12 * 60 * 60 * 1000)
+#define BULK_DELAY_THRESHOLD (12 * 60 * 60 * 1000LL * 1000LL)
 
 /**
  * After how many repetitions do we always print
 
 /**
  * After how many repetitions do we always print
  */
 #define DATE_STR_SIZE 64
 
  */
 #define DATE_STR_SIZE 64
 
+/**
+ * How many log files to keep?
+ */
+#define ROTATION_KEEP 3
+
+#ifndef PATH_MAX
+/**
+ * Assumed maximum path length (for the log file name).
+ */
+#define PATH_MAX 4096
+#endif
+
+
 /**
  * Linked list of active loggers.
  */
 /**
  * Linked list of active loggers.
  */
@@ -121,6 +131,11 @@ static char *component;
  */
 static char *component_nopid;
 
  */
 static char *component_nopid;
 
+/**
+ * Format string describing the name of the log file.
+ */
+static char *log_file_name;
+
 /**
  * Minimum log level.
  */
 /**
  * Minimum log level.
  */
@@ -134,7 +149,7 @@ static struct CustomLogger *loggers;
 /**
  * Number of log calls to ignore.
  */
 /**
  * Number of log calls to ignore.
  */
-unsigned int skip_log;
+static int skip_log = 0;
 
 /**
  * File descriptor to use for "stderr", or NULL for none.
 
 /**
  * File descriptor to use for "stderr", or NULL for none.
@@ -190,40 +205,41 @@ struct LogDef
 /**
  * Dynamic array of logging definitions
  */
 /**
  * Dynamic array of logging definitions
  */
-struct LogDef *logdefs = NULL;
+static struct LogDef *logdefs;
 
 /**
  * Allocated size of logdefs array (in units)
  */
 
 /**
  * Allocated size of logdefs array (in units)
  */
-int logdefs_size = 0;
+static int logdefs_size;
 
 /**
  * The number of units used in logdefs array.
  */
 
 /**
  * The number of units used in logdefs array.
  */
-int logdefs_len = 0;
+static int logdefs_len;
 
 /**
  * GNUNET_YES if GNUNET_LOG environment variable is already parsed.
  */
 
 /**
  * GNUNET_YES if GNUNET_LOG environment variable is already parsed.
  */
-int gnunet_log_parsed = GNUNET_NO;
+static int gnunet_log_parsed;
 
 /**
  * GNUNET_YES if GNUNET_FORCE_LOG environment variable is already parsed.
  */
 
 /**
  * GNUNET_YES if GNUNET_FORCE_LOG environment variable is already parsed.
  */
-int gnunet_force_log_parsed = GNUNET_NO;
+static int gnunet_force_log_parsed;
 
 /**
  * GNUNET_YES if at least one definition with forced == 1 is available.
  */
 
 /**
  * GNUNET_YES if at least one definition with forced == 1 is available.
  */
-int gnunet_force_log_present = GNUNET_NO;
+static int gnunet_force_log_present;
 
 #ifdef WINDOWS
 /**
  * Contains the number of performance counts per second.
  */
 
 #ifdef WINDOWS
 /**
  * Contains the number of performance counts per second.
  */
-LARGE_INTEGER performance_frequency;
+static LARGE_INTEGER performance_frequency;
 #endif
 
 #endif
 
+
 /**
  * Convert a textual description of a loglevel
  * to the respective GNUNET_GE_KIND.
 /**
  * Convert a textual description of a loglevel
  * to the respective GNUNET_GE_KIND.
@@ -234,7 +250,7 @@ LARGE_INTEGER performance_frequency;
 static enum GNUNET_ErrorType
 get_type (const char *log)
 {
 static enum GNUNET_ErrorType
 get_type (const char *log)
 {
-  if (log == NULL)
+  if (NULL == log)
     return GNUNET_ERROR_TYPE_UNSPECIFIED;
   if (0 == strcasecmp (log, _("DEBUG")))
     return GNUNET_ERROR_TYPE_DEBUG;
     return GNUNET_ERROR_TYPE_UNSPECIFIED;
   if (0 == strcasecmp (log, _("DEBUG")))
     return GNUNET_ERROR_TYPE_DEBUG;
@@ -249,6 +265,7 @@ get_type (const char *log)
   return GNUNET_ERROR_TYPE_INVALID;
 }
 
   return GNUNET_ERROR_TYPE_INVALID;
 }
 
+
 #if !defined(GNUNET_CULL_LOGGING)
 /**
  * Utility function - reallocates logdefs array to be twice as large.
 #if !defined(GNUNET_CULL_LOGGING)
 /**
  * Utility function - reallocates logdefs array to be twice as large.
@@ -265,7 +282,7 @@ resize_logdefs ()
  * Abort the process, generate a core dump if possible.
  */
 void
  * Abort the process, generate a core dump if possible.
  */
 void
-GNUNET_abort ()
+GNUNET_abort_ ()
 {
 #if WINDOWS
   DebugBreak ();
 {
 #if WINDOWS
   DebugBreak ();
@@ -274,6 +291,112 @@ GNUNET_abort ()
 }
 
 
 }
 
 
+/**
+ * Rotate logs, deleting the oldest log.
+ *
+ * @param new_name new name to add to the rotation
+ */
+static void
+log_rotate (const char *new_name)
+{
+  static char *rotation[ROTATION_KEEP];
+  static unsigned int rotation_off;
+  char *discard;
+
+  if ('\0' == *new_name)
+    return; /* not a real log file name */
+  discard = rotation[rotation_off % ROTATION_KEEP];
+  if (NULL != discard)
+  {
+    /* Note: can't log errors during logging (recursion!), so this
+       operation MUST silently fail... */
+    (void) UNLINK (discard);
+    GNUNET_free (discard);
+  }
+  rotation[rotation_off % ROTATION_KEEP] = GNUNET_strdup (new_name);
+  rotation_off++;
+}
+
+
+/**
+ * Setup the log file.
+ *
+ * @param tm timestamp for which we should setup logging
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
+ */
+static int
+setup_log_file (const struct tm *tm)
+{
+  static char last_fn[PATH_MAX + 1];
+  char fn[PATH_MAX + 1];
+  int altlog_fd;
+  int dup_return;
+  FILE *altlog;
+  char *leftsquare;
+
+  if (NULL == log_file_name)
+    return GNUNET_SYSERR;
+  if (0 == strftime (fn, sizeof (fn), log_file_name, tm))
+    return GNUNET_SYSERR;
+  leftsquare = strrchr (fn, '[');
+  if ( (NULL != leftsquare) && (']' == leftsquare[1]) )
+  {
+    char *logfile_copy = GNUNET_strdup (fn);
+
+    logfile_copy[leftsquare - fn] = '\0';
+    logfile_copy[leftsquare - fn + 1] = '\0';
+    snprintf (fn,
+              PATH_MAX,
+              "%s%d%s",
+              logfile_copy,
+              getpid (),
+              &logfile_copy[leftsquare - fn + 2]);
+    GNUNET_free (logfile_copy);
+  }
+  if (0 == strcmp (fn, last_fn))
+    return GNUNET_OK; /* no change */
+  log_rotate (last_fn);
+  strcpy (last_fn, fn);
+#if WINDOWS
+  altlog_fd = OPEN (fn, O_APPEND |
+                        O_BINARY |
+                        O_WRONLY | O_CREAT,
+                        _S_IREAD | _S_IWRITE);
+#else
+  altlog_fd = OPEN (fn, O_APPEND |
+                        O_WRONLY | O_CREAT,
+                        S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+#endif
+  if (-1 != altlog_fd)
+  {
+    if (NULL != GNUNET_stderr)
+      fclose (GNUNET_stderr);
+    dup_return = dup2 (altlog_fd, 2);
+    (void) close (altlog_fd);
+    if (-1 != dup_return)
+    {
+      altlog = fdopen (2, "ab");
+      if (NULL == altlog)
+      {
+        (void) close (2);
+        altlog_fd = -1;
+      }
+    }
+    else
+    {
+      altlog_fd = -1;
+    }
+  }
+  if (-1 == altlog_fd)
+  {
+    GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "open", fn);
+    return GNUNET_SYSERR;
+  }
+  GNUNET_stderr = altlog;
+  return GNUNET_OK;
+}
+
+
 /**
  * Utility function - adds a parsed definition to logdefs array.
  *
 /**
  * Utility function - adds a parsed definition to logdefs array.
  *
@@ -287,8 +410,13 @@ GNUNET_abort ()
  * @return 0 on success, regex-specific error otherwise
  */
 static int
  * @return 0 on success, regex-specific error otherwise
  */
 static int
-add_definition (char *component, char *file, char *function, int from_line,
-                int to_line, int level, int force)
+add_definition (const char *component,
+                const char *file,
+                const char *function,
+                int from_line,
+                int to_line,
+                int level,
+                int force)
 {
   struct LogDef n;
   int r;
 {
   struct LogDef n;
   int r;
@@ -296,25 +424,25 @@ add_definition (char *component, char *file, char *function, int from_line,
   if (logdefs_size == logdefs_len)
     resize_logdefs ();
   memset (&n, 0, sizeof (n));
   if (logdefs_size == logdefs_len)
     resize_logdefs ();
   memset (&n, 0, sizeof (n));
-  if (strlen (component) == 0)
+  if (0 == strlen (component))
     component = (char *) ".*";
   r = regcomp (&n.component_regex, (const char *) component, REG_NOSUB);
     component = (char *) ".*";
   r = regcomp (&n.component_regex, (const char *) component, REG_NOSUB);
-  if (r != 0)
+  if (0 != r)
   {
     return r;
   }
   {
     return r;
   }
-  if (strlen (file) == 0)
+  if (0 == strlen (file))
     file = (char *) ".*";
   r = regcomp (&n.file_regex, (const char *) file, REG_NOSUB);
     file = (char *) ".*";
   r = regcomp (&n.file_regex, (const char *) file, REG_NOSUB);
-  if (r != 0)
+  if (0 != r)
   {
     regfree (&n.component_regex);
     return r;
   }
   {
     regfree (&n.component_regex);
     return r;
   }
-  if ((NULL == function) || (strlen (function) == 0))
+  if ((NULL == function) || (0 == strlen (function)))
     function = (char *) ".*";
   r = regcomp (&n.function_regex, (const char *) function, REG_NOSUB);
     function = (char *) ".*";
   r = regcomp (&n.function_regex, (const char *) function, REG_NOSUB);
-  if (r != 0)
+  if (0 != r)
   {
     regfree (&n.component_regex);
     regfree (&n.file_regex);
   {
     regfree (&n.component_regex);
     regfree (&n.file_regex);
@@ -343,21 +471,24 @@ add_definition (char *component, char *file, char *function, int from_line,
  * @return 0 to disallow the call, 1 to allow it
  */
 int
  * @return 0 to disallow the call, 1 to allow it
  */
 int
-GNUNET_get_log_call_status (int caller_level, const char *comp,
-                            const char *file, const char *function, int line)
+GNUNET_get_log_call_status (int caller_level,
+                            const char *comp,
+                            const char *file,
+                            const char *function,
+                            int line)
 {
   struct LogDef *ld;
   int i;
   int force_only;
 
 {
   struct LogDef *ld;
   int i;
   int force_only;
 
-  if (comp == NULL)
+  if (NULL == comp)
     /* Use default component */
     comp = component_nopid;
 
   /* We have no definitions to override globally configured log level,
    * so just use it right away.
    */
     /* Use default component */
     comp = component_nopid;
 
   /* We have no definitions to override globally configured log level,
    * so just use it right away.
    */
-  if (min_level >= 0 && gnunet_force_log_present == GNUNET_NO)
+  if ( (min_level >= 0) && (GNUNET_NO == gnunet_force_log_present) )
     return caller_level <= min_level;
 
   /* Only look for forced definitions? */
     return caller_level <= min_level;
 
   /* Only look for forced definitions? */
@@ -365,11 +496,11 @@ GNUNET_get_log_call_status (int caller_level, const char *comp,
   for (i = 0; i < logdefs_len; i++)
   {
     ld = &logdefs[i];
   for (i = 0; i < logdefs_len; i++)
   {
     ld = &logdefs[i];
-    if ((!force_only || ld->force) &&
+    if (( (!force_only) || ld->force) &&
         (line >= ld->from_line && line <= ld->to_line) &&
         (line >= ld->from_line && line <= ld->to_line) &&
-        (regexec (&ld->component_regex, comp, 0, NULL, 0) == 0) &&
-        (regexec (&ld->file_regex, file, 0, NULL, 0) == 0) &&
-        (regexec (&ld->function_regex, function, 0, NULL, 0) == 0))
+        (0 == regexec (&ld->component_regex, comp, 0, NULL, 0)) &&
+        (0 == regexec (&ld->file_regex, file, 0, NULL, 0)) &&
+        (0 == regexec (&ld->function_regex, function, 0, NULL, 0)))
     {
       /* We're finished */
       return caller_level <= ld->level;
     {
       /* We're finished */
       return caller_level <= ld->level;
@@ -426,7 +557,7 @@ parse_definitions (const char *constname, int force)
   int keep_looking = 1;
 
   tmp = getenv (constname);
   int keep_looking = 1;
 
   tmp = getenv (constname);
-  if (tmp == NULL)
+  if (NULL == tmp)
     return 0;
   def = GNUNET_strdup (tmp);
   from_line = 0;
     return 0;
   def = GNUNET_strdup (tmp);
   from_line = 0;
@@ -454,17 +585,17 @@ parse_definitions (const char *constname, int force)
         {
           errno = 0;
           from_line = strtol (start, &t, 10);
         {
           errno = 0;
           from_line = strtol (start, &t, 10);
-          if (errno != 0 || from_line < 0)
+          if ( (0 != errno) || (from_line < 0) )
           {
             GNUNET_free (def);
             return counter;
           }
           {
             GNUNET_free (def);
             return counter;
           }
-          if (t < p && t[0] == '-')
+          if ( (t < p) && ('-' == t[0]) )
           {
             errno = 0;
             start = t + 1;
             to_line = strtol (start, &t, 10);
           {
             errno = 0;
             start = t + 1;
             to_line = strtol (start, &t, 10);
-            if (errno != 0 || to_line < 0 || t != p)
+            if ( (0 != errno) || (to_line < 0) || (t != p) )
             {
               GNUNET_free (def);
               return counter;
             {
               GNUNET_free (def);
               return counter;
@@ -481,7 +612,7 @@ parse_definitions (const char *constname, int force)
         break;
       }
       start = p + 1;
         break;
       }
       start = p + 1;
-      state += 1;
+      state++;
       break;
     case '\0':                 /* found EOL */
       keep_looking = 0;
       break;
     case '\0':                 /* found EOL */
       keep_looking = 0;
@@ -493,15 +624,15 @@ parse_definitions (const char *constname, int force)
         p[0] = '\0';
         state = 0;
         level = get_type ((const char *) start);
         p[0] = '\0';
         state = 0;
         level = get_type ((const char *) start);
-        if (level == GNUNET_ERROR_TYPE_INVALID ||
-            level == GNUNET_ERROR_TYPE_UNSPECIFIED ||
-            0 != add_definition (comp, file, function, from_line, to_line,
-                                 level, force))
+        if ( (GNUNET_ERROR_TYPE_INVALID == level) ||
+            (GNUNET_ERROR_TYPE_UNSPECIFIED == level) ||
+            (0 != add_definition (comp, file, function, from_line, to_line,
+                                  level, force)) )
         {
           GNUNET_free (def);
           return counter;
         }
         {
           GNUNET_free (def);
           return counter;
         }
-        counter += 1;
+        counter++;
         start = p + 1;
         break;
       default:
         start = p + 1;
         break;
       default:
@@ -515,16 +646,17 @@ parse_definitions (const char *constname, int force)
   return counter;
 }
 
   return counter;
 }
 
+
 /**
  * Utility function - parses GNUNET_LOG and GNUNET_FORCE_LOG.
  */
 static void
 parse_all_definitions ()
 {
 /**
  * Utility function - parses GNUNET_LOG and GNUNET_FORCE_LOG.
  */
 static void
 parse_all_definitions ()
 {
-  if (gnunet_log_parsed == GNUNET_NO)
+  if (GNUNET_NO == gnunet_log_parsed)
     parse_definitions ("GNUNET_LOG", 0);
   gnunet_log_parsed = GNUNET_YES;
     parse_definitions ("GNUNET_LOG", 0);
   gnunet_log_parsed = GNUNET_YES;
-  if (gnunet_force_log_parsed == GNUNET_NO)
+  if (GNUNET_NO == gnunet_force_log_parsed)
     gnunet_force_log_present =
         parse_definitions ("GNUNET_FORCE_LOG", 1) > 0 ? GNUNET_YES : GNUNET_NO;
   gnunet_force_log_parsed = GNUNET_YES;
     gnunet_force_log_present =
         parse_definitions ("GNUNET_FORCE_LOG", 1) > 0 ? GNUNET_YES : GNUNET_NO;
   gnunet_force_log_parsed = GNUNET_YES;
@@ -538,16 +670,16 @@ parse_all_definitions ()
  * @param comp default component to use
  * @param loglevel what types of messages should be logged
  * @param logfile which file to write log messages to (can be NULL)
  * @param comp default component to use
  * @param loglevel what types of messages should be logged
  * @param logfile which file to write log messages to (can be NULL)
- * @return GNUNET_OK on success
+ * @return #GNUNET_OK on success
  */
 int
  */
 int
-GNUNET_log_setup (const char *comp, const char *loglevel, const char *logfile)
+GNUNET_log_setup (const char *comp,
+                 const char *loglevel,
+                 const char *logfile)
 {
 {
-  FILE *altlog;
-  int dirwarn;
-  char *fn;
-  const char *env_logfile = NULL;
-  int altlog_fd;
+  const char *env_logfile;
+  const struct tm *tm;
+  time_t t;
 
   min_level = get_type (loglevel);
 #if !defined(GNUNET_CULL_LOGGING)
 
   min_level = get_type (loglevel);
 #if !defined(GNUNET_CULL_LOGGING)
@@ -562,107 +694,76 @@ GNUNET_log_setup (const char *comp, const char *loglevel, const char *logfile)
   component_nopid = GNUNET_strdup (comp);
 
   env_logfile = getenv ("GNUNET_FORCE_LOGFILE");
   component_nopid = GNUNET_strdup (comp);
 
   env_logfile = getenv ("GNUNET_FORCE_LOGFILE");
-  if ((env_logfile != NULL) && (strlen (env_logfile) > 0))
+  if ((NULL != env_logfile) && (strlen (env_logfile) > 0))
     logfile = env_logfile;
     logfile = env_logfile;
-
-  if (logfile == NULL)
+  if (NULL == logfile)
     return GNUNET_OK;
     return GNUNET_OK;
-  fn = GNUNET_STRINGS_filename_expand (logfile);
-  if (NULL == fn)
-    return GNUNET_SYSERR;
-  dirwarn = (GNUNET_OK != GNUNET_DISK_directory_create_for_file (fn));
-#if WINDOWS
-  altlog_fd = OPEN (fn, O_APPEND |
-                        O_BINARY |
-                        O_WRONLY | O_CREAT,
-                        _S_IREAD | _S_IWRITE);
-#else
-  altlog_fd = OPEN (fn, O_APPEND |
-                        O_WRONLY | O_CREAT,
-                        S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
-#endif
-  if (altlog_fd != -1)
-  {
-    int dup_return;
-    if (GNUNET_stderr != NULL)
-      fclose (GNUNET_stderr);
-    dup_return = dup2 (altlog_fd, 2);
-    (void) close (altlog_fd);
-    if (dup_return != -1)
-    {
-      altlog = fdopen (2, "ab");
-      if (altlog == NULL)
-      {
-        (void) close (2);
-        altlog_fd = -1;
-      }
-    }
-    else
-    {
-      altlog_fd = -1;
-    }
-  }
-  if (altlog_fd == -1)
-  {
-    GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "open", fn);
-    if (dirwarn)
-      GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
-                  _("Failed to create or access directory for log file `%s'\n"),
-                  fn);
-    GNUNET_free (fn);
+  GNUNET_free_non_null (log_file_name);
+  log_file_name = GNUNET_STRINGS_filename_expand (logfile);
+  if (NULL == log_file_name)
     return GNUNET_SYSERR;
     return GNUNET_SYSERR;
-  }
-  GNUNET_free (fn);
-  GNUNET_stderr = altlog;
-  return GNUNET_OK;
+  t = time (NULL);
+  tm = gmtime (&t);
+  return setup_log_file (tm);
 }
 
 }
 
+
 /**
 /**
- * Add a custom logger.
+ * Add a custom logger. Note that installing any custom logger
+ * will disable the standard logger.  When multiple custom loggers
+ * are installed, all will be called.  The standard logger will
+ * only be used if no custom loggers are present.
  *
  * @param logger log function
  *
  * @param logger log function
- * @param logger_cls closure for logger
+ * @param logger_cls closure for @a logger
  */
 void
  */
 void
-GNUNET_logger_add (GNUNET_Logger logger, void *logger_cls)
+GNUNET_logger_add (GNUNET_Logger logger,
+                   void *logger_cls)
 {
   struct CustomLogger *entry;
 
 {
   struct CustomLogger *entry;
 
-  entry = GNUNET_malloc (sizeof (struct CustomLogger));
+  entry = GNUNET_new (struct CustomLogger);
   entry->logger = logger;
   entry->logger_cls = logger_cls;
   entry->next = loggers;
   loggers = entry;
 }
 
   entry->logger = logger;
   entry->logger_cls = logger_cls;
   entry->next = loggers;
   loggers = entry;
 }
 
+
 /**
  * Remove a custom logger.
  *
  * @param logger log function
 /**
  * Remove a custom logger.
  *
  * @param logger log function
- * @param logger_cls closure for logger
+ * @param logger_cls closure for @a logger
  */
 void
  */
 void
-GNUNET_logger_remove (GNUNET_Logger logger, void *logger_cls)
+GNUNET_logger_remove (GNUNET_Logger logger,
+                      void *logger_cls)
 {
   struct CustomLogger *pos;
   struct CustomLogger *prev;
 
   prev = NULL;
   pos = loggers;
 {
   struct CustomLogger *pos;
   struct CustomLogger *prev;
 
   prev = NULL;
   pos = loggers;
-  while ((pos != NULL) &&
+  while ((NULL != pos) &&
          ((pos->logger != logger) || (pos->logger_cls != logger_cls)))
   {
     prev = pos;
     pos = pos->next;
   }
          ((pos->logger != logger) || (pos->logger_cls != logger_cls)))
   {
     prev = pos;
     pos = pos->next;
   }
-  GNUNET_assert (pos != NULL);
-  if (prev == NULL)
+  GNUNET_assert (NULL != pos);
+  if (NULL == prev)
     loggers = pos->next;
   else
     prev->next = pos->next;
   GNUNET_free (pos);
 }
 
     loggers = pos->next;
   else
     prev->next = pos->next;
   GNUNET_free (pos);
 }
 
+#if WINDOWS
+CRITICAL_SECTION output_message_cs;
+#endif
+
 
 /**
  * Actually output the log message.
 
 /**
  * Actually output the log message.
@@ -673,15 +774,26 @@ GNUNET_logger_remove (GNUNET_Logger logger, void *logger_cls)
  * @param msg the actual message
  */
 static void
  * @param msg the actual message
  */
 static void
-output_message (enum GNUNET_ErrorType kind, const char *comp,
-                const char *datestr, const char *msg)
+output_message (enum GNUNET_ErrorType kind,
+                const char *comp,
+                const char *datestr,
+                const char *msg)
 {
   struct CustomLogger *pos;
 
 {
   struct CustomLogger *pos;
 
-  if (GNUNET_stderr != NULL)
+#if WINDOWS
+  EnterCriticalSection (&output_message_cs);
+#endif
+  /* only use the standard logger if no custom loggers are present */
+  if ( (NULL != GNUNET_stderr) &&
+       (NULL == loggers) )
   {
   {
-    FPRINTF (GNUNET_stderr, "%s %s %s %s", datestr, comp,
-             GNUNET_error_type_to_string (kind), msg);
+    FPRINTF (GNUNET_stderr,
+             "%s %s %s %s",
+             datestr,
+             comp,
+             GNUNET_error_type_to_string (kind),
+             msg);
     fflush (GNUNET_stderr);
   }
   pos = loggers;
     fflush (GNUNET_stderr);
   }
   pos = loggers;
@@ -690,6 +802,9 @@ output_message (enum GNUNET_ErrorType kind, const char *comp,
     pos->logger (pos->logger_cls, kind, comp, datestr, msg);
     pos = pos->next;
   }
     pos->logger (pos->logger_cls, kind, comp, datestr, msg);
     pos = pos->next;
   }
+#if WINDOWS
+  LeaveCriticalSection (&output_message_cs);
+#endif
 }
 
 
 }
 
 
@@ -704,9 +819,9 @@ flush_bulk (const char *datestr)
   char msg[DATE_STR_SIZE + BULK_TRACK_SIZE + 256];
   int rev;
   char *last;
   char msg[DATE_STR_SIZE + BULK_TRACK_SIZE + 256];
   int rev;
   char *last;
-  char *ft;
+  const char *ft;
 
 
-  if ((last_bulk_time.abs_value == 0) || (last_bulk_repeat == 0))
+  if ((0 == last_bulk_time.abs_value_us) || (0 == last_bulk_repeat))
     return;
   rev = 0;
   last = memchr (last_bulk, '\0', BULK_TRACK_SIZE);
     return;
   rev = 0;
   last = memchr (last_bulk, '\0', BULK_TRACK_SIZE);
@@ -720,11 +835,10 @@ flush_bulk (const char *datestr)
     last[0] = '\0';
   }
   ft = GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_duration
     last[0] = '\0';
   }
   ft = GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_duration
-                                               (last_bulk_time));
+                                               (last_bulk_time), GNUNET_YES);
   snprintf (msg, sizeof (msg),
             _("Message `%.*s' repeated %u times in the last %s\n"),
             BULK_TRACK_SIZE, last_bulk, last_bulk_repeat, ft);
   snprintf (msg, sizeof (msg),
             _("Message `%.*s' repeated %u times in the last %s\n"),
             BULK_TRACK_SIZE, last_bulk, last_bulk_repeat, ft);
-  GNUNET_free (ft);
   if (rev == 1)
     last[0] = '\n';
   output_message (last_bulk_kind, last_bulk_comp, datestr, msg);
   if (rev == 1)
     last[0] = '\n';
   output_message (last_bulk_kind, last_bulk_comp, datestr, msg);
@@ -736,23 +850,38 @@ flush_bulk (const char *datestr)
 /**
  * Ignore the next n calls to the log function.
  *
 /**
  * Ignore the next n calls to the log function.
  *
- * @param n number of log calls to ignore
- * @param check_reset GNUNET_YES to assert that the log skip counter is currently zero
+ * @param n number of log calls to ignore (could be negative)
+ * @param check_reset #GNUNET_YES to assert that the log skip counter is currently zero
  */
 void
  */
 void
-GNUNET_log_skip (unsigned int n, int check_reset)
+GNUNET_log_skip (int n,
+                int check_reset)
 {
 {
-  if (n == 0)
-  {
-    int ok;
+  int ok;
 
 
+  if (0 == n)
+  {
     ok = (0 == skip_log);
     skip_log = 0;
     if (check_reset)
     ok = (0 == skip_log);
     skip_log = 0;
     if (check_reset)
-      GNUNET_assert (ok);
+      GNUNET_break (ok);
   }
   else
   }
   else
+  {
     skip_log += n;
     skip_log += n;
+  }
+}
+
+
+/**
+ * Get the number of log calls that are going to be skipped
+ *
+ * @return number of log calls to be ignored
+ */
+int
+GNUNET_get_log_skip ()
+{
+  return skip_log;
 }
 
 
 }
 
 
@@ -765,13 +894,13 @@ GNUNET_log_skip (unsigned int n, int check_reset)
  * @param va arguments to the format string "message"
  */
 static void
  * @param va arguments to the format string "message"
  */
 static void
-mylog (enum GNUNET_ErrorType kind, const char *comp, const char *message,
+mylog (enum GNUNET_ErrorType kind,
+       const char *comp,
+       const char *message,
        va_list va)
 {
   char date[DATE_STR_SIZE];
   char date2[DATE_STR_SIZE];
        va_list va)
 {
   char date[DATE_STR_SIZE];
   char date2[DATE_STR_SIZE];
-  time_t timetmp;
-  struct timeval timeofday;
   struct tm *tmptr;
   size_t size;
   va_list vacp;
   struct tm *tmptr;
   size_t size;
   va_list vacp;
@@ -780,39 +909,81 @@ mylog (enum GNUNET_ErrorType kind, const char *comp, const char *message,
   size = VSNPRINTF (NULL, 0, message, vacp) + 1;
   GNUNET_assert (0 != size);
   va_end (vacp);
   size = VSNPRINTF (NULL, 0, message, vacp) + 1;
   GNUNET_assert (0 != size);
   va_end (vacp);
+  memset (date, 0, DATE_STR_SIZE);
   {
     char buf[size];
   {
     char buf[size];
+    long long offset;
+#ifdef WINDOWS
+    LARGE_INTEGER pc;
+    time_t timetmp;
 
 
-    VSNPRINTF (buf, size, message, va);
+    offset = GNUNET_TIME_get_offset ();
     time (&timetmp);
     time (&timetmp);
-    memset (date, 0, DATE_STR_SIZE);
+    timetmp += offset / 1000;
     tmptr = localtime (&timetmp);
     tmptr = localtime (&timetmp);
-    gettimeofday (&timeofday, NULL);
-    if (NULL != tmptr)
+    pc.QuadPart = 0;
+    QueryPerformanceCounter (&pc);
+    if (NULL == tmptr)
+    {
+      strcpy (date, "localtime error");
+    }
+    else
     {
     {
-#ifdef WINDOWS
-      LARGE_INTEGER pc;
-
-      pc.QuadPart = 0;
-      QueryPerformanceCounter (&pc);
       strftime (date2, DATE_STR_SIZE, "%b %d %H:%M:%S-%%020llu", tmptr);
       snprintf (date, sizeof (date), date2,
       strftime (date2, DATE_STR_SIZE, "%b %d %H:%M:%S-%%020llu", tmptr);
       snprintf (date, sizeof (date), date2,
-                (long long) (pc.QuadPart /
-                             (performance_frequency.QuadPart / 1000)));
+               (long long) (pc.QuadPart /
+                            (performance_frequency.QuadPart / 1000)));
+    }
 #else
 #else
-      strftime (date2, DATE_STR_SIZE, "%b %d %H:%M:%S-%%06u", tmptr);
-      snprintf (date, sizeof (date), date2, timeofday.tv_usec);
-#endif
+    struct timeval timeofday;
+
+    gettimeofday (&timeofday, NULL);
+    offset = GNUNET_TIME_get_offset ();
+    if (offset > 0)
+    {
+      timeofday.tv_sec += offset / 1000LL;
+      timeofday.tv_usec += (offset % 1000LL) * 1000LL;
+      if (timeofday.tv_usec > 1000000LL)
+      {
+       timeofday.tv_usec -= 1000000LL;
+       timeofday.tv_sec++;
+      }
     }
     else
     }
     else
+    {
+      timeofday.tv_sec += offset / 1000LL;
+      if (timeofday.tv_usec > - (offset % 1000LL) * 1000LL)
+      {
+       timeofday.tv_usec += (offset % 1000LL) * 1000LL;
+      }
+      else
+      {
+       timeofday.tv_usec += 1000000LL + (offset % 1000LL) * 1000LL;
+       timeofday.tv_sec--;
+      }
+    }
+    tmptr = localtime (&timeofday.tv_sec);
+    if (NULL == tmptr)
+    {
       strcpy (date, "localtime error");
       strcpy (date, "localtime error");
+    }
+    else
+    {
+      strftime (date2, DATE_STR_SIZE, "%b %d %H:%M:%S-%%06u", tmptr);
+      snprintf (date, sizeof (date), date2, timeofday.tv_usec);
+    }
+#endif
+    VSNPRINTF (buf, size, message, va);
+    if (NULL != tmptr)
+      (void) setup_log_file (tmptr);
     if ((0 != (kind & GNUNET_ERROR_TYPE_BULK)) &&
     if ((0 != (kind & GNUNET_ERROR_TYPE_BULK)) &&
-        (last_bulk_time.abs_value != 0) &&
+        (0 != last_bulk_time.abs_value_us) &&
         (0 == strncmp (buf, last_bulk, sizeof (last_bulk))))
     {
       last_bulk_repeat++;
         (0 == strncmp (buf, last_bulk, sizeof (last_bulk))))
     {
       last_bulk_repeat++;
-      if ((GNUNET_TIME_absolute_get_duration (last_bulk_time).rel_value >
-           BULK_DELAY_THRESHOLD) || (last_bulk_repeat > BULK_REPEAT_THRESHOLD))
+      if ( (GNUNET_TIME_absolute_get_duration (last_bulk_time).rel_value_us >
+           BULK_DELAY_THRESHOLD) ||
+          (last_bulk_repeat > BULK_REPEAT_THRESHOLD) )
         flush_bulk (date);
       return;
     }
         flush_bulk (date);
       return;
     }
@@ -835,7 +1006,8 @@ mylog (enum GNUNET_ErrorType kind, const char *comp, const char *message,
  * @param ... arguments for format string
  */
 void
  * @param ... arguments for format string
  */
 void
-GNUNET_log_nocheck (enum GNUNET_ErrorType kind, const char *message, ...)
+GNUNET_log_nocheck (enum GNUNET_ErrorType kind,
+                   const char *message, ...)
 {
   va_list va;
 
 {
   va_list va;
 
@@ -912,6 +1084,7 @@ GNUNET_h2s (const struct GNUNET_HashCode * hc)
   return (const char *) ret.encoding;
 }
 
   return (const char *) ret.encoding;
 }
 
+
 /**
  * Convert a hash to a string (for printing debug messages).
  * This is one of the very few calls in the entire API that is
 /**
  * Convert a hash to a string (for printing debug messages).
  * This is one of the very few calls in the entire API that is
@@ -930,6 +1103,7 @@ GNUNET_h2s_full (const struct GNUNET_HashCode * hc)
   return (const char *) ret.encoding;
 }
 
   return (const char *) ret.encoding;
 }
 
+
 /**
  * Convert a peer identity to a string (for printing debug messages).
  * This is one of the very few calls in the entire API that is
 /**
  * Convert a peer identity to a string (for printing debug messages).
  * This is one of the very few calls in the entire API that is
@@ -937,18 +1111,22 @@ GNUNET_h2s_full (const struct GNUNET_HashCode * hc)
  *
  * @param pid the peer identity
  * @return string form of the pid; will be overwritten by next
  *
  * @param pid the peer identity
  * @return string form of the pid; will be overwritten by next
- *         call to GNUNET_i2s.
+ *         call to #GNUNET_i2s.
  */
 const char *
 GNUNET_i2s (const struct GNUNET_PeerIdentity *pid)
 {
  */
 const char *
 GNUNET_i2s (const struct GNUNET_PeerIdentity *pid)
 {
-  static struct GNUNET_CRYPTO_HashAsciiEncoded ret;
-
-  GNUNET_CRYPTO_hash_to_enc (&pid->hashPubKey, &ret);
-  ret.encoding[4] = '\0';
-  return (const char *) ret.encoding;
+  static char buf[256];
+  char *ret;
+
+  ret = GNUNET_CRYPTO_eddsa_public_key_to_string (&pid->public_key);
+  strcpy (buf, ret);
+  GNUNET_free (ret);
+  buf[4] = '\0';
+  return buf;
 }
 
 }
 
+
 /**
  * Convert a peer identity to a string (for printing debug messages).
  * This is one of the very few calls in the entire API that is
 /**
  * Convert a peer identity to a string (for printing debug messages).
  * This is one of the very few calls in the entire API that is
@@ -956,15 +1134,18 @@ GNUNET_i2s (const struct GNUNET_PeerIdentity *pid)
  *
  * @param pid the peer identity
  * @return string form of the pid; will be overwritten by next
  *
  * @param pid the peer identity
  * @return string form of the pid; will be overwritten by next
- *         call to GNUNET_i2s.
+ *         call to #GNUNET_i2s_full.
  */
 const char *
 GNUNET_i2s_full (const struct GNUNET_PeerIdentity *pid)
 {
  */
 const char *
 GNUNET_i2s_full (const struct GNUNET_PeerIdentity *pid)
 {
-  static struct GNUNET_CRYPTO_HashAsciiEncoded ret;
+  static char buf[256];
+  char *ret;
 
 
-  GNUNET_CRYPTO_hash_to_enc (&pid->hashPubKey, &ret);
-  return (const char *) ret.encoding;
+  ret = GNUNET_CRYPTO_eddsa_public_key_to_string (&pid->public_key);
+  strcpy (buf, ret);
+  GNUNET_free (ret);
+  return buf;
 }
 
 
 }
 
 
@@ -974,14 +1155,22 @@ GNUNET_i2s_full (const struct GNUNET_PeerIdentity *pid)
  * in the entire API that is NOT reentrant!
  *
  * @param addr the address
  * in the entire API that is NOT reentrant!
  *
  * @param addr the address
- * @param addrlen the length of the address
+ * @param addrlen the length of the address in @a addr
  * @return nicely formatted string for the address
  * @return nicely formatted string for the address
- *  will be overwritten by next call to GNUNET_a2s.
+ *  will be overwritten by next call to #GNUNET_a2s.
  */
 const char *
  */
 const char *
-GNUNET_a2s (const struct sockaddr *addr, socklen_t addrlen)
+GNUNET_a2s (const struct sockaddr *addr,
+            socklen_t addrlen)
 {
 {
-  static char buf[INET6_ADDRSTRLEN + 8];
+#ifndef WINDOWS
+#define LEN GNUNET_MAX ((INET6_ADDRSTRLEN + 8),         \
+                        (1 + sizeof (struct sockaddr_un) - sizeof (sa_family_t)))
+#else
+#define LEN (INET6_ADDRSTRLEN + 8)
+#endif
+  static char buf[LEN];
+#undef LEN
   static char b2[6];
   const struct sockaddr_in *v4;
   const struct sockaddr_un *un;
   static char b2[6];
   const struct sockaddr_in *v4;
   const struct sockaddr_un *un;
@@ -1020,11 +1209,15 @@ GNUNET_a2s (const struct sockaddr *addr, socklen_t addrlen)
       return "<unbound UNIX client>";
     un = (const struct sockaddr_un *) addr;
     off = 0;
       return "<unbound UNIX client>";
     un = (const struct sockaddr_un *) addr;
     off = 0;
-    if (un->sun_path[0] == '\0')
+    if ('\0' == un->sun_path[0])
       off++;
       off++;
-    snprintf (buf, sizeof (buf), "%s%.*s", (off == 1) ? "@" : "",
-              (int) (addrlen - sizeof (sa_family_t) - 1 - off),
-              &un->sun_path[off]);
+    memset (buf, 0, sizeof (buf));
+    GNUNET_snprintf (buf,
+                     sizeof (buf),
+                     "%s%.*s",
+                     (1 == off) ? "@" : "",
+                     (int) (addrlen - sizeof (sa_family_t) - off),
+                     &un->sun_path[off]);
     return buf;
   default:
     return _("invalid address");
     return buf;
   default:
     return _("invalid address");
@@ -1032,23 +1225,71 @@ GNUNET_a2s (const struct sockaddr *addr, socklen_t addrlen)
 }
 
 
 }
 
 
+/**
+ * Log error message about missing configuration option.
+ *
+ * @param kind log level
+ * @param section section with missing option
+ * @param option name of missing option
+ */
+void
+GNUNET_log_config_missing (enum GNUNET_ErrorType kind,
+                          const char *section,
+                          const char *option)
+{
+  GNUNET_log (kind,
+             _("Configuration fails to specify option `%s' in section `%s'!\n"),
+             option,
+             section);
+}
+
+
+/**
+ * Log error message about invalid configuration option value.
+ *
+ * @param kind log level
+ * @param section section with invalid option
+ * @param option name of invalid option
+ * @param required what is required that is invalid about the option
+ */
+void
+GNUNET_log_config_invalid (enum GNUNET_ErrorType kind,
+                          const char *section,
+                          const char *option,
+                          const char *required)
+{
+  GNUNET_log (kind,
+             _("Configuration specifies invalid value for option `%s' in section `%s': %s\n"),
+             option, section, required);
+}
+
+
 /**
  * Initializer
  */
 /**
  * Initializer
  */
-void __attribute__ ((constructor)) GNUNET_util_cl_init ()
+void __attribute__ ((constructor))
+GNUNET_util_cl_init ()
 {
   GNUNET_stderr = stderr;
 #ifdef MINGW
   GNInitWinEnv (NULL);
 #endif
 {
   GNUNET_stderr = stderr;
 #ifdef MINGW
   GNInitWinEnv (NULL);
 #endif
+#if WINDOWS
+  if (!InitializeCriticalSectionAndSpinCount (&output_message_cs, 0x00000400))
+    GNUNET_abort_ ();
+#endif
 }
 
 
 /**
  * Destructor
  */
 }
 
 
 /**
  * Destructor
  */
-void __attribute__ ((destructor)) GNUNET_util_cl_fini ()
+void __attribute__ ((destructor))
+GNUNET_util_cl_fini ()
 {
 {
+#if WINDOWS
+  DeleteCriticalSection (&output_message_cs);
+#endif
 #ifdef MINGW
   GNShutdownWinEnv ();
 #endif
 #ifdef MINGW
   GNShutdownWinEnv ();
 #endif