plibc: win32 related, socket
[oweals/gnunet.git] / src / util / common_logging.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2006-2013 GNUnet e.V.
4
5      GNUnet is free software: you can redistribute it and/or modify it
6      under the terms of the GNU Affero General Public License as published
7      by the Free Software Foundation, either version 3 of the License,
8      or (at your option) any later version.
9
10      GNUnet is distributed in the hope that it will be useful, but
11      WITHOUT ANY WARRANTY; without even the implied warranty of
12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13      Affero General Public License for more details.
14
15      You should have received a copy of the GNU Affero General Public License
16      along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
18      SPDX-License-Identifier: AGPL3.0-or-later
19  */
20
21 /**
22  * @file util/common_logging.c
23  * @brief error handling API
24  * @author Christian Grothoff
25  */
26 #include "platform.h"
27 #include "gnunet_crypto_lib.h"
28 #include "gnunet_disk_lib.h"
29 #include "gnunet_strings_lib.h"
30 #include <regex.h>
31
32
33 /**
34  * After how many milliseconds do we always print
35  * that "message X was repeated N times"?  Use 12h.
36  */
37 #define BULK_DELAY_THRESHOLD (12 * 60 * 60 * 1000LL * 1000LL)
38
39 /**
40  * After how many repetitions do we always print
41  * that "message X was repeated N times"? (even if
42  * we have not yet reached the delay threshold)
43  */
44 #define BULK_REPEAT_THRESHOLD 1000
45
46 /**
47  * How many characters do we use for matching of
48  * bulk messages?
49  */
50 #define BULK_TRACK_SIZE 256
51
52 /**
53  * How many characters do we use for matching of
54  * bulk components?
55  */
56 #define COMP_TRACK_SIZE 32
57
58 /**
59  * How many characters can a date/time string
60  * be at most?
61  */
62 #define DATE_STR_SIZE 64
63
64 /**
65  * How many log files to keep?
66  */
67 #define ROTATION_KEEP 3
68
69 #ifndef PATH_MAX
70 /**
71  * Assumed maximum path length (for the log file name).
72  */
73 #define PATH_MAX 4096
74 #endif
75
76
77 /**
78  * Linked list of active loggers.
79  */
80 struct CustomLogger {
81   /**
82    * This is a linked list.
83    */
84   struct CustomLogger *next;
85
86   /**
87    * Log function.
88    */
89   GNUNET_Logger logger;
90
91   /**
92    * Closure for logger.
93    */
94   void *logger_cls;
95 };
96
97
98 /**
99  * Asynchronous scope of the current thread, or NULL if we have not
100  * entered an async scope yet.
101  */
102 static __thread struct GNUNET_AsyncScopeSave current_async_scope;
103
104 /**
105  * The last "bulk" error message that we have been logging.
106  * Note that this message maybe truncated to the first BULK_TRACK_SIZE
107  * characters, in which case it is NOT 0-terminated!
108  */
109 static GNUNET_THREAD_LOCAL char last_bulk[BULK_TRACK_SIZE] __nonstring;
110
111 /**
112  * Type of the last bulk message.
113  */
114 static GNUNET_THREAD_LOCAL enum GNUNET_ErrorType last_bulk_kind;
115
116 /**
117  * Time of the last bulk error message (0 for none)
118  */
119 static GNUNET_THREAD_LOCAL struct GNUNET_TIME_Absolute last_bulk_time;
120
121 /**
122  * Number of times that bulk message has been repeated since.
123  */
124 static GNUNET_THREAD_LOCAL unsigned int last_bulk_repeat;
125
126 /**
127  * Component when the last bulk was logged.  Will be 0-terminated.
128  */
129 static GNUNET_THREAD_LOCAL char last_bulk_comp[COMP_TRACK_SIZE + 1];
130
131 /**
132  * Running component.
133  */
134 static char *component;
135
136 /**
137  * Running component (without pid).
138  */
139 static char *component_nopid;
140
141 /**
142  * Format string describing the name of the log file.
143  */
144 static char *log_file_name;
145
146 /**
147  * Minimum log level.
148  */
149 static enum GNUNET_ErrorType min_level;
150
151 /**
152  * Linked list of our custom loggres.
153  */
154 static struct CustomLogger *loggers;
155
156 /**
157  * Number of log calls to ignore.
158  */
159 static GNUNET_THREAD_LOCAL int skip_log = 0;
160
161 /**
162  * File descriptor to use for "stderr", or NULL for none.
163  */
164 static FILE *GNUNET_stderr;
165
166 /**
167  * Represents a single logging definition
168  */
169 struct LogDef {
170   /**
171    * Component name regex
172    */
173   regex_t component_regex;
174
175   /**
176    * File name regex
177    */
178   regex_t file_regex;
179
180   /**
181    * Function name regex
182    */
183   regex_t function_regex;
184
185   /**
186    * Lowest line at which this definition matches.
187    * Defaults to 0. Must be <= to_line.
188    */
189   int from_line;
190
191   /**
192    * Highest line at which this definition matches.
193    * Defaults to INT_MAX. Must be >= from_line.
194    */
195   int to_line;
196
197   /**
198    * Maximal log level allowed for calls that match this definition.
199    * Calls with higher log level will be disabled.
200    * Must be >= 0
201    */
202   int level;
203
204   /**
205    * 1 if this definition comes from GNUNET_FORCE_LOG, which means that it
206    * overrides any configuration options. 0 otherwise.
207    */
208   int force;
209 };
210
211
212 #if !defined(GNUNET_CULL_LOGGING)
213 /**
214  * Dynamic array of logging definitions
215  */
216 static struct LogDef *logdefs;
217
218 /**
219  * Allocated size of logdefs array (in units)
220  */
221 static int logdefs_size;
222
223 /**
224  * The number of units used in logdefs array.
225  */
226 static int logdefs_len;
227
228 /**
229  * #GNUNET_YES if GNUNET_LOG environment variable is already parsed.
230  */
231 static int gnunet_log_parsed;
232
233 /**
234  * #GNUNET_YES if GNUNET_FORCE_LOG environment variable is already parsed.
235  */
236 static int gnunet_force_log_parsed;
237
238 /**
239  * #GNUNET_YES if at least one definition with forced == 1 is available.
240  */
241 static int gnunet_force_log_present;
242 #endif
243
244 #ifdef WINDOWS
245 /**
246  * Contains the number of performance counts per second.
247  */
248 static LARGE_INTEGER performance_frequency;
249 #endif
250
251
252 /**
253  * Convert a textual description of a loglevel
254  * to the respective GNUNET_GE_KIND.
255  *
256  * @param log loglevel to parse
257  * @return GNUNET_GE_INVALID if log does not parse
258  */
259 static enum GNUNET_ErrorType
260 get_type(const char *log)
261 {
262   if (NULL == log)
263     return GNUNET_ERROR_TYPE_UNSPECIFIED;
264   if (0 == strcasecmp(log, _("DEBUG")))
265     return GNUNET_ERROR_TYPE_DEBUG;
266   if (0 == strcasecmp(log, _("INFO")))
267     return GNUNET_ERROR_TYPE_INFO;
268   if (0 == strcasecmp(log, _("MESSAGE")))
269     return GNUNET_ERROR_TYPE_MESSAGE;
270   if (0 == strcasecmp(log, _("WARNING")))
271     return GNUNET_ERROR_TYPE_WARNING;
272   if (0 == strcasecmp(log, _("ERROR")))
273     return GNUNET_ERROR_TYPE_ERROR;
274   if (0 == strcasecmp(log, _("NONE")))
275     return GNUNET_ERROR_TYPE_NONE;
276   return GNUNET_ERROR_TYPE_INVALID;
277 }
278
279
280 /**
281  * Abort the process, generate a core dump if possible.
282  */
283 void
284 GNUNET_abort_()
285 {
286 #if WINDOWS
287   DebugBreak();
288 #endif
289   abort();
290 }
291
292
293 #if !defined(GNUNET_CULL_LOGGING)
294 /**
295  * Utility function - reallocates logdefs array to be twice as large.
296  */
297 static void
298 resize_logdefs()
299 {
300   logdefs_size = (logdefs_size + 1) * 2;
301   logdefs = GNUNET_realloc(logdefs, logdefs_size * sizeof(struct LogDef));
302 }
303
304
305 #if !TALER_WALLET_ONLY
306 /**
307  * Rotate logs, deleting the oldest log.
308  *
309  * @param new_name new name to add to the rotation
310  */
311 static void
312 log_rotate(const char *new_name)
313 {
314   static char *rotation[ROTATION_KEEP];
315   static unsigned int rotation_off;
316   char *discard;
317
318   if ('\0' == *new_name)
319     return; /* not a real log file name */
320   discard = rotation[rotation_off % ROTATION_KEEP];
321   if (NULL != discard)
322     {
323       /* Note: can't log errors during logging (recursion!), so this
324          operation MUST silently fail... */
325       (void)unlink(discard);
326       GNUNET_free(discard);
327     }
328   rotation[rotation_off % ROTATION_KEEP] = GNUNET_strdup(new_name);
329   rotation_off++;
330 }
331
332
333 /**
334  * Setup the log file.
335  *
336  * @param tm timestamp for which we should setup logging
337  * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
338  */
339 static int
340 setup_log_file(const struct tm *tm)
341 {
342   static char last_fn[PATH_MAX + 1];
343   char fn[PATH_MAX + 1];
344   int altlog_fd;
345   int dup_return;
346   FILE *altlog;
347   char *leftsquare;
348
349   if (NULL == log_file_name)
350     return GNUNET_SYSERR;
351   if (0 == strftime(fn, sizeof(fn), log_file_name, tm))
352     return GNUNET_SYSERR;
353   leftsquare = strrchr(fn, '[');
354   if ((NULL != leftsquare) && (']' == leftsquare[1]))
355     {
356       char *logfile_copy = GNUNET_strdup(fn);
357
358       logfile_copy[leftsquare - fn] = '\0';
359       logfile_copy[leftsquare - fn + 1] = '\0';
360       snprintf(fn,
361                PATH_MAX,
362                "%s%d%s",
363                logfile_copy,
364                getpid(),
365                &logfile_copy[leftsquare - fn + 2]);
366       GNUNET_free(logfile_copy);
367     }
368   if (0 == strcmp(fn, last_fn))
369     return GNUNET_OK; /* no change */
370   log_rotate(last_fn);
371   strcpy(last_fn, fn);
372   if (GNUNET_SYSERR == GNUNET_DISK_directory_create_for_file(fn))
373     {
374       fprintf(stderr,
375               "Failed to create directory for `%s': %s\n",
376               fn,
377               strerror(errno));
378       return GNUNET_SYSERR;
379     }
380 #if WINDOWS
381   altlog_fd =
382     open(fn, O_APPEND | O_BINARY | O_WRONLY | O_CREAT, _S_IREAD | _S_IWRITE);
383 #else
384   altlog_fd = open(fn,
385                    O_APPEND | O_WRONLY | O_CREAT,
386                    S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
387 #endif
388   if (-1 != altlog_fd)
389     {
390       if (NULL != GNUNET_stderr)
391         fclose(GNUNET_stderr);
392       dup_return = dup2(altlog_fd, 2);
393       (void)close(altlog_fd);
394       if (-1 != dup_return)
395         {
396           altlog = fdopen(2, "ab");
397           if (NULL == altlog)
398             {
399               (void)close(2);
400               altlog_fd = -1;
401             }
402         }
403       else
404         {
405           altlog_fd = -1;
406         }
407     }
408   if (-1 == altlog_fd)
409     {
410       GNUNET_log_strerror_file(GNUNET_ERROR_TYPE_ERROR, "open", fn);
411       return GNUNET_SYSERR;
412     }
413   GNUNET_stderr = altlog;
414   return GNUNET_OK;
415 }
416 #endif
417
418
419 /**
420  * Utility function - adds a parsed definition to logdefs array.
421  *
422  * @param component see struct LogDef, can't be NULL
423  * @param file see struct LogDef, can't be NULL
424  * @param function see struct LogDef, can't be NULL
425  * @param from_line see struct LogDef
426  * @param to_line see struct LogDef
427  * @param level see struct LogDef, must be >= 0
428  * @param force see struct LogDef
429  * @return 0 on success, regex-specific error otherwise
430  */
431 static int
432 add_definition(const char *component,
433                const char *file,
434                const char *function,
435                int from_line,
436                int to_line,
437                int level,
438                int force)
439 {
440   struct LogDef n;
441   int r;
442
443   if (logdefs_size == logdefs_len)
444     resize_logdefs();
445   memset(&n, 0, sizeof(n));
446   if (0 == strlen(component))
447     component = (char *)".*";
448   r = regcomp(&n.component_regex, (const char *)component, REG_NOSUB);
449   if (0 != r)
450     {
451       return r;
452     }
453   if (0 == strlen(file))
454     file = (char *)".*";
455   r = regcomp(&n.file_regex, (const char *)file, REG_NOSUB);
456   if (0 != r)
457     {
458       regfree(&n.component_regex);
459       return r;
460     }
461   if ((NULL == function) || (0 == strlen(function)))
462     function = (char *)".*";
463   r = regcomp(&n.function_regex, (const char *)function, REG_NOSUB);
464   if (0 != r)
465     {
466       regfree(&n.component_regex);
467       regfree(&n.file_regex);
468       return r;
469     }
470   n.from_line = from_line;
471   n.to_line = to_line;
472   n.level = level;
473   n.force = force;
474   logdefs[logdefs_len++] = n;
475   return 0;
476 }
477
478
479 /**
480  * Decides whether a particular logging call should or should not be allowed
481  * to be made. Used internally by GNUNET_log*()
482  *
483  * @param caller_level loglevel the caller wants to use
484  * @param comp component name the caller uses (NULL means that global
485  *   component name is used)
486  * @param file file name containing the logging call, usually __FILE__
487  * @param function function which tries to make a logging call,
488  *   usually __FUNCTION__
489  * @param line line at which the call is made, usually __LINE__
490  * @return 0 to disallow the call, 1 to allow it
491  */
492 int
493 GNUNET_get_log_call_status(int caller_level,
494                            const char *comp,
495                            const char *file,
496                            const char *function,
497                            int line)
498 {
499   struct LogDef *ld;
500   int i;
501   int force_only;
502
503   if (NULL == comp)
504     /* Use default component */
505     comp = component_nopid;
506
507   /* We have no definitions to override globally configured log level,
508    * so just use it right away.
509    */
510   if ((min_level >= 0) && (GNUNET_NO == gnunet_force_log_present))
511     return caller_level <= min_level;
512
513   /* Only look for forced definitions? */
514   force_only = min_level >= 0;
515   for (i = 0; i < logdefs_len; i++)
516     {
517       ld = &logdefs[i];
518       if (((!force_only) || ld->force) &&
519           (line >= ld->from_line && line <= ld->to_line) &&
520           (0 == regexec(&ld->component_regex, comp, 0, NULL, 0)) &&
521           (0 == regexec(&ld->file_regex, file, 0, NULL, 0)) &&
522           (0 == regexec(&ld->function_regex, function, 0, NULL, 0)))
523         {
524           /* We're finished */
525           return caller_level <= ld->level;
526         }
527     }
528   /* No matches - use global level, if defined */
529   if (min_level >= 0)
530     return caller_level <= min_level;
531   /* All programs/services previously defaulted to WARNING.
532    * Now *we* default to WARNING, and THEY default to NULL.
533    * Or rather we default to MESSAGE, since things aren't always bad.
534    */
535   return caller_level <= GNUNET_ERROR_TYPE_MESSAGE;
536 }
537
538
539 /**
540  * Utility function - parses a definition
541  *
542  * Definition format:
543  * component;file;function;from_line-to_line;level[/component...]
544  * All entries are mandatory, but may be empty.
545  * Empty entries for component, file and function are treated as
546  * "matches anything".
547  * Empty line entry is treated as "from 0 to INT_MAX"
548  * Line entry with only one line is treated as "this line only"
549  * Entry for level MUST NOT be empty.
550  * Entries for component, file and function that consist of a
551  * single character "*" are treated (at the moment) the same way
552  * empty entries are treated (wildcard matching is not implemented (yet?)).
553  * file entry is matched to the end of __FILE__. That is, it might be
554  * a base name, or a base name with leading directory names (some compilers
555  * define __FILE__ to absolute file path).
556  *
557  * @param constname name of the environment variable from which to get the
558  *   string to be parsed
559  * @param force 1 if definitions found in constname are to be forced
560  * @return number of added definitions
561  */
562 static int
563 parse_definitions(const char *constname, int force)
564 {
565   char *def;
566   const char *tmp;
567   char *comp = NULL;
568   char *file = NULL;
569   char *function = NULL;
570   char *p;
571   char *start;
572   char *t;
573   short state;
574   int level;
575   int from_line, to_line;
576   int counter = 0;
577   int keep_looking = 1;
578
579   tmp = getenv(constname);
580   if (NULL == tmp)
581     return 0;
582   def = GNUNET_strdup(tmp);
583   from_line = 0;
584   to_line = INT_MAX;
585   for (p = def, state = 0, start = def; keep_looking; p++)
586     {
587       switch (p[0])
588         {
589         case ';': /* found a field separator */
590           p[0] = '\0';
591           switch (state)
592             {
593             case 0: /* within a component name */
594               comp = start;
595               break;
596
597             case 1: /* within a file name */
598               file = start;
599               break;
600
601             case 2: /* within a function name */
602               /* after a file name there must be a function name */
603               function = start;
604               break;
605
606             case 3: /* within a from-to line range */
607               if (strlen(start) > 0)
608                 {
609                   errno = 0;
610                   from_line = strtol(start, &t, 10);
611                   if ((0 != errno) || (from_line < 0))
612                     {
613                       GNUNET_free(def);
614                       return counter;
615                     }
616                   if ((t < p) && ('-' == t[0]))
617                     {
618                       errno = 0;
619                       start = t + 1;
620                       to_line = strtol(start, &t, 10);
621                       if ((0 != errno) || (to_line < 0) || (t != p))
622                         {
623                           GNUNET_free(def);
624                           return counter;
625                         }
626                     }
627                   else /* one number means "match this line only" */
628                     to_line = from_line;
629                 }
630               else /* default to 0-max */
631                 {
632                   from_line = 0;
633                   to_line = INT_MAX;
634                 }
635               break;
636
637             default:
638               fprintf(
639                 stderr,
640                 _("ERROR: Unable to parse log definition: Syntax error at `%s'.\n"),
641                 p);
642               break;
643             }
644           start = p + 1;
645           state++;
646           break;
647
648         case '\0': /* found EOL */
649           keep_looking = 0;
650
651         /* fall through to '/' */
652         case '/': /* found a definition separator */
653           switch (state)
654             {
655             case 4: /* within a log level */
656               p[0] = '\0';
657               state = 0;
658               level = get_type((const char *)start);
659               if ((GNUNET_ERROR_TYPE_INVALID == level) ||
660                   (GNUNET_ERROR_TYPE_UNSPECIFIED == level) ||
661                   (0 != add_definition(comp,
662                                        file,
663                                        function,
664                                        from_line,
665                                        to_line,
666                                        level,
667                                        force)))
668                 {
669                   GNUNET_free(def);
670                   return counter;
671                 }
672               counter++;
673               start = p + 1;
674               break;
675
676             default:
677               fprintf(
678                 stderr,
679                 _("ERROR: Unable to parse log definition: Syntax error at `%s'.\n"),
680                 p);
681               break;
682             }
683
684         default:
685           break;
686         }
687     }
688   GNUNET_free(def);
689   return counter;
690 }
691
692
693 /**
694  * Utility function - parses GNUNET_LOG and GNUNET_FORCE_LOG.
695  */
696 static void
697 parse_all_definitions()
698 {
699   if (GNUNET_NO == gnunet_force_log_parsed)
700     gnunet_force_log_present =
701       parse_definitions("GNUNET_FORCE_LOG", 1) > 0 ? GNUNET_YES : GNUNET_NO;
702   gnunet_force_log_parsed = GNUNET_YES;
703
704   if (GNUNET_NO == gnunet_log_parsed)
705     parse_definitions("GNUNET_LOG", 0);
706   gnunet_log_parsed = GNUNET_YES;
707 }
708 #endif
709
710
711 /**
712  * Setup logging.
713  *
714  * @param comp default component to use
715  * @param loglevel what types of messages should be logged
716  * @param logfile which file to write log messages to (can be NULL)
717  * @return #GNUNET_OK on success
718  */
719 int
720 GNUNET_log_setup(const char *comp, const char *loglevel, const char *logfile)
721 {
722   const char *env_logfile;
723
724   min_level = get_type(loglevel);
725 #if !defined(GNUNET_CULL_LOGGING)
726   parse_all_definitions();
727 #endif
728 #ifdef WINDOWS
729   QueryPerformanceFrequency(&performance_frequency);
730 #endif
731   GNUNET_free_non_null(component);
732   GNUNET_asprintf(&component, "%s-%d", comp, getpid());
733   GNUNET_free_non_null(component_nopid);
734   component_nopid = GNUNET_strdup(comp);
735
736   env_logfile = getenv("GNUNET_FORCE_LOGFILE");
737   if ((NULL != env_logfile) && (strlen(env_logfile) > 0))
738     logfile = env_logfile;
739   if (NULL == logfile)
740     return GNUNET_OK;
741   GNUNET_free_non_null(log_file_name);
742   log_file_name = GNUNET_STRINGS_filename_expand(logfile);
743   if (NULL == log_file_name)
744     return GNUNET_SYSERR;
745 #if TALER_WALLET_ONLY || defined(GNUNET_CULL_LOGGING)
746   /* log file option not allowed for wallet logic */
747   GNUNET_assert(NULL == logfile);
748   return GNUNET_OK;
749 #else
750   {
751     time_t t;
752     const struct tm *tm;
753
754     t = time(NULL);
755     tm = gmtime(&t);
756     return setup_log_file(tm);
757   }
758 #endif
759 }
760
761
762 /**
763  * Add a custom logger. Note that installing any custom logger
764  * will disable the standard logger.  When multiple custom loggers
765  * are installed, all will be called.  The standard logger will
766  * only be used if no custom loggers are present.
767  *
768  * @param logger log function
769  * @param logger_cls closure for @a logger
770  */
771 void
772 GNUNET_logger_add(GNUNET_Logger logger, void *logger_cls)
773 {
774   struct CustomLogger *entry;
775
776   entry = GNUNET_new(struct CustomLogger);
777   entry->logger = logger;
778   entry->logger_cls = logger_cls;
779   entry->next = loggers;
780   loggers = entry;
781 }
782
783
784 /**
785  * Remove a custom logger.
786  *
787  * @param logger log function
788  * @param logger_cls closure for @a logger
789  */
790 void
791 GNUNET_logger_remove(GNUNET_Logger logger, void *logger_cls)
792 {
793   struct CustomLogger *pos;
794   struct CustomLogger *prev;
795
796   prev = NULL;
797   pos = loggers;
798   while ((NULL != pos) &&
799          ((pos->logger != logger) || (pos->logger_cls != logger_cls)))
800     {
801       prev = pos;
802       pos = pos->next;
803     }
804   GNUNET_assert(NULL != pos);
805   if (NULL == prev)
806     loggers = pos->next;
807   else
808     prev->next = pos->next;
809   GNUNET_free(pos);
810 }
811
812 #if WINDOWS
813 CRITICAL_SECTION output_message_cs;
814 #endif
815
816
817 /**
818  * Actually output the log message.
819  *
820  * @param kind how severe was the issue
821  * @param comp component responsible
822  * @param datestr current date/time
823  * @param msg the actual message
824  */
825 static void
826 output_message(enum GNUNET_ErrorType kind,
827                const char *comp,
828                const char *datestr,
829                const char *msg)
830 {
831   struct CustomLogger *pos;
832
833 #if WINDOWS
834   EnterCriticalSection(&output_message_cs);
835 #endif
836   /* only use the standard logger if no custom loggers are present */
837   if ((NULL != GNUNET_stderr) && (NULL == loggers))
838     {
839       if (kind == GNUNET_ERROR_TYPE_MESSAGE)
840         {
841           /* The idea here is to produce "normal" output messages
842            * for end users while still having the power of the
843            * logging engine for developer needs. So ideally this
844            * is what it should look like when CLI tools are used
845            * interactively, yet the same message shouldn't look
846            * this way if the output is going to logfiles or robots
847            * instead.
848            */
849           fprintf(GNUNET_stderr, "* %s", msg);
850         }
851       else if (GNUNET_YES == current_async_scope.have_scope)
852         {
853           static GNUNET_THREAD_LOCAL char id_buf[27];
854           char *end;
855
856           /* We're logging, so skip_log must be currently 0. */
857           skip_log = 100;
858           end = GNUNET_STRINGS_data_to_string(&current_async_scope.scope_id,
859                                               sizeof(struct GNUNET_AsyncScopeId),
860                                               id_buf,
861                                               sizeof(id_buf) - 1);
862           GNUNET_assert(NULL != end);
863           *end = '\0';
864           skip_log = 0;
865           fprintf(GNUNET_stderr,
866                   "%s %s(%s) %s %s",
867                   datestr,
868                   comp,
869                   id_buf,
870                   GNUNET_error_type_to_string(kind),
871                   msg);
872         }
873       else
874         {
875           fprintf(GNUNET_stderr,
876                   "%s %s %s %s",
877                   datestr,
878                   comp,
879                   GNUNET_error_type_to_string(kind),
880                   msg);
881         }
882       fflush(GNUNET_stderr);
883     }
884   pos = loggers;
885   while (NULL != pos)
886     {
887       pos->logger(pos->logger_cls, kind, comp, datestr, msg);
888       pos = pos->next;
889     }
890 #if WINDOWS
891   LeaveCriticalSection(&output_message_cs);
892 #endif
893 }
894
895
896 /**
897  * Flush an existing bulk report to the output.
898  *
899  * @param datestr our current timestamp
900  */
901 static void
902 flush_bulk(const char *datestr)
903 {
904   char msg[DATE_STR_SIZE + BULK_TRACK_SIZE + 256];
905   int rev;
906   char *last;
907   const char *ft;
908
909   if ((0 == last_bulk_time.abs_value_us) || (0 == last_bulk_repeat))
910     return;
911   rev = 0;
912   last = memchr(last_bulk, '\0', BULK_TRACK_SIZE);
913   if (last == NULL)
914     last = &last_bulk[BULK_TRACK_SIZE - 1];
915   else if (last != last_bulk)
916     last--;
917   if (last[0] == '\n')
918     {
919       rev = 1;
920       last[0] = '\0';
921     }
922   ft =
923     GNUNET_STRINGS_relative_time_to_string(GNUNET_TIME_absolute_get_duration(
924                                              last_bulk_time),
925                                            GNUNET_YES);
926   snprintf(msg,
927            sizeof(msg),
928            _("Message `%.*s' repeated %u times in the last %s\n"),
929            BULK_TRACK_SIZE,
930            last_bulk,
931            last_bulk_repeat,
932            ft);
933   if (rev == 1)
934     last[0] = '\n';
935   output_message(last_bulk_kind, last_bulk_comp, datestr, msg);
936   last_bulk_time = GNUNET_TIME_absolute_get();
937   last_bulk_repeat = 0;
938 }
939
940
941 /**
942  * Ignore the next n calls to the log function.
943  *
944  * @param n number of log calls to ignore (could be negative)
945  * @param check_reset #GNUNET_YES to assert that the log skip counter is currently zero
946  */
947 void
948 GNUNET_log_skip(int n, int check_reset)
949 {
950   int ok;
951
952   if (0 == n)
953     {
954       ok = (0 == skip_log);
955       skip_log = 0;
956       if (check_reset)
957         GNUNET_break(ok);
958     }
959   else
960     {
961       skip_log += n;
962     }
963 }
964
965
966 /**
967  * Get the number of log calls that are going to be skipped
968  *
969  * @return number of log calls to be ignored
970  */
971 int
972 GNUNET_get_log_skip()
973 {
974   return skip_log;
975 }
976
977
978 /**
979  * Output a log message using the default mechanism.
980  *
981  * @param kind how severe was the issue
982  * @param comp component responsible
983  * @param message the actual message
984  * @param va arguments to the format string "message"
985  */
986 static void
987 mylog(enum GNUNET_ErrorType kind,
988       const char *comp,
989       const char *message,
990       va_list va)
991 {
992   char date[DATE_STR_SIZE];
993   char date2[DATE_STR_SIZE];
994   struct tm *tmptr;
995   size_t size;
996   va_list vacp;
997
998   va_copy(vacp, va);
999   size = vsnprintf(NULL, 0, message, vacp) + 1;
1000   GNUNET_assert(0 != size);
1001   va_end(vacp);
1002   memset(date, 0, DATE_STR_SIZE);
1003   {
1004     char buf[size];
1005     long long offset;
1006 #ifdef WINDOWS
1007     LARGE_INTEGER pc;
1008     time_t timetmp;
1009
1010     offset = GNUNET_TIME_get_offset();
1011     time(&timetmp);
1012     timetmp += offset / 1000;
1013     tmptr = localtime(&timetmp);
1014     pc.QuadPart = 0;
1015     QueryPerformanceCounter(&pc);
1016     if (NULL == tmptr)
1017       {
1018         strcpy(date, "localtime error");
1019       }
1020     else
1021       {
1022         if (0 ==
1023             strftime(date2, DATE_STR_SIZE, "%b %d %H:%M:%S-%%020llu", tmptr))
1024           abort();
1025         if (0 > snprintf(date,
1026                          sizeof(date),
1027                          date2,
1028                          (long long)(pc.QuadPart /
1029                                      (performance_frequency.QuadPart / 1000))))
1030           abort();
1031       }
1032 #else
1033     struct timeval timeofday;
1034
1035     gettimeofday(&timeofday, NULL);
1036     offset = GNUNET_TIME_get_offset();
1037     if (offset > 0)
1038       {
1039         timeofday.tv_sec += offset / 1000LL;
1040         timeofday.tv_usec += (offset % 1000LL) * 1000LL;
1041         if (timeofday.tv_usec > 1000000LL)
1042           {
1043             timeofday.tv_usec -= 1000000LL;
1044             timeofday.tv_sec++;
1045           }
1046       }
1047     else
1048       {
1049         timeofday.tv_sec += offset / 1000LL;
1050         if (timeofday.tv_usec > -(offset % 1000LL) * 1000LL)
1051           {
1052             timeofday.tv_usec += (offset % 1000LL) * 1000LL;
1053           }
1054         else
1055           {
1056             timeofday.tv_usec += 1000000LL + (offset % 1000LL) * 1000LL;
1057             timeofday.tv_sec--;
1058           }
1059       }
1060     tmptr = localtime(&timeofday.tv_sec);
1061     if (NULL == tmptr)
1062       {
1063         strcpy(date, "localtime error");
1064       }
1065     else
1066       {
1067         if (0 == strftime(date2, DATE_STR_SIZE, "%b %d %H:%M:%S-%%06u", tmptr))
1068           abort();
1069         if (0 > snprintf(date, sizeof(date), date2, timeofday.tv_usec))
1070           abort();
1071       }
1072 #endif
1073     vsnprintf(buf, size, message, va);
1074 #if !(defined(GNUNET_CULL_LOGGING) || TALER_WALLET_ONLY)
1075     if (NULL != tmptr)
1076       (void)setup_log_file(tmptr);
1077 #endif
1078     if ((0 != (kind & GNUNET_ERROR_TYPE_BULK)) &&
1079         (0 != last_bulk_time.abs_value_us) &&
1080         (0 == strncmp(buf, last_bulk, sizeof(last_bulk))))
1081       {
1082         last_bulk_repeat++;
1083         if ((GNUNET_TIME_absolute_get_duration(last_bulk_time).rel_value_us >
1084              BULK_DELAY_THRESHOLD) ||
1085             (last_bulk_repeat > BULK_REPEAT_THRESHOLD))
1086           flush_bulk(date);
1087         return;
1088       }
1089     flush_bulk(date);
1090     GNUNET_strlcpy(last_bulk, buf, sizeof(last_bulk));
1091     last_bulk_repeat = 0;
1092     last_bulk_kind = kind;
1093     last_bulk_time = GNUNET_TIME_absolute_get();
1094     GNUNET_strlcpy(last_bulk_comp, comp, sizeof(last_bulk_comp));
1095     output_message(kind, comp, date, buf);
1096   }
1097 }
1098
1099
1100 /**
1101  * Main log function.
1102  *
1103  * @param kind how serious is the error?
1104  * @param message what is the message (format string)
1105  * @param ... arguments for format string
1106  */
1107 void
1108 GNUNET_log_nocheck(enum GNUNET_ErrorType kind, const char *message, ...)
1109 {
1110   va_list va;
1111
1112   va_start(va, message);
1113   mylog(kind, component, message, va);
1114   va_end(va);
1115 }
1116
1117
1118 /**
1119  * Log function that specifies an alternative component.
1120  * This function should be used by plugins.
1121  *
1122  * @param kind how serious is the error?
1123  * @param comp component responsible for generating the message
1124  * @param message what is the message (format string)
1125  * @param ... arguments for format string
1126  */
1127 void
1128 GNUNET_log_from_nocheck(enum GNUNET_ErrorType kind,
1129                         const char *comp,
1130                         const char *message,
1131                         ...)
1132 {
1133   va_list va;
1134   char comp_w_pid[128];
1135
1136   if (comp == NULL)
1137     comp = component_nopid;
1138
1139   va_start(va, message);
1140   GNUNET_snprintf(comp_w_pid, sizeof(comp_w_pid), "%s-%d", comp, getpid());
1141   mylog(kind, comp_w_pid, message, va);
1142   va_end(va);
1143 }
1144
1145
1146 /**
1147  * Convert error type to string.
1148  *
1149  * @param kind type to convert
1150  * @return string corresponding to the type
1151  */
1152 const char *
1153 GNUNET_error_type_to_string(enum GNUNET_ErrorType kind)
1154 {
1155   if ((kind & GNUNET_ERROR_TYPE_ERROR) > 0)
1156     return _("ERROR");
1157   if ((kind & GNUNET_ERROR_TYPE_WARNING) > 0)
1158     return _("WARNING");
1159   if ((kind & GNUNET_ERROR_TYPE_MESSAGE) > 0)
1160     return _("MESSAGE");
1161   if ((kind & GNUNET_ERROR_TYPE_INFO) > 0)
1162     return _("INFO");
1163   if ((kind & GNUNET_ERROR_TYPE_DEBUG) > 0)
1164     return _("DEBUG");
1165   if ((kind & ~GNUNET_ERROR_TYPE_BULK) == 0)
1166     return _("NONE");
1167   return _("INVALID");
1168 }
1169
1170
1171 /**
1172  * Convert a hash to a string (for printing debug messages).
1173  *
1174  * @param hc the hash code
1175  * @return string form; will be overwritten by next call to GNUNET_h2s.
1176  */
1177 const char *
1178 GNUNET_h2s(const struct GNUNET_HashCode *hc)
1179 {
1180   static GNUNET_THREAD_LOCAL struct GNUNET_CRYPTO_HashAsciiEncoded ret;
1181
1182   GNUNET_CRYPTO_hash_to_enc(hc, &ret);
1183   ret.encoding[8] = '\0';
1184   return (const char *)ret.encoding;
1185 }
1186
1187
1188 /**
1189  * Convert a hash to a string (for printing debug messages).
1190  * This is one of the very few calls in the entire API that is
1191  * NOT reentrant! Identical to #GNUNET_h2s(), except that another
1192  * buffer is used so both #GNUNET_h2s() and #GNUNET_h2s2() can be
1193  * used within the same log statement.
1194  *
1195  * @param hc the hash code
1196  * @return string form; will be overwritten by next call to GNUNET_h2s.
1197  */
1198 const char *
1199 GNUNET_h2s2(const struct GNUNET_HashCode *hc)
1200 {
1201   static struct GNUNET_CRYPTO_HashAsciiEncoded ret;
1202
1203   GNUNET_CRYPTO_hash_to_enc(hc, &ret);
1204   ret.encoding[8] = '\0';
1205   return (const char *)ret.encoding;
1206 }
1207
1208
1209 /**
1210  * @ingroup logging
1211  * Convert a public key value to a string (for printing debug messages).
1212  * This is one of the very few calls in the entire API that is
1213  * NOT reentrant!
1214  *
1215  * @param hc the hash code
1216  * @return string
1217  */
1218 const char *
1219 GNUNET_p2s(const struct GNUNET_CRYPTO_EddsaPublicKey *p)
1220 {
1221   static struct GNUNET_CRYPTO_HashAsciiEncoded ret;
1222   struct GNUNET_HashCode hc;
1223
1224   GNUNET_CRYPTO_hash(p, sizeof(*p), &hc);
1225   GNUNET_CRYPTO_hash_to_enc(&hc, &ret);
1226   ret.encoding[6] = '\0';
1227   return (const char *)ret.encoding;
1228 }
1229
1230
1231 /**
1232  * @ingroup logging
1233  * Convert a public key value to a string (for printing debug messages).
1234  * This is one of the very few calls in the entire API that is
1235  * NOT reentrant!
1236  *
1237  * @param hc the hash code
1238  * @return string
1239  */
1240 const char *
1241 GNUNET_p2s2(const struct GNUNET_CRYPTO_EddsaPublicKey *p)
1242 {
1243   static struct GNUNET_CRYPTO_HashAsciiEncoded ret;
1244   struct GNUNET_HashCode hc;
1245
1246   GNUNET_CRYPTO_hash(p, sizeof(*p), &hc);
1247   GNUNET_CRYPTO_hash_to_enc(&hc, &ret);
1248   ret.encoding[6] = '\0';
1249   return (const char *)ret.encoding;
1250 }
1251
1252
1253 /**
1254  * @ingroup logging
1255  * Convert a public key value to a string (for printing debug messages).
1256  * This is one of the very few calls in the entire API that is
1257  * NOT reentrant!
1258  *
1259  * @param hc the hash code
1260  * @return string
1261  */
1262 const char *
1263 GNUNET_e2s(const struct GNUNET_CRYPTO_EcdhePublicKey *p)
1264 {
1265   static struct GNUNET_CRYPTO_HashAsciiEncoded ret;
1266   struct GNUNET_HashCode hc;
1267
1268   GNUNET_CRYPTO_hash(p, sizeof(*p), &hc);
1269   GNUNET_CRYPTO_hash_to_enc(&hc, &ret);
1270   ret.encoding[6] = '\0';
1271   return (const char *)ret.encoding;
1272 }
1273
1274
1275 /**
1276  * @ingroup logging
1277  * Convert a public key value to a string (for printing debug messages).
1278  * This is one of the very few calls in the entire API that is
1279  * NOT reentrant!
1280  *
1281  * @param hc the hash code
1282  * @return string
1283  */
1284 const char *
1285 GNUNET_e2s2(const struct GNUNET_CRYPTO_EcdhePublicKey *p)
1286 {
1287   static struct GNUNET_CRYPTO_HashAsciiEncoded ret;
1288   struct GNUNET_HashCode hc;
1289
1290   GNUNET_CRYPTO_hash(p, sizeof(*p), &hc);
1291   GNUNET_CRYPTO_hash_to_enc(&hc, &ret);
1292   ret.encoding[6] = '\0';
1293   return (const char *)ret.encoding;
1294 }
1295
1296
1297 /**
1298  * @ingroup logging
1299  * Convert a short hash value to a string (for printing debug messages).
1300  * This is one of the very few calls in the entire API that is
1301  * NOT reentrant!
1302  *
1303  * @param shc the hash code
1304  * @return string
1305  */
1306 const char *
1307 GNUNET_sh2s(const struct GNUNET_ShortHashCode *shc)
1308 {
1309   static char buf[64];
1310
1311   GNUNET_STRINGS_data_to_string(shc, sizeof(*shc), buf, sizeof(buf));
1312   buf[6] = '\0';
1313   return (const char *)buf;
1314 }
1315
1316
1317 /**
1318  * @ingroup logging
1319  * Convert a UUID to a string (for printing debug messages).
1320  * This is one of the very few calls in the entire API that is
1321  * NOT reentrant!
1322  *
1323  * @param uuid the UUID
1324  * @return string
1325  */
1326 const char *
1327 GNUNET_uuid2s(const struct GNUNET_Uuid *uuid)
1328 {
1329   static char buf[32];
1330
1331   GNUNET_STRINGS_data_to_string(uuid, sizeof(*uuid), buf, sizeof(buf));
1332   buf[6] = '\0';
1333   return (const char *)buf;
1334 }
1335
1336
1337 /**
1338  * Convert a hash to a string (for printing debug messages).
1339  * This is one of the very few calls in the entire API that is
1340  * NOT reentrant!
1341  *
1342  * @param hc the hash code
1343  * @return string form; will be overwritten by next call to GNUNET_h2s_full.
1344  */
1345 const char *
1346 GNUNET_h2s_full(const struct GNUNET_HashCode *hc)
1347 {
1348   static struct GNUNET_CRYPTO_HashAsciiEncoded ret;
1349
1350   GNUNET_CRYPTO_hash_to_enc(hc, &ret);
1351   ret.encoding[sizeof(ret) - 1] = '\0';
1352   return (const char *)ret.encoding;
1353 }
1354
1355
1356 /**
1357  * Convert a peer identity to a string (for printing debug messages).
1358  *
1359  * @param pid the peer identity
1360  * @return string form of the pid; will be overwritten by next
1361  *         call to #GNUNET_i2s.
1362  */
1363 const char *
1364 GNUNET_i2s(const struct GNUNET_PeerIdentity *pid)
1365 {
1366   static GNUNET_THREAD_LOCAL char buf[5];
1367   char *ret;
1368
1369   if (NULL == pid)
1370     return "NULL";
1371   ret = GNUNET_CRYPTO_eddsa_public_key_to_string(&pid->public_key);
1372   GNUNET_strlcpy(buf, ret, sizeof(buf));
1373   GNUNET_free(ret);
1374   return buf;
1375 }
1376
1377
1378 /**
1379  * Convert a peer identity to a string (for printing debug messages).
1380  * Identical to #GNUNET_i2s(), except that another
1381  * buffer is used so both #GNUNET_i2s() and #GNUNET_i2s2() can be
1382  * used within the same log statement.
1383  *
1384  * @param pid the peer identity
1385  * @return string form of the pid; will be overwritten by next
1386  *         call to #GNUNET_i2s.
1387  */
1388 const char *
1389 GNUNET_i2s2(const struct GNUNET_PeerIdentity *pid)
1390 {
1391   static GNUNET_THREAD_LOCAL char buf[5];
1392   char *ret;
1393
1394   if (NULL == pid)
1395     return "NULL";
1396   ret = GNUNET_CRYPTO_eddsa_public_key_to_string(&pid->public_key);
1397   GNUNET_strlcpy(buf, ret, sizeof(buf));
1398   GNUNET_free(ret);
1399   return buf;
1400 }
1401
1402
1403 /**
1404  * Convert a peer identity to a string (for printing debug messages).
1405  *
1406  * @param pid the peer identity
1407  * @return string form of the pid; will be overwritten by next
1408  *         call to #GNUNET_i2s_full.
1409  */
1410 const char *
1411 GNUNET_i2s_full(const struct GNUNET_PeerIdentity *pid)
1412 {
1413   static GNUNET_THREAD_LOCAL char buf[256];
1414   char *ret;
1415
1416   ret = GNUNET_CRYPTO_eddsa_public_key_to_string(&pid->public_key);
1417   strcpy(buf, ret);
1418   GNUNET_free(ret);
1419   return buf;
1420 }
1421
1422
1423 /**
1424  * Convert a "struct sockaddr*" (IPv4 or IPv6 address) to a string
1425  * (for printing debug messages).  This is one of the very few calls
1426  * in the entire API that is NOT reentrant!
1427  *
1428  * @param addr the address
1429  * @param addrlen the length of the address in @a addr
1430  * @return nicely formatted string for the address
1431  *  will be overwritten by next call to #GNUNET_a2s.
1432  */
1433 const char *
1434 GNUNET_a2s(const struct sockaddr *addr, socklen_t addrlen)
1435 {
1436 #ifndef WINDOWS
1437 #define LEN                           \
1438   GNUNET_MAX((INET6_ADDRSTRLEN + 8), \
1439              (1 + sizeof(struct sockaddr_un) - sizeof(sa_family_t)))
1440 #else
1441 #define LEN (INET6_ADDRSTRLEN + 8)
1442 #endif
1443   static char buf[LEN];
1444 #undef LEN
1445   static char b2[6];
1446   const struct sockaddr_in *v4;
1447   const struct sockaddr_un *un;
1448   const struct sockaddr_in6 *v6;
1449   unsigned int off;
1450
1451   if (addr == NULL)
1452     return _("unknown address");
1453   switch (addr->sa_family)
1454     {
1455     case AF_INET:
1456       if (addrlen != sizeof(struct sockaddr_in))
1457         return "<invalid v4 address>";
1458       v4 = (const struct sockaddr_in *)addr;
1459       inet_ntop(AF_INET, &v4->sin_addr, buf, INET_ADDRSTRLEN);
1460       if (0 == ntohs(v4->sin_port))
1461         return buf;
1462       strcat(buf, ":");
1463       GNUNET_snprintf(b2, sizeof(b2), "%u", ntohs(v4->sin_port));
1464       strcat(buf, b2);
1465       return buf;
1466
1467     case AF_INET6:
1468       if (addrlen != sizeof(struct sockaddr_in6))
1469         return "<invalid v4 address>";
1470       v6 = (const struct sockaddr_in6 *)addr;
1471       buf[0] = '[';
1472       inet_ntop(AF_INET6, &v6->sin6_addr, &buf[1], INET6_ADDRSTRLEN);
1473       if (0 == ntohs(v6->sin6_port))
1474         return &buf[1];
1475       strcat(buf, "]:");
1476       GNUNET_snprintf(b2, sizeof(b2), "%u", ntohs(v6->sin6_port));
1477       strcat(buf, b2);
1478       return buf;
1479
1480     case AF_UNIX:
1481       if (addrlen <= sizeof(sa_family_t))
1482         return "<unbound UNIX client>";
1483       un = (const struct sockaddr_un *)addr;
1484       off = 0;
1485       if ('\0' == un->sun_path[0])
1486         off++;
1487       memset(buf, 0, sizeof(buf));
1488       GNUNET_snprintf(buf,
1489                       sizeof(buf),
1490                       "%s%.*s",
1491                       (1 == off) ? "@" : "",
1492                       (int)(addrlen - sizeof(sa_family_t) - off),
1493                       &un->sun_path[off]);
1494       return buf;
1495
1496     default:
1497       return _("invalid address");
1498     }
1499 }
1500
1501
1502 /**
1503  * Log error message about missing configuration option.
1504  *
1505  * @param kind log level
1506  * @param section section with missing option
1507  * @param option name of missing option
1508  */
1509 void
1510 GNUNET_log_config_missing(enum GNUNET_ErrorType kind,
1511                           const char *section,
1512                           const char *option)
1513 {
1514   GNUNET_log(kind,
1515              _(
1516                "Configuration fails to specify option `%s' in section `%s'!\n"),
1517              option,
1518              section);
1519 }
1520
1521
1522 /**
1523  * Log error message about invalid configuration option value.
1524  *
1525  * @param kind log level
1526  * @param section section with invalid option
1527  * @param option name of invalid option
1528  * @param required what is required that is invalid about the option
1529  */
1530 void
1531 GNUNET_log_config_invalid(enum GNUNET_ErrorType kind,
1532                           const char *section,
1533                           const char *option,
1534                           const char *required)
1535 {
1536   GNUNET_log(
1537     kind,
1538     _(
1539       "Configuration specifies invalid value for option `%s' in section `%s': %s\n"),
1540     option,
1541     section,
1542     required);
1543 }
1544
1545
1546 /**
1547  * Set the async scope for the current thread.
1548  *
1549  * @param aid the async scope identifier
1550  * @param old_scope[out] location to save the old scope
1551  */
1552 void
1553 GNUNET_async_scope_enter(const struct GNUNET_AsyncScopeId *aid,
1554                          struct GNUNET_AsyncScopeSave *old_scope)
1555 {
1556   *old_scope = current_async_scope;
1557   current_async_scope.have_scope = GNUNET_YES;
1558   current_async_scope.scope_id = *aid;
1559 }
1560
1561
1562 /**
1563  * Clear the current thread's async scope.
1564  *
1565  * @param old_scope scope to restore
1566  */
1567 void
1568 GNUNET_async_scope_restore(struct GNUNET_AsyncScopeSave *old_scope)
1569 {
1570   current_async_scope = *old_scope;
1571 }
1572
1573
1574 /**
1575  * Generate a fresh async scope identifier.
1576  *
1577  * @param[out] aid_ret pointer to where the result is stored
1578  */
1579 void
1580 GNUNET_async_scope_fresh(struct GNUNET_AsyncScopeId *aid_ret)
1581 {
1582   GNUNET_CRYPTO_random_block(GNUNET_CRYPTO_QUALITY_WEAK,
1583                              aid_ret,
1584                              sizeof(struct GNUNET_AsyncScopeId));
1585 }
1586
1587
1588 /**
1589  * Get the current async scope.
1590  *
1591  * @param[out] scope_ret pointer to where the result is stored
1592  */
1593 void
1594 GNUNET_async_scope_get(struct GNUNET_AsyncScopeSave *scope_ret)
1595 {
1596   *scope_ret = current_async_scope;
1597 }
1598
1599
1600 /**
1601  * Initializer
1602  */
1603 void __attribute__ ((constructor)) GNUNET_util_cl_init()
1604 {
1605   GNUNET_stderr = stderr;
1606 #ifdef MINGW
1607   GNInitWinEnv(NULL);
1608 #endif
1609 #if WINDOWS
1610   if (!InitializeCriticalSectionAndSpinCount(&output_message_cs, 0x00000400))
1611     GNUNET_abort_();
1612 #endif
1613 }
1614
1615
1616 /**
1617  * Destructor
1618  */
1619 void __attribute__ ((destructor)) GNUNET_util_cl_fini()
1620 {
1621 #if WINDOWS
1622   DeleteCriticalSection(&output_message_cs);
1623 #endif
1624 #ifdef MINGW
1625   GNShutdownWinEnv();
1626 #endif
1627 }
1628
1629 /* end of common_logging.c */