aboutsummaryrefslogtreecommitdiff
path: root/src/util/common_logging.c
diff options
context:
space:
mode:
authorMartin Schanzenbach <schanzen@gnunet.org>2023-10-18 13:37:38 +0200
committerMartin Schanzenbach <schanzen@gnunet.org>2023-10-18 13:37:38 +0200
commit9ef4abad615bea12d13be542b8ae5fbeb2dfee32 (patch)
tree8875a687e004d331c9ea6a1d511a328c72b88113 /src/util/common_logging.c
parente95236b3ed78cd597c15f34b89385295702b627f (diff)
downloadgnunet-9ef4abad615bea12d13be542b8ae5fbeb2dfee32.tar.gz
gnunet-9ef4abad615bea12d13be542b8ae5fbeb2dfee32.zip
NEWS: Refactoring components under src/ into lib/, plugin/, cli/ and service/
This also includes a necessary API refactoring of crypto from IDENTITY to UTIL.
Diffstat (limited to 'src/util/common_logging.c')
-rw-r--r--src/util/common_logging.c1512
1 files changed, 0 insertions, 1512 deletions
diff --git a/src/util/common_logging.c b/src/util/common_logging.c
deleted file mode 100644
index d27f70e83..000000000
--- a/src/util/common_logging.c
+++ /dev/null
@@ -1,1512 +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
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 int
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 */
728int
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, "%s-%d", comp, getpid ());
741 GNUNET_free (component_nopid);
742 component_nopid = GNUNET_strdup (comp);
743
744 env_logfile = getenv ("GNUNET_FORCE_LOGFILE");
745 if ((NULL != env_logfile) && (strlen (env_logfile) > 0))
746 logfile = env_logfile;
747 if (NULL == logfile)
748 return GNUNET_OK;
749 GNUNET_free (log_file_name);
750 log_file_name = GNUNET_STRINGS_filename_expand (logfile);
751 if (NULL == log_file_name)
752 return GNUNET_SYSERR;
753#if defined(GNUNET_CULL_LOGGING)
754 /* log file option not allowed for wallet logic */
755 GNUNET_assert (NULL == logfile);
756 return GNUNET_OK;
757#else
758 {
759 time_t t;
760 const struct tm *tm;
761
762 t = time (NULL);
763 tm = gmtime (&t);
764 return setup_log_file (tm);
765 }
766#endif
767}
768
769
770void
771GNUNET_logger_add (GNUNET_Logger logger, void *logger_cls)
772{
773 struct CustomLogger *entry;
774
775 entry = GNUNET_new (struct CustomLogger);
776 entry->logger = logger;
777 entry->logger_cls = logger_cls;
778 entry->next = loggers;
779 loggers = entry;
780}
781
782
783void
784GNUNET_logger_remove (GNUNET_Logger logger, void *logger_cls)
785{
786 struct CustomLogger *pos;
787 struct CustomLogger *prev;
788
789 prev = NULL;
790 pos = loggers;
791 while ((NULL != pos) &&
792 ((pos->logger != logger) || (pos->logger_cls != logger_cls)))
793 {
794 prev = pos;
795 pos = pos->next;
796 }
797 GNUNET_assert (NULL != pos);
798 if (NULL == prev)
799 loggers = pos->next;
800 else
801 prev->next = pos->next;
802 GNUNET_free (pos);
803}
804
805
806/**
807 * Actually output the log message.
808 *
809 * @param kind how severe was the issue
810 * @param comp component responsible
811 * @param datestr current date/time
812 * @param msg the actual message
813 */
814static void
815output_message (enum GNUNET_ErrorType kind,
816 const char *comp,
817 const char *datestr,
818 const char *msg)
819{
820 struct CustomLogger *pos;
821
822 /* only use the standard logger if no custom loggers are present */
823 if ((NULL != GNUNET_stderr) && (NULL == loggers))
824 {
825 if (kind == GNUNET_ERROR_TYPE_MESSAGE)
826 {
827 /* The idea here is to produce "normal" output messages
828 * for end users while still having the power of the
829 * logging engine for developer needs. So ideally this
830 * is what it should look like when CLI tools are used
831 * interactively, yet the same message shouldn't look
832 * this way if the output is going to logfiles or robots
833 * instead.
834 */fprintf (GNUNET_stderr, "* %s", msg);
835 }
836 else if (GNUNET_YES == current_async_scope.have_scope)
837 {
838 static GNUNET_THREAD_LOCAL char id_buf[27];
839 char *end;
840
841 /* We're logging, so skip_log must be currently 0. */
842 skip_log = 100;
843 end = GNUNET_STRINGS_data_to_string (&current_async_scope.scope_id,
844 sizeof(struct GNUNET_AsyncScopeId),
845 id_buf,
846 sizeof(id_buf) - 1);
847 GNUNET_assert (NULL != end);
848 *end = '\0';
849 skip_log = 0;
850 fprintf (GNUNET_stderr,
851 "%s %s(%s) %s %s",
852 datestr,
853 comp,
854 id_buf,
855 GNUNET_error_type_to_string (kind),
856 msg);
857 }
858 else
859 {
860 fprintf (GNUNET_stderr,
861 "%s %s %s %s",
862 datestr,
863 comp,
864 GNUNET_error_type_to_string (kind),
865 msg);
866 }
867 fflush (GNUNET_stderr);
868 }
869 pos = loggers;
870 while (NULL != pos)
871 {
872 pos->logger (pos->logger_cls, kind, comp, datestr, msg);
873 pos = pos->next;
874 }
875}
876
877
878/**
879 * Flush an existing bulk report to the output.
880 *
881 * @param datestr our current timestamp
882 */
883static void
884flush_bulk (const char *datestr)
885{
886 char msg[DATE_STR_SIZE + BULK_TRACK_SIZE + 256];
887 int rev;
888 char *last;
889 const char *ft;
890
891 if ((0 == last_bulk_time.abs_value_us) || (0 == last_bulk_repeat))
892 return;
893 rev = 0;
894 last = memchr (last_bulk, '\0', BULK_TRACK_SIZE);
895 if (last == NULL)
896 last = &last_bulk[BULK_TRACK_SIZE - 1];
897 else if (last != last_bulk)
898 last--;
899 if (last[0] == '\n')
900 {
901 rev = 1;
902 last[0] = '\0';
903 }
904 ft =
905 GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_duration (
906 last_bulk_time),
907 GNUNET_YES);
908 snprintf (msg,
909 sizeof(msg),
910 _ ("Message `%.*s' repeated %u times in the last %s\n"),
911 BULK_TRACK_SIZE,
912 last_bulk,
913 last_bulk_repeat,
914 ft);
915 if (rev == 1)
916 last[0] = '\n';
917 output_message (last_bulk_kind, last_bulk_comp, datestr, msg);
918 last_bulk_time = GNUNET_TIME_absolute_get ();
919 last_bulk_repeat = 0;
920}
921
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",
1019 tmptr))
1020 abort ();
1021 /* Fill in microseconds */
1022 if (0 > snprintf (date, sizeof(date), date2, timeofday.tv_usec))
1023 abort ();
1024 }
1025
1026 vsnprintf (buf, size, message, va);
1027#if ! defined(GNUNET_CULL_LOGGING)
1028 if (NULL != tmptr)
1029 (void) setup_log_file (tmptr);
1030#endif
1031 if ((0 != (kind & GNUNET_ERROR_TYPE_BULK)) &&
1032 (0 != last_bulk_time.abs_value_us) &&
1033 (0 == strncmp (buf, last_bulk, sizeof(last_bulk))))
1034 {
1035 last_bulk_repeat++;
1036 if ((GNUNET_TIME_absolute_get_duration (last_bulk_time).rel_value_us >
1037 BULK_DELAY_THRESHOLD) ||
1038 (last_bulk_repeat > BULK_REPEAT_THRESHOLD))
1039 flush_bulk (date);
1040 return;
1041 }
1042 flush_bulk (date);
1043 GNUNET_strlcpy (last_bulk, buf, sizeof(last_bulk));
1044 last_bulk_repeat = 0;
1045 last_bulk_kind = kind;
1046 last_bulk_time = GNUNET_TIME_absolute_get ();
1047 GNUNET_strlcpy (last_bulk_comp, comp, sizeof(last_bulk_comp));
1048 output_message (kind, comp, date, buf);
1049 }
1050}
1051
1052
1053/**
1054 * Main log function.
1055 *
1056 * @param kind how serious is the error?
1057 * @param message what is the message (format string)
1058 * @param ... arguments for format string
1059 */
1060void
1061GNUNET_log_nocheck (enum GNUNET_ErrorType kind, const char *message, ...)
1062{
1063 va_list va;
1064
1065 va_start (va, message);
1066 mylog (kind, component, message, va);
1067 va_end (va);
1068}
1069
1070
1071/**
1072 * Log function that specifies an alternative component.
1073 * This function should be used by plugins.
1074 *
1075 * @param kind how serious is the error?
1076 * @param comp component responsible for generating the message
1077 * @param message what is the message (format string)
1078 * @param ... arguments for format string
1079 */
1080void
1081GNUNET_log_from_nocheck (enum GNUNET_ErrorType kind,
1082 const char *comp,
1083 const char *message,
1084 ...)
1085{
1086 va_list va;
1087 char comp_w_pid[128];
1088
1089 if (comp == NULL)
1090 comp = component_nopid;
1091
1092 va_start (va, message);
1093 GNUNET_snprintf (comp_w_pid, sizeof(comp_w_pid), "%s-%d", comp, getpid ());
1094 mylog (kind, comp_w_pid, message, va);
1095 va_end (va);
1096}
1097
1098
1099const char *
1100GNUNET_error_type_to_string (enum GNUNET_ErrorType kind)
1101{
1102 if ((kind & GNUNET_ERROR_TYPE_ERROR) > 0)
1103 return _ ("ERROR");
1104 if ((kind & GNUNET_ERROR_TYPE_WARNING) > 0)
1105 return _ ("WARNING");
1106 if ((kind & GNUNET_ERROR_TYPE_MESSAGE) > 0)
1107 return _ ("MESSAGE");
1108 if ((kind & GNUNET_ERROR_TYPE_INFO) > 0)
1109 return _ ("INFO");
1110 if ((kind & GNUNET_ERROR_TYPE_DEBUG) > 0)
1111 return _ ("DEBUG");
1112 if ((kind & ~GNUNET_ERROR_TYPE_BULK) == 0)
1113 return _ ("NONE");
1114 return _ ("INVALID");
1115}
1116
1117
1118/**
1119 * Convert a hash to a string (for printing debug messages).
1120 *
1121 * @param hc the hash code
1122 * @return string form; will be overwritten by next call to GNUNET_h2s.
1123 */
1124const char *
1125GNUNET_h2s (const struct GNUNET_HashCode *hc)
1126{
1127 static GNUNET_THREAD_LOCAL struct GNUNET_CRYPTO_HashAsciiEncoded ret;
1128
1129 GNUNET_CRYPTO_hash_to_enc (hc, &ret);
1130 ret.encoding[8] = '\0';
1131 return (const char *) ret.encoding;
1132}
1133
1134
1135/**
1136 * Convert a hash to a string (for printing debug messages).
1137 * This is one of the very few calls in the entire API that is
1138 * NOT reentrant! Identical to #GNUNET_h2s(), except that another
1139 * buffer is used so both #GNUNET_h2s() and #GNUNET_h2s2() can be
1140 * used within the same log statement.
1141 *
1142 * @param hc the hash code
1143 * @return string form; will be overwritten by next call to GNUNET_h2s.
1144 */
1145const char *
1146GNUNET_h2s2 (const struct GNUNET_HashCode *hc)
1147{
1148 static GNUNET_THREAD_LOCAL struct GNUNET_CRYPTO_HashAsciiEncoded ret;
1149
1150 GNUNET_CRYPTO_hash_to_enc (hc, &ret);
1151 ret.encoding[8] = '\0';
1152 return (const char *) ret.encoding;
1153}
1154
1155
1156const char *
1157GNUNET_p2s (const struct GNUNET_CRYPTO_EddsaPublicKey *p)
1158{
1159 static GNUNET_THREAD_LOCAL struct GNUNET_CRYPTO_HashAsciiEncoded ret;
1160 struct GNUNET_HashCode hc;
1161
1162 GNUNET_CRYPTO_hash (p, sizeof(*p), &hc);
1163 GNUNET_CRYPTO_hash_to_enc (&hc, &ret);
1164 ret.encoding[6] = '\0';
1165 return (const char *) ret.encoding;
1166}
1167
1168
1169const char *
1170GNUNET_p2s2 (const struct GNUNET_CRYPTO_EddsaPublicKey *p)
1171{
1172 static GNUNET_THREAD_LOCAL struct GNUNET_CRYPTO_HashAsciiEncoded ret;
1173 struct GNUNET_HashCode hc;
1174
1175 GNUNET_CRYPTO_hash (p, sizeof(*p), &hc);
1176 GNUNET_CRYPTO_hash_to_enc (&hc, &ret);
1177 ret.encoding[6] = '\0';
1178 return (const char *) ret.encoding;
1179}
1180
1181
1182const char *
1183GNUNET_e2s (const struct GNUNET_CRYPTO_EcdhePublicKey *p)
1184{
1185 static GNUNET_THREAD_LOCAL struct GNUNET_CRYPTO_HashAsciiEncoded ret;
1186 struct GNUNET_HashCode hc;
1187
1188 GNUNET_CRYPTO_hash (p, sizeof(*p), &hc);
1189 GNUNET_CRYPTO_hash_to_enc (&hc, &ret);
1190 ret.encoding[6] = '\0';
1191 return (const char *) ret.encoding;
1192}
1193
1194
1195const char *
1196GNUNET_e2s2 (const struct GNUNET_CRYPTO_EcdhePublicKey *p)
1197{
1198 static GNUNET_THREAD_LOCAL struct GNUNET_CRYPTO_HashAsciiEncoded ret;
1199 struct GNUNET_HashCode hc;
1200
1201 GNUNET_CRYPTO_hash (p, sizeof(*p), &hc);
1202 GNUNET_CRYPTO_hash_to_enc (&hc, &ret);
1203 ret.encoding[6] = '\0';
1204 return (const char *) ret.encoding;
1205}
1206
1207
1208/**
1209 * @ingroup logging
1210 * Convert a short hash value to a string (for printing debug messages).
1211 * This is one of the very few calls in the entire API that is
1212 * NOT reentrant!
1213 *
1214 * @param shc the hash code
1215 * @return string
1216 */
1217const char *
1218GNUNET_sh2s (const struct GNUNET_ShortHashCode *shc)
1219{
1220 static GNUNET_THREAD_LOCAL char buf[64];
1221
1222 GNUNET_STRINGS_data_to_string (shc, sizeof(*shc), buf, sizeof(buf));
1223 buf[6] = '\0';
1224 return (const char *) buf;
1225}
1226
1227
1228/**
1229 * @ingroup logging
1230 * Convert a UUID 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 uuid the UUID
1235 * @return string
1236 */
1237const char *
1238GNUNET_uuid2s (const struct GNUNET_Uuid *uuid)
1239{
1240 static GNUNET_THREAD_LOCAL char buf[32];
1241
1242 GNUNET_STRINGS_data_to_string (uuid, sizeof(*uuid), buf, sizeof(buf));
1243 buf[6] = '\0';
1244 return (const char *) buf;
1245}
1246
1247
1248/**
1249 * Convert a hash to a string (for printing debug messages).
1250 * This is one of the very few calls in the entire API that is
1251 * NOT reentrant!
1252 *
1253 * @param hc the hash code
1254 * @return string form; will be overwritten by next call to GNUNET_h2s_full.
1255 */
1256const char *
1257GNUNET_h2s_full (const struct GNUNET_HashCode *hc)
1258{
1259 static GNUNET_THREAD_LOCAL struct GNUNET_CRYPTO_HashAsciiEncoded ret;
1260
1261 GNUNET_CRYPTO_hash_to_enc (hc, &ret);
1262 ret.encoding[sizeof(ret) - 1] = '\0';
1263 return (const char *) ret.encoding;
1264}
1265
1266
1267/**
1268 * Convert a peer identity to a string (for printing debug messages).
1269 *
1270 * @param pid the peer identity
1271 * @return string form of the pid; will be overwritten by next
1272 * call to #GNUNET_i2s.
1273 */
1274const char *
1275GNUNET_i2s (const struct GNUNET_PeerIdentity *pid)
1276{
1277 static GNUNET_THREAD_LOCAL char buf[5];
1278 char *ret;
1279
1280 if (NULL == pid)
1281 return "NULL";
1282 ret = GNUNET_CRYPTO_eddsa_public_key_to_string (&pid->public_key);
1283 GNUNET_strlcpy (buf, ret, sizeof(buf));
1284 GNUNET_free (ret);
1285 return buf;
1286}
1287
1288
1289/**
1290 * Convert a peer identity to a string (for printing debug messages).
1291 * Identical to #GNUNET_i2s(), except that another
1292 * buffer is used so both #GNUNET_i2s() and #GNUNET_i2s2() can be
1293 * used within the same log statement.
1294 *
1295 * @param pid the peer identity
1296 * @return string form of the pid; will be overwritten by next
1297 * call to #GNUNET_i2s.
1298 */
1299const char *
1300GNUNET_i2s2 (const struct GNUNET_PeerIdentity *pid)
1301{
1302 static GNUNET_THREAD_LOCAL char buf[5];
1303 char *ret;
1304
1305 if (NULL == pid)
1306 return "NULL";
1307 ret = GNUNET_CRYPTO_eddsa_public_key_to_string (&pid->public_key);
1308 GNUNET_strlcpy (buf, ret, sizeof(buf));
1309 GNUNET_free (ret);
1310 return buf;
1311}
1312
1313
1314/**
1315 * Convert a peer identity to a string (for printing debug messages).
1316 *
1317 * @param pid the peer identity
1318 * @return string form of the pid; will be overwritten by next
1319 * call to #GNUNET_i2s_full.
1320 */
1321const char *
1322GNUNET_i2s_full (const struct GNUNET_PeerIdentity *pid)
1323{
1324 static GNUNET_THREAD_LOCAL char buf[256];
1325 char *ret;
1326
1327 ret = GNUNET_CRYPTO_eddsa_public_key_to_string (&pid->public_key);
1328 strcpy (buf, ret);
1329 GNUNET_free (ret);
1330 return buf;
1331}
1332
1333
1334/**
1335 * Convert a "struct sockaddr*" (IPv4 or IPv6 address) to a string
1336 * (for printing debug messages). This is one of the very few calls
1337 * in the entire API that is NOT reentrant!
1338 *
1339 * @param addr the address
1340 * @param addrlen the length of the address in @a addr
1341 * @return nicely formatted string for the address
1342 * will be overwritten by next call to #GNUNET_a2s.
1343 */
1344const char *
1345GNUNET_a2s (const struct sockaddr *addr, socklen_t addrlen)
1346{
1347#define LEN \
1348 GNUNET_MAX ((INET6_ADDRSTRLEN + 8), \
1349 (1 + sizeof(struct sockaddr_un) - sizeof(sa_family_t)))
1350 static GNUNET_THREAD_LOCAL char buf[LEN];
1351#undef LEN
1352 static GNUNET_THREAD_LOCAL char b2[6];
1353 const struct sockaddr_in *v4;
1354 const struct sockaddr_un *un;
1355 const struct sockaddr_in6 *v6;
1356 unsigned int off;
1357
1358 if (addr == NULL)
1359 return _ ("unknown address");
1360 switch (addr->sa_family)
1361 {
1362 case AF_INET:
1363 if (addrlen != sizeof(struct sockaddr_in))
1364 return "<invalid v4 address>";
1365 v4 = (const struct sockaddr_in *) addr;
1366 inet_ntop (AF_INET, &v4->sin_addr, buf, INET_ADDRSTRLEN);
1367 if (0 == ntohs (v4->sin_port))
1368 return buf;
1369 strcat (buf, ":");
1370 GNUNET_snprintf (b2, sizeof(b2), "%u", ntohs (v4->sin_port));
1371 strcat (buf, b2);
1372 return buf;
1373
1374 case AF_INET6:
1375 if (addrlen != sizeof(struct sockaddr_in6))
1376 return "<invalid v6 address>";
1377 v6 = (const struct sockaddr_in6 *) addr;
1378 buf[0] = '[';
1379 inet_ntop (AF_INET6, &v6->sin6_addr, &buf[1], INET6_ADDRSTRLEN);
1380 if (0 == ntohs (v6->sin6_port))
1381 return &buf[1];
1382 strcat (buf, "]:");
1383 GNUNET_snprintf (b2, sizeof(b2), "%u", ntohs (v6->sin6_port));
1384 strcat (buf, b2);
1385 return buf;
1386
1387 case AF_UNIX:
1388 if (addrlen <= sizeof(sa_family_t))
1389 return "<unbound UNIX client>";
1390 un = (const struct sockaddr_un *) addr;
1391 off = 0;
1392 if ('\0' == un->sun_path[0])
1393 off++;
1394 memset (buf, 0, sizeof(buf));
1395 GNUNET_snprintf (buf,
1396 sizeof(buf),
1397 "%s%.*s",
1398 (1 == off) ? "@" : "",
1399 (int) (addrlen - sizeof(sa_family_t) - off),
1400 &un->sun_path[off]);
1401 return buf;
1402
1403 default:
1404 return _ ("invalid address");
1405 }
1406}
1407
1408
1409void
1410GNUNET_log_config_missing (enum GNUNET_ErrorType kind,
1411 const char *section,
1412 const char *option)
1413{
1414 GNUNET_log (kind,
1415 _ (
1416 "Configuration fails to specify option `%s' in section `%s'!\n"),
1417 option,
1418 section);
1419}
1420
1421
1422void
1423GNUNET_log_config_invalid (enum GNUNET_ErrorType kind,
1424 const char *section,
1425 const char *option,
1426 const char *required)
1427{
1428 GNUNET_log (
1429 kind,
1430 _ (
1431 "Configuration specifies invalid value for option `%s' in section `%s': %s\n"),
1432 option,
1433 section,
1434 required);
1435}
1436
1437
1438/**
1439 * Set the async scope for the current thread.
1440 *
1441 * @param aid the async scope identifier
1442 * @param[out] old_scope location to save the old scope
1443 */
1444void
1445GNUNET_async_scope_enter (const struct GNUNET_AsyncScopeId *aid,
1446 struct GNUNET_AsyncScopeSave *old_scope)
1447{
1448 *old_scope = current_async_scope;
1449 current_async_scope.have_scope = GNUNET_YES;
1450 current_async_scope.scope_id = *aid;
1451}
1452
1453
1454/**
1455 * Clear the current thread's async scope.
1456 *
1457 * @param old_scope scope to restore
1458 */
1459void
1460GNUNET_async_scope_restore (struct GNUNET_AsyncScopeSave *old_scope)
1461{
1462 current_async_scope = *old_scope;
1463}
1464
1465
1466/**
1467 * Generate a fresh async scope identifier.
1468 *
1469 * @param[out] aid_ret pointer to where the result is stored
1470 */
1471void
1472GNUNET_async_scope_fresh (struct GNUNET_AsyncScopeId *aid_ret)
1473{
1474 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
1475 aid_ret,
1476 sizeof(struct GNUNET_AsyncScopeId));
1477}
1478
1479
1480/**
1481 * Get the current async scope.
1482 *
1483 * @param[out] scope_ret pointer to where the result is stored
1484 */
1485void
1486GNUNET_async_scope_get (struct GNUNET_AsyncScopeSave *scope_ret)
1487{
1488 *scope_ret = current_async_scope;
1489}
1490
1491
1492/**
1493 * Initializer
1494 */
1495void __attribute__ ((constructor))
1496GNUNET_util_cl_init ()
1497{
1498 GNUNET_stderr = stderr;
1499}
1500
1501
1502/**
1503 * Destructor
1504 */
1505void __attribute__ ((destructor))
1506GNUNET_util_cl_fini ()
1507{
1508
1509}
1510
1511
1512/* end of common_logging.c */