X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=src%2Futil%2Fcommon_logging.c;h=5b355b2e1d570ee3c8a23382c0762075657e7b41;hb=72c8645af31896829b674b575c5375706f362a30;hp=503fb671de77659a92641da06b90586c8188d3ef;hpb=c44ec6c4cbc9534a3c7f5c0de9406c00305f8f52;p=oweals%2Fgnunet.git diff --git a/src/util/common_logging.c b/src/util/common_logging.c index 503fb671d..5b355b2e1 100644 --- a/src/util/common_logging.c +++ b/src/util/common_logging.c @@ -30,6 +30,8 @@ #include "gnunet_strings_lib.h" #include "gnunet_time_lib.h" +#include + /** * After how many milliseconds do we always print * that "message X was repeated N times"? Use 12h. @@ -61,6 +63,19 @@ */ #define DATE_STR_SIZE 64 +/** + * How many log files to keep? + */ +#define ROTATION_KEEP 3 + +#ifndef PATH_MAX +/** + * Assumed maximum path length (for the log file name). + */ +#define PATH_MAX 4096 +#endif + + /** * Linked list of active loggers. */ @@ -119,6 +134,11 @@ static char *component; */ static char *component_nopid; +/** + * Format string describing the name of the log file. + */ +static char *log_file_name; + /** * Minimum log level. */ @@ -132,7 +152,7 @@ static struct CustomLogger *loggers; /** * Number of log calls to ignore. */ -unsigned int skip_log; +int skip_log = 0; /** * File descriptor to use for "stderr", or NULL for none. @@ -145,24 +165,19 @@ static FILE *GNUNET_stderr; struct LogDef { /** - * Component name. NULL means that this definition matches any component - */ - char *component; - - /** - * File name. NULL means that this definition matches any file + * Component name regex */ - char *file; + regex_t component_regex; /** - * Stores strlen(file) + * File name regex */ - int strlen_file; + regex_t file_regex; /** - * Function name. NULL means that this definition matches any function + * Function name regex */ - char *function; + regex_t function_regex; /** * Lowest line at which this definition matches. @@ -193,40 +208,41 @@ struct LogDef /** * Dynamic array of logging definitions */ -struct LogDef *logdefs = NULL; +static struct LogDef *logdefs; /** * Allocated size of logdefs array (in units) */ -int logdefs_size = 0; +static int logdefs_size; /** * The number of units used in logdefs array. */ -int logdefs_len = 0; +static int logdefs_len; /** * GNUNET_YES if GNUNET_LOG environment variable is already parsed. */ -int gnunet_log_parsed = GNUNET_NO; +static int gnunet_log_parsed; /** * GNUNET_YES if GNUNET_FORCE_LOG environment variable is already parsed. */ -int gnunet_force_log_parsed = GNUNET_NO; +static int gnunet_force_log_parsed; /** * GNUNET_YES if at least one definition with forced == 1 is available. */ -int gnunet_force_log_present = GNUNET_NO; +static int gnunet_force_log_present; #ifdef WINDOWS /** * Contains the number of performance counts per second. */ -LARGE_INTEGER performance_frequency; +static LARGE_INTEGER performance_frequency; #endif + /** * Convert a textual description of a loglevel * to the respective GNUNET_GE_KIND. @@ -237,7 +253,7 @@ LARGE_INTEGER performance_frequency; static enum GNUNET_ErrorType get_type (const char *log) { - if (log == NULL) + if (NULL == log) return GNUNET_ERROR_TYPE_UNSPECIFIED; if (0 == strcasecmp (log, _("DEBUG"))) return GNUNET_ERROR_TYPE_DEBUG; @@ -252,6 +268,7 @@ get_type (const char *log) return GNUNET_ERROR_TYPE_INVALID; } + #if !defined(GNUNET_CULL_LOGGING) /** * Utility function - reallocates logdefs array to be twice as large. @@ -263,6 +280,126 @@ resize_logdefs () logdefs = GNUNET_realloc (logdefs, logdefs_size * sizeof (struct LogDef)); } + +/** + * Abort the process, generate a core dump if possible. + */ +void +GNUNET_abort () +{ +#if WINDOWS + DebugBreak (); +#endif + abort (); +} + + +/** + * Rotate logs, deleting the oldest log. + * + * @param new_name new name to add to the rotation + */ +static void +log_rotate (const char *new_name) +{ + static char *rotation[ROTATION_KEEP]; + static unsigned int rotation_off; + char *discard; + + if ('\0' == *new_name) + return; /* not a real log file name */ + discard = rotation[rotation_off % ROTATION_KEEP]; + if (NULL != discard) + { + /* Note: can't log errors during logging (recursion!), so this + operation MUST silently fail... */ + (void) UNLINK (discard); + GNUNET_free (discard); + } + rotation[rotation_off % ROTATION_KEEP] = GNUNET_strdup (new_name); + rotation_off++; +} + + +/** + * Setup the log file. + * + * @param tm timestamp for which we should setup logging + * @return GNUNET_OK on success, GNUNET_SYSERR on error + */ +static int +setup_log_file (const struct tm *tm) +{ + static char last_fn[PATH_MAX + 1]; + char fn[PATH_MAX + 1]; + int dirwarn; + int altlog_fd; + int dup_return; + FILE *altlog; + char *leftsquare; + + if (NULL == log_file_name) + return GNUNET_SYSERR; + if (0 == strftime (fn, sizeof (fn), log_file_name, tm)) + return GNUNET_SYSERR; + leftsquare = strrchr (fn, '['); + if ( (NULL != leftsquare) && (']' == leftsquare[1]) ) + { + char *logfile_copy = GNUNET_strdup (fn); + logfile_copy[leftsquare - fn] = '\0'; + logfile_copy[leftsquare - fn + 1] = '\0'; + snprintf (fn, PATH_MAX, "%s%d%s", + logfile_copy, getpid (), &logfile_copy[leftsquare - fn + 2]); + GNUNET_free (logfile_copy); + } + if (0 == strcmp (fn, last_fn)) + return GNUNET_OK; /* no change */ + log_rotate (last_fn); + strcpy (last_fn, fn); + dirwarn = (GNUNET_OK != GNUNET_DISK_directory_create_for_file (fn)); +#if WINDOWS + altlog_fd = OPEN (fn, O_APPEND | + O_BINARY | + O_WRONLY | O_CREAT, + _S_IREAD | _S_IWRITE); +#else + altlog_fd = OPEN (fn, O_APPEND | + O_WRONLY | O_CREAT, + S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); +#endif + if (-1 != altlog_fd) + { + if (NULL != GNUNET_stderr) + fclose (GNUNET_stderr); + dup_return = dup2 (altlog_fd, 2); + (void) close (altlog_fd); + if (-1 != dup_return) + { + altlog = fdopen (2, "ab"); + if (NULL == altlog) + { + (void) close (2); + altlog_fd = -1; + } + } + else + { + altlog_fd = -1; + } + } + if (-1 == altlog_fd) + { + GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "open", fn); + if (dirwarn) + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _("Failed to create or access directory for log file `%s'\n"), + fn); + return GNUNET_SYSERR; + } + GNUNET_stderr = altlog; + return GNUNET_OK; +} + /** * Utility function - adds a parsed definition to logdefs array. * @@ -273,31 +410,48 @@ resize_logdefs () * @param to_line see struct LogDef * @param level see struct LogDef, must be >= 0 * @param force see struct LogDef + * @return 0 on success, regex-specific error otherwise */ -static void +static int add_definition (char *component, char *file, char *function, int from_line, - int to_line, int level, int force) + int to_line, int level, int force) { + struct LogDef n; + int r; + if (logdefs_size == logdefs_len) resize_logdefs (); - struct LogDef n; memset (&n, 0, sizeof (n)); - if (strlen (component) > 0 && component[0] != '*') - n.component = strdup (component); - if (strlen (file) > 0 && file[0] != '*') - { - n.file = strdup (file); - n.strlen_file = strlen (file); - } - if ( (NULL != function) && - (strlen (function) > 0) && - (function[0] != '*') ) - n.function = strdup (function); + if (0 == strlen (component)) + component = (char *) ".*"; + r = regcomp (&n.component_regex, (const char *) component, REG_NOSUB); + if (0 != r) + { + return r; + } + if (0 == strlen (file)) + file = (char *) ".*"; + r = regcomp (&n.file_regex, (const char *) file, REG_NOSUB); + if (0 != r) + { + regfree (&n.component_regex); + return r; + } + if ((NULL == function) || (0 == strlen (function))) + function = (char *) ".*"; + r = regcomp (&n.function_regex, (const char *) function, REG_NOSUB); + if (0 != r) + { + regfree (&n.component_regex); + regfree (&n.file_regex); + return r; + } n.from_line = from_line; n.to_line = to_line; n.level = level; n.force = force; logdefs[logdefs_len++] = n; + return 0; } @@ -316,41 +470,37 @@ add_definition (char *component, char *file, char *function, int from_line, */ int GNUNET_get_log_call_status (int caller_level, const char *comp, - const char *file, const char *function, int line) + const char *file, const char *function, int line) { struct LogDef *ld; int i; int force_only; - size_t strlen_file; - if (comp == NULL) + if (NULL == comp) /* Use default component */ comp = component_nopid; /* We have no definitions to override globally configured log level, * so just use it right away. */ - if (min_level >= 0 && gnunet_force_log_present == GNUNET_NO) + if ( (min_level >= 0) && (GNUNET_NO == gnunet_force_log_present) ) return caller_level <= min_level; /* Only look for forced definitions? */ force_only = min_level >= 0; - strlen_file = strlen (file); for (i = 0; i < logdefs_len; i++) + { + ld = &logdefs[i]; + if (( (!force_only) || ld->force) && + (line >= ld->from_line && line <= ld->to_line) && + (0 == regexec (&ld->component_regex, comp, 0, NULL, 0)) && + (0 == regexec (&ld->file_regex, file, 0, NULL, 0)) && + (0 == regexec (&ld->function_regex, function, 0, NULL, 0))) { - ld = &logdefs[i]; - if ((!force_only || ld->force) && - (line >= ld->from_line && line <= ld->to_line) && - (ld->component == NULL || strcmp (comp, ld->component) == 0) && - (ld->file == NULL || - (ld->strlen_file <= strlen_file && - strcmp (&file[strlen_file - ld->strlen_file], ld->file) == 0)) && - (ld->function == NULL || strcmp (function, ld->function) == 0)) - { - /* We're finished */ - return caller_level <= ld->level; - } + /* We're finished */ + return caller_level <= ld->level; } + } /* No matches - use global level, if defined */ if (min_level >= 0) return caller_level <= min_level; @@ -381,7 +531,7 @@ GNUNET_get_log_call_status (int caller_level, const char *comp, * * @param constname name of the environment variable from which to get the * string to be parsed - * @param force 1 if definitions found in @constname are to be forced + * @param force 1 if definitions found in constname are to be forced * @return number of added definitions */ static int @@ -400,112 +550,115 @@ parse_definitions (const char *constname, int force) int from_line, to_line; int counter = 0; int keep_looking = 1; + tmp = getenv (constname); - if (tmp == NULL) + if (NULL == tmp) return 0; - def = strdup (tmp); - level = -1; + def = GNUNET_strdup (tmp); from_line = 0; to_line = INT_MAX; for (p = def, state = 0, start = def; keep_looking; p++) + { + switch (p[0]) { - switch (p[0]) - { - case ';': /* found a field separator */ - p[0] = '\0'; - switch (state) - { - case 0: /* within a component name */ - comp = start; - break; - case 1: /* within a file name */ - file = start; - break; - case 2: /* within a function name */ - /* after a file name there must be a function name */ - function = start; - break; - case 3: /* within a from-to line range */ - if (strlen (start) > 0) - { - errno = 0; - from_line = strtol (start, &t, 10); - if (errno != 0 || from_line < 0) - { - free (def); - return counter; - } - if (t < p && t[0] == '-') - { - errno = 0; - start = t + 1; - to_line = strtol (start, &t, 10); - if (errno != 0 || to_line < 0 || t != p) - { - free (def); - return counter; - } - } - else /* one number means "match this line only" */ - to_line = from_line; - } - else /* default to 0-max */ - { - from_line = 0; - to_line = INT_MAX; - } - break; - } - start = p + 1; - state += 1; - break; - case '\0': /* found EOL */ - keep_looking = 0; - /* fall through to '/' */ - case '/': /* found a definition separator */ - switch (state) - { - case 4: /* within a log level */ - p[0] = '\0'; - state = 0; - level = get_type ((const char *) start); - if (level == GNUNET_ERROR_TYPE_INVALID - || level == GNUNET_ERROR_TYPE_UNSPECIFIED) - { - free (def); - return counter; - } - add_definition (comp, file, function, from_line, to_line, level, - force); - counter += 1; - start = p + 1; - break; - default: - break; - } - default: - break; - } + case ';': /* found a field separator */ + p[0] = '\0'; + switch (state) + { + case 0: /* within a component name */ + comp = start; + break; + case 1: /* within a file name */ + file = start; + break; + case 2: /* within a function name */ + /* after a file name there must be a function name */ + function = start; + break; + case 3: /* within a from-to line range */ + if (strlen (start) > 0) + { + errno = 0; + from_line = strtol (start, &t, 10); + if ( (0 != errno) || (from_line < 0) ) + { + GNUNET_free (def); + return counter; + } + if ( (t < p) && ('-' == t[0]) ) + { + errno = 0; + start = t + 1; + to_line = strtol (start, &t, 10); + if ( (0 != errno) || (to_line < 0) || (t != p) ) + { + GNUNET_free (def); + return counter; + } + } + else /* one number means "match this line only" */ + to_line = from_line; + } + else /* default to 0-max */ + { + from_line = 0; + to_line = INT_MAX; + } + break; + } + start = p + 1; + state++; + break; + case '\0': /* found EOL */ + keep_looking = 0; + /* fall through to '/' */ + case '/': /* found a definition separator */ + switch (state) + { + case 4: /* within a log level */ + p[0] = '\0'; + state = 0; + level = get_type ((const char *) start); + if ( (GNUNET_ERROR_TYPE_INVALID == level) || + (GNUNET_ERROR_TYPE_UNSPECIFIED == level) || + (0 != add_definition (comp, file, function, from_line, to_line, + level, force)) ) + { + GNUNET_free (def); + return counter; + } + counter++; + start = p + 1; + break; + default: + break; + } + default: + break; } - free (def); + } + GNUNET_free (def); return counter; } + /** * Utility function - parses GNUNET_LOG and GNUNET_FORCE_LOG. */ static void parse_all_definitions () { - if (gnunet_log_parsed == GNUNET_NO) + if (GNUNET_NO == gnunet_log_parsed) parse_definitions ("GNUNET_LOG", 0); gnunet_log_parsed = GNUNET_YES; - if (gnunet_force_log_parsed == GNUNET_NO) + if (GNUNET_NO == gnunet_force_log_parsed) gnunet_force_log_present = - parse_definitions ("GNUNET_FORCE_LOG", 1) > 0 ? GNUNET_YES : GNUNET_NO; + parse_definitions ("GNUNET_FORCE_LOG", 1) > 0 ? GNUNET_YES : GNUNET_NO; gnunet_force_log_parsed = GNUNET_YES; } #endif + + /** * Setup logging. * @@ -517,10 +670,9 @@ parse_all_definitions () int GNUNET_log_setup (const char *comp, const char *loglevel, const char *logfile) { - FILE *altlog; - int dirwarn; - char *fn; - const char *env_logfile = NULL; + const char *env_logfile; + const struct tm *tm; + time_t t; min_level = get_type (loglevel); #if !defined(GNUNET_CULL_LOGGING) @@ -532,37 +684,23 @@ GNUNET_log_setup (const char *comp, const char *loglevel, const char *logfile) GNUNET_free_non_null (component); GNUNET_asprintf (&component, "%s-%d", comp, getpid ()); GNUNET_free_non_null (component_nopid); - component_nopid = strdup (comp); + component_nopid = GNUNET_strdup (comp); env_logfile = getenv ("GNUNET_FORCE_LOGFILE"); - if (env_logfile != NULL) + if ((NULL != env_logfile) && (strlen (env_logfile) > 0)) logfile = env_logfile; - - if (logfile == NULL) + if (NULL == logfile) return GNUNET_OK; - fn = GNUNET_STRINGS_filename_expand (logfile); - if (NULL == fn) + GNUNET_free_non_null (log_file_name); + log_file_name = GNUNET_STRINGS_filename_expand (logfile); + if (NULL == log_file_name) return GNUNET_SYSERR; - dirwarn = (GNUNET_OK != GNUNET_DISK_directory_create_for_file (fn)); - altlog = FOPEN (fn, "a"); - if (altlog == NULL) - { - GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "fopen", fn); - if (dirwarn) - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - _ - ("Failed to create or access directory for log file `%s'\n"), - fn); - GNUNET_free (fn); - return GNUNET_SYSERR; - } - GNUNET_free (fn); - if (GNUNET_stderr != NULL) - fclose (GNUNET_stderr); - GNUNET_stderr = altlog; - return GNUNET_OK; + t = time (NULL); + tm = gmtime (&t); + return setup_log_file (tm); } + /** * Add a custom logger. * @@ -581,6 +719,7 @@ GNUNET_logger_add (GNUNET_Logger logger, void *logger_cls) loggers = entry; } + /** * Remove a custom logger. * @@ -596,11 +735,11 @@ GNUNET_logger_remove (GNUNET_Logger logger, void *logger_cls) prev = NULL; pos = loggers; while ((pos != NULL) && - ((pos->logger != logger) || (pos->logger_cls != logger_cls))) - { - prev = pos; - pos = pos->next; - } + ((pos->logger != logger) || (pos->logger_cls != logger_cls))) + { + prev = pos; + pos = pos->next; + } GNUNET_assert (pos != NULL); if (prev == NULL) loggers = pos->next; @@ -609,6 +748,10 @@ GNUNET_logger_remove (GNUNET_Logger logger, void *logger_cls) GNUNET_free (pos); } +#if WINDOWS +CRITICAL_SECTION output_message_cs; +#endif + /** * Actually output the log message. @@ -620,22 +763,27 @@ GNUNET_logger_remove (GNUNET_Logger logger, void *logger_cls) */ static void output_message (enum GNUNET_ErrorType kind, const char *comp, - const char *datestr, const char *msg) + const char *datestr, const char *msg) { struct CustomLogger *pos; - - if (GNUNET_stderr != NULL) - { - fprintf (GNUNET_stderr, "%s %s %s %s", datestr, comp, - GNUNET_error_type_to_string (kind), msg); - fflush (GNUNET_stderr); - } +#if WINDOWS + EnterCriticalSection (&output_message_cs); +#endif + if (NULL != GNUNET_stderr) + { + FPRINTF (GNUNET_stderr, "%s %s %s %s", datestr, comp, + GNUNET_error_type_to_string (kind), msg); + fflush (GNUNET_stderr); + } pos = loggers; while (pos != NULL) - { - pos->logger (pos->logger_cls, kind, comp, datestr, msg); - pos = pos->next; - } + { + pos->logger (pos->logger_cls, kind, comp, datestr, msg); + pos = pos->next; + } +#if WINDOWS + LeaveCriticalSection (&output_message_cs); +#endif } @@ -650,7 +798,7 @@ flush_bulk (const char *datestr) char msg[DATE_STR_SIZE + BULK_TRACK_SIZE + 256]; int rev; char *last; - char *ft; + const char *ft; if ((last_bulk_time.abs_value == 0) || (last_bulk_repeat == 0)) return; @@ -661,17 +809,15 @@ flush_bulk (const char *datestr) else if (last != last_bulk) last--; if (last[0] == '\n') - { - rev = 1; - last[0] = '\0'; - } - ft = - GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_duration - (last_bulk_time)); + { + rev = 1; + last[0] = '\0'; + } + ft = GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_duration + (last_bulk_time), GNUNET_YES); snprintf (msg, sizeof (msg), - _("Message `%.*s' repeated %u times in the last %s\n"), - BULK_TRACK_SIZE, last_bulk, last_bulk_repeat, ft); - GNUNET_free (ft); + _("Message `%.*s' repeated %u times in the last %s\n"), + BULK_TRACK_SIZE, last_bulk, last_bulk_repeat, ft); if (rev == 1) last[0] = '\n'; output_message (last_bulk_kind, last_bulk_comp, datestr, msg); @@ -683,25 +829,37 @@ flush_bulk (const char *datestr) /** * Ignore the next n calls to the log function. * - * @param n number of log calls to ignore + * @param n number of log calls to ignore (could be negative) * @param check_reset GNUNET_YES to assert that the log skip counter is currently zero */ void -GNUNET_log_skip (unsigned int n, int check_reset) +GNUNET_log_skip (int n, int check_reset) { - if (n == 0) - { - int ok; + int ok; - ok = (0 == skip_log); - skip_log = 0; - if (check_reset) - GNUNET_assert (ok); - } + if (0 == n) + { + ok = (0 == skip_log); + skip_log = 0; + if (check_reset) + GNUNET_break (ok); + } else + { skip_log += n; + } } +/** + * Get the number of log calls that are going to be skipped + * + * @return number of log calls to be ignored + */ +int +GNUNET_get_log_skip () +{ + return skip_log; +} /** * Output a log message using the default mechanism. @@ -717,8 +875,6 @@ mylog (enum GNUNET_ErrorType kind, const char *comp, const char *message, { char date[DATE_STR_SIZE]; char date2[DATE_STR_SIZE]; - time_t timetmp; - struct timeval timeofday; struct tm *tmptr; size_t size; va_list vacp; @@ -727,43 +883,83 @@ mylog (enum GNUNET_ErrorType kind, const char *comp, const char *message, size = VSNPRINTF (NULL, 0, message, vacp) + 1; GNUNET_assert (0 != size); va_end (vacp); + memset (date, 0, DATE_STR_SIZE); { char buf[size]; + long long offset; +#ifdef WINDOWS + LARGE_INTEGER pc; + time_t timetmp; - VSNPRINTF (buf, size, message, va); + offset = GNUNET_TIME_get_offset (); time (&timetmp); - memset (date, 0, DATE_STR_SIZE); + timetmp += offset / 1000; tmptr = localtime (&timetmp); + pc.QuadPart = 0; + QueryPerformanceCounter (&pc); + if (NULL == tmptr) + { + strcpy (date, "localtime error"); + } + else + { + strftime (date2, DATE_STR_SIZE, "%b %d %H:%M:%S-%%020llu", tmptr); + snprintf (date, sizeof (date), date2, + (long long) (pc.QuadPart / + (performance_frequency.QuadPart / 1000))); + } +#else + struct timeval timeofday; + gettimeofday (&timeofday, NULL); - if (NULL != tmptr) + offset = GNUNET_TIME_get_offset (); + if (offset > 0) + { + timeofday.tv_sec += offset / 1000LL; + timeofday.tv_usec += (offset % 1000LL) * 1000LL; + if (timeofday.tv_usec > 1000000LL) { -#ifdef WINDOWS - LARGE_INTEGER pc; - - pc.QuadPart = 0; - QueryPerformanceCounter (&pc); - strftime (date2, DATE_STR_SIZE, "%b %d %H:%M:%S-%%020llu", tmptr); - snprintf (date, sizeof (date), date2, - (long long) (pc.QuadPart / - (performance_frequency.QuadPart / 1000))); -#else - strftime (date2, DATE_STR_SIZE, "%b %d %H:%M:%S-%%06u", tmptr); - snprintf (date, sizeof (date), date2, timeofday.tv_usec); -#endif + timeofday.tv_usec -= 1000000LL; + timeofday.tv_sec++; } + } else - strcpy (date, "localtime error"); - if ((0 != (kind & GNUNET_ERROR_TYPE_BULK)) - && (last_bulk_time.abs_value != 0) - && (0 == strncmp (buf, last_bulk, sizeof (last_bulk)))) + { + timeofday.tv_sec += offset / 1000LL; + if (timeofday.tv_usec > - (offset % 1000LL) * 1000LL) + { + timeofday.tv_usec += (offset % 1000LL) * 1000LL; + } + else { - last_bulk_repeat++; - if ((GNUNET_TIME_absolute_get_duration (last_bulk_time).rel_value > - BULK_DELAY_THRESHOLD) - || (last_bulk_repeat > BULK_REPEAT_THRESHOLD)) - flush_bulk (date); - return; + timeofday.tv_usec += 1000000LL + (offset % 1000LL) * 1000LL; + timeofday.tv_sec--; } + } + tmptr = localtime (&timeofday.tv_sec); + if (NULL == tmptr) + { + strcpy (date, "localtime error"); + } + else + { + strftime (date2, DATE_STR_SIZE, "%b %d %H:%M:%S-%%06u", tmptr); + snprintf (date, sizeof (date), date2, timeofday.tv_usec); + } +#endif + VSNPRINTF (buf, size, message, va); + if (NULL != tmptr) + (void) setup_log_file (tmptr); + if ((0 != (kind & GNUNET_ERROR_TYPE_BULK)) && + (last_bulk_time.abs_value != 0) && + (0 == strncmp (buf, last_bulk, sizeof (last_bulk)))) + { + last_bulk_repeat++; + if ((GNUNET_TIME_absolute_get_duration (last_bulk_time).rel_value > + BULK_DELAY_THRESHOLD) || (last_bulk_repeat > BULK_REPEAT_THRESHOLD)) + flush_bulk (date); + return; + } flush_bulk (date); strncpy (last_bulk, buf, sizeof (last_bulk)); last_bulk_repeat = 0; @@ -804,7 +1000,7 @@ GNUNET_log_nocheck (enum GNUNET_ErrorType kind, const char *message, ...) */ void GNUNET_log_from_nocheck (enum GNUNET_ErrorType kind, const char *comp, - const char *message, ...) + const char *message, ...) { va_list va; char comp_w_pid[128]; @@ -842,6 +1038,43 @@ GNUNET_error_type_to_string (enum GNUNET_ErrorType kind) } +/** + * Convert a short hash to a string (for printing debug messages). + * This is one of the very few calls in the entire API that is + * NOT reentrant! + * + * @param hc the short hash code + * @return string form; will be overwritten by next call to GNUNET_h2s. + */ +const char * +GNUNET_short_h2s (const struct GNUNET_CRYPTO_ShortHashCode * hc) +{ + static struct GNUNET_CRYPTO_ShortHashAsciiEncoded ret; + + GNUNET_CRYPTO_short_hash_to_enc (hc, &ret); + ret.short_encoding[8] = '\0'; + return (const char *) ret.short_encoding; +} + + +/** + * Convert a short hash to a string (for printing debug messages). + * This is one of the very few calls in the entire API that is + * NOT reentrant! + * + * @param hc the short hash code + * @return string form; will be overwritten by next call to GNUNET_h2s_full. + */ +const char * +GNUNET_short_h2s_full (const struct GNUNET_CRYPTO_ShortHashCode * hc) +{ + static struct GNUNET_CRYPTO_ShortHashAsciiEncoded ret; + + GNUNET_CRYPTO_short_hash_to_enc (hc, &ret); + ret.short_encoding[sizeof (ret) - 1] = '\0'; + return (const char *) ret.short_encoding; +} + /** * Convert a hash to a string (for printing debug messages). * This is one of the very few calls in the entire API that is @@ -851,7 +1084,7 @@ GNUNET_error_type_to_string (enum GNUNET_ErrorType kind) * @return string form; will be overwritten by next call to GNUNET_h2s. */ const char * -GNUNET_h2s (const GNUNET_HashCode * hc) +GNUNET_h2s (const struct GNUNET_HashCode * hc) { static struct GNUNET_CRYPTO_HashAsciiEncoded ret; @@ -860,6 +1093,7 @@ GNUNET_h2s (const GNUNET_HashCode * hc) return (const char *) ret.encoding; } + /** * Convert a hash to a string (for printing debug messages). * This is one of the very few calls in the entire API that is @@ -869,7 +1103,7 @@ GNUNET_h2s (const GNUNET_HashCode * hc) * @return string form; will be overwritten by next call to GNUNET_h2s_full. */ const char * -GNUNET_h2s_full (const GNUNET_HashCode * hc) +GNUNET_h2s_full (const struct GNUNET_HashCode * hc) { static struct GNUNET_CRYPTO_HashAsciiEncoded ret; @@ -878,6 +1112,7 @@ GNUNET_h2s_full (const GNUNET_HashCode * hc) return (const char *) ret.encoding; } + /** * Convert a peer identity to a string (for printing debug messages). * This is one of the very few calls in the entire API that is @@ -898,6 +1133,24 @@ GNUNET_i2s (const struct GNUNET_PeerIdentity *pid) } +/** + * Convert a peer identity to a string (for printing debug messages). + * This is one of the very few calls in the entire API that is + * NOT reentrant! + * + * @param pid the peer identity + * @return string form of the pid; will be overwritten by next + * call to GNUNET_i2s. + */ +const char * +GNUNET_i2s_full (const struct GNUNET_PeerIdentity *pid) +{ + static struct GNUNET_CRYPTO_HashAsciiEncoded ret; + + GNUNET_CRYPTO_hash_to_enc (&pid->hashPubKey, &ret); + return (const char *) ret.encoding; +} + /** * Convert a "struct sockaddr*" (IPv4 or IPv6 address) to a string @@ -922,44 +1175,84 @@ GNUNET_a2s (const struct sockaddr *addr, socklen_t addrlen) if (addr == NULL) return _("unknown address"); switch (addr->sa_family) - { - case AF_INET: - if (addrlen != sizeof (struct sockaddr_in)) - return ""; - v4 = (const struct sockaddr_in *) addr; - inet_ntop (AF_INET, &v4->sin_addr, buf, INET_ADDRSTRLEN); - if (0 == ntohs (v4->sin_port)) - return buf; - strcat (buf, ":"); - GNUNET_snprintf (b2, sizeof (b2), "%u", ntohs (v4->sin_port)); - strcat (buf, b2); - return buf; - case AF_INET6: - if (addrlen != sizeof (struct sockaddr_in6)) - return ""; - v6 = (const struct sockaddr_in6 *) addr; - buf[0] = '['; - inet_ntop (AF_INET6, &v6->sin6_addr, &buf[1], INET6_ADDRSTRLEN); - if (0 == ntohs (v6->sin6_port)) - return &buf[1]; - strcat (buf, "]:"); - GNUNET_snprintf (b2, sizeof (b2), "%u", ntohs (v6->sin6_port)); - strcat (buf, b2); - return buf; - case AF_UNIX: - if (addrlen <= sizeof (sa_family_t)) - return ""; - un = (const struct sockaddr_un *) addr; - off = 0; - if (un->sun_path[0] == '\0') - off++; - snprintf (buf, sizeof (buf), "%s%.*s", (off == 1) ? "@" : "", - (int) (addrlen - sizeof (sa_family_t) - 1 - off), - &un->sun_path[off]); + { + case AF_INET: + if (addrlen != sizeof (struct sockaddr_in)) + return ""; + v4 = (const struct sockaddr_in *) addr; + inet_ntop (AF_INET, &v4->sin_addr, buf, INET_ADDRSTRLEN); + if (0 == ntohs (v4->sin_port)) return buf; - default: - return _("invalid address"); - } + strcat (buf, ":"); + GNUNET_snprintf (b2, sizeof (b2), "%u", ntohs (v4->sin_port)); + strcat (buf, b2); + return buf; + case AF_INET6: + if (addrlen != sizeof (struct sockaddr_in6)) + return ""; + v6 = (const struct sockaddr_in6 *) addr; + buf[0] = '['; + inet_ntop (AF_INET6, &v6->sin6_addr, &buf[1], INET6_ADDRSTRLEN); + if (0 == ntohs (v6->sin6_port)) + return &buf[1]; + strcat (buf, "]:"); + GNUNET_snprintf (b2, sizeof (b2), "%u", ntohs (v6->sin6_port)); + strcat (buf, b2); + return buf; + case AF_UNIX: + if (addrlen <= sizeof (sa_family_t)) + return ""; + un = (const struct sockaddr_un *) addr; + off = 0; + if (un->sun_path[0] == '\0') + off++; + memset (buf, 0, sizeof (buf)); + snprintf (buf, sizeof (buf) - 1, "%s%.*s", (off == 1) ? "@" : "", + (int) (addrlen - sizeof (sa_family_t) - 1 - off), + &un->sun_path[off]); + return buf; + default: + return _("invalid address"); + } +} + + +/** + * Log error message about missing configuration option. + * + * @param kind log level + * @param section section with missing option + * @param option name of missing option + */ +void +GNUNET_log_config_missing (enum GNUNET_ErrorType kind, + const char *section, + const char *option) +{ + GNUNET_log (kind, + _("Configuration fails to specify option `%s' in section `%s'!\n"), + option, + section); +} + + +/** + * Log error message about invalid configuration option value. + * + * @param kind log level + * @param section section with invalid option + * @param option name of invalid option + * @param required what is required that is invalid about the option + */ +void +GNUNET_log_config_invalid (enum GNUNET_ErrorType kind, + const char *section, + const char *option, + const char *required) +{ + GNUNET_log (kind, + _("Configuration specifies invalid value for option `%s' in section `%s': %s\n"), + option, section, required); } @@ -972,6 +1265,10 @@ void __attribute__ ((constructor)) GNUNET_util_cl_init () #ifdef MINGW GNInitWinEnv (NULL); #endif +#if WINDOWS + if (!InitializeCriticalSectionAndSpinCount (&output_message_cs, 0x00000400)) + GNUNET_abort (); +#endif } @@ -980,6 +1277,9 @@ void __attribute__ ((constructor)) GNUNET_util_cl_init () */ void __attribute__ ((destructor)) GNUNET_util_cl_fini () { +#if WINDOWS + DeleteCriticalSection (&output_message_cs); +#endif #ifdef MINGW GNShutdownWinEnv (); #endif