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