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