*/
#define BULK_TRACK_SIZE 256
+/**
+ * How many characters do we use for matching of
+ * bulk components?
+ */
+#define COMP_TRACK_SIZE 32
+
/**
* How many characters can a date/time string
* be at most?
static unsigned int last_bulk_repeat;
/**
- * Component when the last bulk was logged.
+ * Component when the last bulk was logged. Will be 0-terminated.
*/
-static const char *last_bulk_comp;
+static char last_bulk_comp[COMP_TRACK_SIZE+1];
/**
* Running component.
*/
-static const char *component;
+static char *component;
/**
* Minimum log level.
*/
static unsigned int skip_log;
+/**
+ * File descriptor to use for "stderr", or NULL for none.
+ */
static FILE *GNUNET_stderr;
/**
* Convert a textual description of a loglevel
* to the respective GNUNET_GE_KIND.
- * @returns GNUNET_GE_INVALID if log does not parse
+ *
+ * @param log loglevel to parse
+ * @return GNUNET_GE_INVALID if log does not parse
*/
static enum GNUNET_ErrorType
get_type (const char *log)
return GNUNET_ERROR_TYPE_INVALID;
}
+
/**
* Setup logging.
*
* @param comp default component to use
* @param loglevel what types of messages should be logged
+ * @param logfile which file to write log messages to (can be NULL)
+ * @return GNUNET_OK on success
*/
int
GNUNET_log_setup (const char *comp, const char *loglevel, const char *logfile)
{
FILE *altlog;
-
- component = comp;
+ int dirwarn;
+ char *fn;
+
+ GNUNET_free_non_null (component);
+ GNUNET_asprintf (&component,
+ "%s-%d",
+ comp,
+ getpid());
min_level = get_type (loglevel);
if (logfile == NULL)
return GNUNET_OK;
- altlog = fopen (logfile, "a");
+ fn = GNUNET_STRINGS_filename_expand (logfile);
+ if (NULL == fn)
+ 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", logfile);
+ 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;
GNUNET_free (pos);
}
+
+/**
+ * Actually output the log message.
+ *
+ * @param kind how severe was the issue
+ * @param comp component responsible
+ * @param datestr current date/time
+ * @param msg the actual message
+ */
static void
output_message (enum GNUNET_ErrorType kind,
const char *comp, 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);
+ {
+ fprintf (GNUNET_stderr, "%s %s %s %s", datestr, comp,
+ GNUNET_error_type_to_string (kind), msg);
+ fflush (GNUNET_stderr);
+ }
pos = loggers;
while (pos != NULL)
{
}
}
+
+/**
+ * Flush an existing bulk report to the output.
+ *
+ * @param datestr our current timestamp
+ */
static void
flush_bulk (const char *datestr)
{
* Ignore the next n calls to the log function.
*
* @param n number of log calls to ignore
+ * @param check_reset GNUNET_YES to assert that the log skip counter is currently zero
*/
void
-GNUNET_log_skip (unsigned int n)
+GNUNET_log_skip (unsigned int n, int check_reset)
{
if (n == 0)
+ {
+ int ok;
+
+ ok = (0 == skip_log);
skip_log = 0;
+ if (check_reset)
+ GNUNET_assert (ok);
+ }
else
skip_log += n;
}
+/**
+ * Output a log message using the default mechanism.
+ *
+ * @param kind how severe was the issue
+ * @param comp component responsible
+ * @param message the actual message
+ * @param va arguments to the format string "message"
+ */
static void
mylog (enum GNUNET_ErrorType kind,
const char *comp, const char *message, va_list va)
time (&timetmp);
memset (date, 0, DATE_STR_SIZE);
tmptr = localtime (&timetmp);
- strftime (date, DATE_STR_SIZE, "%b %d %H:%M:%S", tmptr);
+ if (NULL != tmptr)
+ strftime (date, DATE_STR_SIZE, "%b %d %H:%M:%S", tmptr);
+ else
+ strcpy (date, "localtime error");
if ((0 != (kind & GNUNET_ERROR_TYPE_BULK)) &&
(last_bulk_time.value != 0) &&
(0 == strncmp (buf, last_bulk, sizeof (last_bulk))))
last_bulk_repeat = 0;
last_bulk_kind = kind;
last_bulk_time = GNUNET_TIME_absolute_get ();
- last_bulk_comp = comp;
+ strncpy (last_bulk_comp, comp, COMP_TRACK_SIZE);
output_message (kind, comp, date, buf);
free (buf);
}
+/**
+ * Main log function.
+ *
+ * @param kind how serious is the error?
+ * @param message what is the message (format string)
+ * @param ... arguments for format string
+ */
void
GNUNET_log (enum GNUNET_ErrorType kind, const char *message, ...)
{
}
+/**
+ * Log function that specifies an alternative component.
+ * This function should be used by plugins.
+ *
+ * @param kind how serious is the error?
+ * @param comp component responsible for generating the message
+ * @param message what is the message (format string)
+ * @param ... arguments for format string
+ */
void
GNUNET_log_from (enum GNUNET_ErrorType kind,
const char *comp, const char *message, ...)
/**
- * Convert KIND to String
+ * Convert error type to string.
+ *
+ * @param kind type to convert
+ * @return string corresponding to the type
*/
const char *
GNUNET_error_type_to_string (enum GNUNET_ErrorType kind)
* This is one of the very few calls in the entire API that is
* NOT reentrant!
*
- * @param pid the peer identity
+ * @param hc the hash code
* @return string form; will be overwritten by next call to GNUNET_h2s.
*/
const char *
-GNUNET_h2s (const GNUNET_HashCode *pid)
+GNUNET_h2s (const GNUNET_HashCode * hc)
{
static struct GNUNET_CRYPTO_HashAsciiEncoded ret;
- GNUNET_CRYPTO_hash_to_enc (pid, &ret);
+
+ GNUNET_CRYPTO_hash_to_enc (hc, &ret);
ret.encoding[8] = '\0';
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
+ * NOT reentrant!
+ *
+ * @param hc the hash code
+ * @return string form; will be overwritten by next call to GNUNET_h2s_full.
+ */
+const char *
+GNUNET_h2s_full (const GNUNET_HashCode * hc)
+{
+ static struct GNUNET_CRYPTO_HashAsciiEncoded ret;
+
+ GNUNET_CRYPTO_hash_to_enc (hc, &ret);
+ ret.encoding[sizeof(ret)-1] = '\0';
+ return (const char *) ret.encoding;
+}
/**
* Convert a peer identity to a string (for printing debug messages).
GNUNET_i2s (const struct GNUNET_PeerIdentity *pid)
{
static struct GNUNET_CRYPTO_HashAsciiEncoded ret;
+
GNUNET_CRYPTO_hash_to_enc (&pid->hashPubKey, &ret);
ret.encoding[4] = '\0';
return (const char *) ret.encoding;
* @return nicely formatted string for the address
* will be overwritten by next call to GNUNET_a2s.
*/
-const char *GNUNET_a2s (const struct sockaddr *addr,
- socklen_t addrlen)
+const char *
+GNUNET_a2s (const struct sockaddr *addr, socklen_t addrlen)
{
- static char buf[INET6_ADDRSTRLEN+8];
+ static char buf[INET6_ADDRSTRLEN + 8];
static char b2[6];
- const struct sockaddr_in * v4;
+ const struct sockaddr_in *v4;
+ const struct sockaddr_un *un;
const struct sockaddr_in6 *v6;
+ unsigned int off;
if (addr == NULL)
return _("unknown address");
switch (addr->sa_family)
{
case AF_INET:
- v4 = (const struct sockaddr_in*)addr;
- inet_ntop(AF_INET, &v4->sin_addr, buf, INET_ADDRSTRLEN);
- if (0 == ntohs(v4->sin_port))
- return buf;
+ if (addrlen != sizeof (struct sockaddr_in))
+ return "<invalid v4 address>";
+ 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, ":");
- sprintf (b2, "%u", ntohs(v4->sin_port));
+ GNUNET_snprintf (b2, sizeof(b2), "%u", ntohs (v4->sin_port));
strcat (buf, b2);
return buf;
case AF_INET6:
- v6 = (const struct sockaddr_in6*)addr;
+ if (addrlen != sizeof (struct sockaddr_in6))
+ return "<invalid v4 address>";
+ 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];
+ inet_ntop (AF_INET6, &v6->sin6_addr, &buf[1], INET6_ADDRSTRLEN);
+ if (0 == ntohs (v6->sin6_port))
+ return &buf[1];
strcat (buf, "]:");
- sprintf (b2, "%u", ntohs(v6->sin6_port));
+ GNUNET_snprintf (b2, sizeof(b2), "%u", ntohs (v6->sin6_port));
strcat (buf, b2);
- return buf;
+ return buf;
+ case AF_UNIX:
+ if (addrlen <= sizeof (sa_family_t))
+ return "<unbound UNIX client>";
+ 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]);
+ return buf;
default:
return _("invalid address");
}
/**
* Initializer
*/
-void __attribute__ ((constructor))
-GNUNET_util_cl_init()
+void __attribute__ ((constructor)) GNUNET_util_cl_init ()
{
GNUNET_stderr = stderr;
+#ifdef MINGW
+ InitWinEnv (NULL);
+#endif
+}
+
+
+/**
+ * Destructor
+ */
+void __attribute__ ((destructor)) GNUNET_util_cl_fini ()
+{
+#ifdef MINGW
+ ShutdownWinEnv ();
+#endif
}
/* end of common_logging.c */