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