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