1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195
|
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include <syslog.h>
#include <time.h>
#include <unistd.h>
#include <string>
#include <vector>
#include "tlse.h"
#include "log.h"
using namespace std;
// Yes, it's a bit ugly.
#define SYSLOG_FAKE_FILE (static_cast<FILE *>(nullptr))
bool logging_started = false;
vector<FILE *> log_destinations;
void add_log_destination_file(const string &filename)
{
FILE *fp = fopen(filename.c_str(), "ae");
if (fp == nullptr) {
perror(filename.c_str());
return;
}
log_destinations.push_back(fp);
}
void add_log_destination_console()
{
log_destinations.push_back(stderr);
}
void add_log_destination_syslog()
{
openlog("cubemap", LOG_PID, LOG_DAEMON);
log_destinations.push_back(SYSLOG_FAKE_FILE);
}
void start_logging()
{
logging_started = true;
}
void shut_down_logging()
{
for (size_t i = 0; i < log_destinations.size(); ++i) {
if (log_destinations[i] == SYSLOG_FAKE_FILE) {
closelog();
} else if (log_destinations[i] != stderr) {
if (fclose(log_destinations[i]) != 0) {
perror("fclose");
}
}
}
log_destinations.clear();
logging_started = false;
}
void log(LogLevel log_level, const char *fmt, ...)
{
char formatted_msg[4096];
va_list ap;
va_start(ap, fmt);
vsnprintf(formatted_msg, sizeof(formatted_msg), fmt, ap);
va_end(ap);
time_t now = time(nullptr);
struct tm lt;
struct tm *ltime = localtime_r(&now, <);
char timestamp[1024];
if (ltime == nullptr) {
strcpy(timestamp, "???");
} else {
strftime(timestamp, sizeof(timestamp), "%a, %d %b %Y %T %z", ltime);
}
const char *log_level_str;
int syslog_level;
switch (log_level) {
case INFO:
log_level_str = "INFO: ";
syslog_level = LOG_INFO;
break;
case WARNING:
log_level_str = "WARNING: ";
syslog_level = LOG_WARNING;
break;
case ERROR:
log_level_str = "ERROR: ";
syslog_level = LOG_ERR;
break;
default:
assert(false);
}
// Log to stderr if logging hasn't been set up yet. Note that this means
// that such messages will come even if there are no “error_log” lines.
if (!logging_started) {
fprintf(stderr, "[%s] %s%s\n", timestamp, log_level_str, formatted_msg);
return;
}
for (size_t i = 0; i < log_destinations.size(); ++i) {
if (log_destinations[i] == SYSLOG_FAKE_FILE) {
syslog(syslog_level, "%s", formatted_msg);
} else {
int err = fprintf(log_destinations[i], "[%s] %s%s\n", timestamp, log_level_str, formatted_msg);
if (err < 0) {
perror("fprintf");
}
if (log_destinations[i] != stderr) {
fflush(log_destinations[i]);
}
}
}
}
void log_perror(const char *msg)
{
char errbuf[4096];
log(ERROR, "%s: %s", msg, strerror_r(errno, errbuf, sizeof(errbuf)));
}
void log_tls_error(const char *msg, int tls_err)
{
switch (tls_err) {
case TLS_NEED_MORE_DATA:
log(ERROR, "%s: Need more data (TLS)", msg);
break;
case TLS_GENERIC_ERROR:
log(ERROR, "%s: Generic TLS error", msg);
break;
case TLS_BROKEN_PACKET:
log(ERROR, "%s: Broken TLS packet", msg);
break;
case TLS_NOT_UNDERSTOOD:
log(ERROR, "%s: Not understood (TLS)", msg);
break;
case TLS_NOT_SAFE:
log(ERROR, "%s: Not safe (TLS)", msg);
break;
case TLS_NO_COMMON_CIPHER:
log(ERROR, "%s: No common TLS cipher", msg);
break;
case TLS_UNEXPECTED_MESSAGE:
log(ERROR, "%s: Unexpected TLS message", msg);
break;
case TLS_CLOSE_CONNECTION:
log(ERROR, "%s: Close TLS connection", msg);
break;
case TLS_COMPRESSION_NOT_SUPPORTED:
log(ERROR, "%s: TLS compression not supported", msg);
break;
case TLS_NO_MEMORY:
log(ERROR, "%s: No TLS memory", msg);
break;
case TLS_NOT_VERIFIED:
log(ERROR, "%s: Not verified (TLS)", msg);
break;
case TLS_INTEGRITY_FAILED:
log(ERROR, "%s: TLS integrity failed", msg);
break;
case TLS_ERROR_ALERT:
log(ERROR, "%s: TLS alert", msg);
break;
case TLS_BROKEN_CONNECTION:
log(ERROR, "%s: Broken TLS connection", msg);
break;
case TLS_BAD_CERTIFICATE:
log(ERROR, "%s: Bad TLS certificate", msg);
break;
case TLS_UNSUPPORTED_CERTIFICATE:
log(ERROR, "%s: Unsupported TLS certificate", msg);
break;
case TLS_NO_RENEGOTIATION:
log(ERROR, "%s: No TLS renegotiation", msg);
break;
case TLS_FEATURE_NOT_SUPPORTED:
log(ERROR, "%s: TLS feature not supported", msg);
break;
default:
log(ERROR, "%s: Unknown TLS error %d", msg, tls_err);
break;
}
}
|