Add a global log configuration.

This is the easiest and cleanest way to get logging into some of the
fundamental APIs, such as the database and TLS APIs. We don't want to
have to pass logging functions to those, but they can safely use the
global logging configuration.
This commit is contained in:
Jordan Bancino 2023-03-22 14:52:04 +00:00
parent 8782aa046d
commit f3c4c0ac65
13 changed files with 207 additions and 142 deletions

View file

@ -6,52 +6,63 @@ Key:
[ ] Not Started [ ] Not Started
[x] Done [x] Done
[~] In Progress [~] In Progress
[!] Won't Fix [!] Won't Do
Milestone: v0.3.0 Milestone: v0.3.0
----------------- -----------------
[~] Stream API [x] Stream API
[x] Implementation [x] Implementation
[x] Convert all code that deals with I/O [x] Convert all code that deals with I/O
[!] Multi-output (proof of concept) [!] Multi-output (proof of concept)
[!] Memory streams (proof of concept) [!] Memory streams (proof of concept)
[~] TLS [x] TLS
[ ] SOCKS [!] SOCKS
[x] Move/convert UtilStreamCopy() [x] Move/convert UtilStreamCopy()
[ ] Io man page [x] HTTP Client API
[ ] Stream man page
[ ] Tls man page
[~] HTTP Client API
[x] Document HttpParseHeaders() [x] Document HttpParseHeaders()
[ ] HttpClient man page
[ ] Uri man page
[x] Test on other platforms [x] Test on other platforms
[x] Option to pretty-print Json [x] Option to pretty-print Json
[x] Document JsonEncode() and JsonEncodeValue() [x] Document JsonEncode() and JsonEncodeValue()
[ ] Update man page for td
[x] Document Telodendria and Main [x] Document Telodendria and Main
[ ] Document tt and http-debug-server
[x] Simple command line tool to make matrix requests [x] Simple command line tool to make matrix requests
[x] Built on HTTP client API [x] Built on HTTP client API
[x] http man page [x] http man page
[~] Simple command line tool for working with JSON [x] Simple command line tool for working with JSON
[x] Pretty-print Json [x] Pretty-print Json
[x] Query fields for use in shell scripts. [x] Query fields for use in shell scripts.
[x] Encode user-provided JSON strings [x] Encode user-provided JSON strings
[x] json man page [x] json man page
[ ] Update man pages for tp and send-patch
[x] Global log object
- So we don't have to pass LogConfig around everywhere
- Also allows debug and error logging in other APIs
[ ] Proper HTTP request router [ ] Proper HTTP request router
- Support regex matching - Support regex matching
[ ] Move configuration to database [ ] Move configuration to database
[ ] Initial configuration [ ] Initial configuration
[ ] If no config, create one-time use registration token that [ ] If no config, create one-time use registration token that
grants user admin privileges. grants user admin privileges.
[ ] /_telodendria/admin/config endpoint [ ] /_telodendria/admin/config endpoint
[ ] Refactor TelodendriaConfig to just Config (ConfigLock() and ConfigUnlock()) [ ] Refactor TelodendriaConfig to just Config (ConfigLock() and ConfigUnlock())
[ ] Make 'listen' directive in config an array of objects
- Each object has port, threads, maxConnections
- If tls is given, it can be null, false, or an object with cert and key
[ ] Pass TLS certs and keys into HttpServer
[ ] Documentation
[ ] Io
[ ] Stream
[ ] Tls
[ ] HttpClient
[ ] Uri
[ ] td
[ ] tt
[ ] http-debug-server
[ ] tp
[ ] send-patch
[ ] Log
[~] Client-Server API [~] Client-Server API
[x] 4: Token-based user registration [x] 4: Token-based user registration

View file

@ -45,6 +45,8 @@ struct LogConfig
pthread_mutex_t lock; pthread_mutex_t lock;
}; };
LogConfig *globalConfig = NULL;
LogConfig * LogConfig *
LogConfigCreate(void) LogConfigCreate(void)
{ {
@ -68,6 +70,17 @@ LogConfigCreate(void)
return config; return config;
} }
LogConfig *
LogConfigGlobal(void)
{
if (!globalConfig)
{
globalConfig = LogConfigCreate();
}
return globalConfig;
}
void void
LogConfigFlagClear(LogConfig * config, int flags) LogConfigFlagClear(LogConfig * config, int flags)
{ {
@ -111,6 +124,11 @@ LogConfigFree(LogConfig * config)
StreamClose(config->out); StreamClose(config->out);
Free(config); Free(config);
if (config == globalConfig)
{
globalConfig = NULL;
}
} }
void void
@ -202,12 +220,11 @@ LogConfigUnindent(LogConfig * config)
} }
void void
Log(LogConfig * config, int level, const char *msg,...) Logv(LogConfig * config, int level, const char *msg, va_list argp)
{ {
size_t i; size_t i;
int doColor; int doColor;
char indicator; char indicator;
va_list argp;
/* /*
* Only proceed if we have a config and its log level is set to a * Only proceed if we have a config and its log level is set to a
@ -232,9 +249,7 @@ Log(LogConfig * config, int level, const char *msg,...)
{ {
/* No further print logic is needed; syslog will handle it all /* No further print logic is needed; syslog will handle it all
* for us. */ * for us. */
va_start(argp, msg);
vsyslog(level, msg, argp); vsyslog(level, msg, argp);
va_end(argp);
pthread_mutex_unlock(&config->lock); pthread_mutex_unlock(&config->lock);
return; return;
} }
@ -345,12 +360,30 @@ Log(LogConfig * config, int level, const char *msg,...)
StreamPutc(config->out, ' '); StreamPutc(config->out, ' ');
} }
va_start(argp, msg);
StreamVprintf(config->out, msg, argp); StreamVprintf(config->out, msg, argp);
StreamPutc(config->out, '\n'); StreamPutc(config->out, '\n');
va_end(argp);
StreamFlush(config->out); StreamFlush(config->out);
pthread_mutex_unlock(&config->lock); pthread_mutex_unlock(&config->lock);
} }
void
LogTo(LogConfig *config, int level, const char *fmt, ...)
{
va_list argp;
va_start(argp, fmt);
Logv(config, level, fmt, argp);
va_end(argp);
}
extern void
Log(int level, const char *fmt, ...)
{
va_list argp;
va_start(argp, fmt);
Logv(LogConfigGlobal(), level, fmt, argp);
va_end(argp);
}

View file

@ -63,7 +63,6 @@ typedef enum ArgFlag
int int
main(int argc, char **argv) main(int argc, char **argv)
{ {
LogConfig *lc;
int exit = EXIT_SUCCESS; int exit = EXIT_SUCCESS;
/* Arg parsing */ /* Arg parsing */
@ -90,17 +89,15 @@ main(int argc, char **argv)
memset(&matrixArgs, 0, sizeof(matrixArgs)); memset(&matrixArgs, 0, sizeof(matrixArgs));
lc = LogConfigCreate(); if (!LogConfigGlobal())
if (!lc)
{ {
printf("Fatal error: unable to allocate memory for logger.\n"); printf("Fatal error: unable to allocate memory for logger.\n");
return EXIT_FAILURE; return EXIT_FAILURE;
} }
MemoryHook(TelodendriaMemoryHook, lc); MemoryHook(TelodendriaMemoryHook, NULL);
TelodendriaPrintHeader(lc); TelodendriaPrintHeader();
while ((opt = getopt(argc, argv, "f:Vvn")) != -1) while ((opt = getopt(argc, argv, "f:Vvn")) != -1)
{ {
@ -128,7 +125,7 @@ main(int argc, char **argv)
if (flags & ARG_VERBOSE) if (flags & ARG_VERBOSE)
{ {
LogConfigLevelSet(lc, LOG_DEBUG); LogConfigLevelSet(LogConfigGlobal(), LOG_DEBUG);
} }
if (flags & ARG_VERSION) if (flags & ARG_VERSION)
@ -138,7 +135,7 @@ main(int argc, char **argv)
if (!configArg) if (!configArg)
{ {
Log(lc, LOG_ERR, "No configuration file specified."); Log(LOG_ERR, "No configuration file specified.");
exit = EXIT_FAILURE; exit = EXIT_FAILURE;
goto finish; goto finish;
} }
@ -153,25 +150,25 @@ main(int argc, char **argv)
configFile = StreamOpen(configArg, "r"); configFile = StreamOpen(configArg, "r");
if (!configFile) if (!configFile)
{ {
Log(lc, LOG_ERR, "Unable to open configuration file '%s' for reading.", configArg); Log(LOG_ERR, "Unable to open configuration file '%s' for reading.", configArg);
exit = EXIT_FAILURE; exit = EXIT_FAILURE;
goto finish; goto finish;
} }
} }
Log(lc, LOG_NOTICE, "Processing configuration file '%s'.", configArg); Log(LOG_NOTICE, "Processing configuration file '%s'.", configArg);
config = JsonDecode(configFile); config = JsonDecode(configFile);
StreamClose(configFile); StreamClose(configFile);
if (!config) if (!config)
{ {
Log(lc, LOG_ERR, "Syntax error in configuration file."); Log(LOG_ERR, "Syntax error in configuration file.");
exit = EXIT_FAILURE; exit = EXIT_FAILURE;
goto finish; goto finish;
} }
tConfig = TelodendriaConfigParse(config, lc); tConfig = TelodendriaConfigParse(config, LogConfigGlobal());
JsonFree(config); JsonFree(config);
if (!tConfig) if (!tConfig)
@ -182,13 +179,13 @@ main(int argc, char **argv)
if (flags & ARG_CONFIGTEST) if (flags & ARG_CONFIGTEST)
{ {
Log(lc, LOG_INFO, "Configuration is OK."); Log(LOG_INFO, "Configuration is OK.");
goto finish; goto finish;
} }
if (!tConfig->logTimestamp || strcmp(tConfig->logTimestamp, "default") != 0) if (!tConfig->logTimestamp || strcmp(tConfig->logTimestamp, "default") != 0)
{ {
LogConfigTimeStampFormatSet(lc, tConfig->logTimestamp); LogConfigTimeStampFormatSet(LogConfigGlobal(), tConfig->logTimestamp);
} }
else else
{ {
@ -198,24 +195,24 @@ main(int argc, char **argv)
if (tConfig->flags & TELODENDRIA_LOG_COLOR) if (tConfig->flags & TELODENDRIA_LOG_COLOR)
{ {
LogConfigFlagSet(lc, LOG_FLAG_COLOR); LogConfigFlagSet(LogConfigGlobal(), LOG_FLAG_COLOR);
} }
else else
{ {
LogConfigFlagClear(lc, LOG_FLAG_COLOR); LogConfigFlagClear(LogConfigGlobal(), LOG_FLAG_COLOR);
} }
LogConfigLevelSet(lc, flags & ARG_VERBOSE ? LOG_DEBUG : tConfig->logLevel); LogConfigLevelSet(LogConfigGlobal(), flags & ARG_VERBOSE ? LOG_DEBUG : tConfig->logLevel);
if (chdir(tConfig->dataDir) != 0) if (chdir(tConfig->dataDir) != 0)
{ {
Log(lc, LOG_ERR, "Unable to change into data directory: %s.", strerror(errno)); Log(LOG_ERR, "Unable to change into data directory: %s.", strerror(errno));
exit = EXIT_FAILURE; exit = EXIT_FAILURE;
goto finish; goto finish;
} }
else else
{ {
Log(lc, LOG_DEBUG, "Changed working directory to: %s", tConfig->dataDir); Log(LOG_DEBUG, "Changed working directory to: %s", tConfig->dataDir);
} }
@ -225,22 +222,22 @@ main(int argc, char **argv)
if (!logFile) if (!logFile)
{ {
Log(lc, LOG_ERR, "Unable to open log file for appending."); Log(LOG_ERR, "Unable to open log file for appending.");
exit = EXIT_FAILURE; exit = EXIT_FAILURE;
goto finish; goto finish;
} }
Log(lc, LOG_INFO, "Logging to the log file. Check there for all future messages."); Log(LOG_INFO, "Logging to the log file. Check there for all future messages.");
LogConfigOutputSet(lc, logFile); LogConfigOutputSet(LogConfigGlobal(), logFile);
} }
else if (tConfig->flags & TELODENDRIA_LOG_STDOUT) else if (tConfig->flags & TELODENDRIA_LOG_STDOUT)
{ {
Log(lc, LOG_DEBUG, "Already logging to standard output."); Log(LOG_DEBUG, "Already logging to standard output.");
} }
else if (tConfig->flags & TELODENDRIA_LOG_SYSLOG) else if (tConfig->flags & TELODENDRIA_LOG_SYSLOG)
{ {
Log(lc, LOG_INFO, "Logging to the syslog. Check there for all future messages."); Log(LOG_INFO, "Logging to the syslog. Check there for all future messages.");
LogConfigFlagSet(lc, LOG_FLAG_SYSLOG); LogConfigFlagSet(LogConfigGlobal(), LOG_FLAG_SYSLOG);
openlog("telodendria", LOG_PID | LOG_NDELAY, LOG_DAEMON); openlog("telodendria", LOG_PID | LOG_NDELAY, LOG_DAEMON);
/* Always log everything, because the Log API will control what /* Always log everything, because the Log API will control what
@ -249,28 +246,27 @@ main(int argc, char **argv)
} }
else else
{ {
Log(lc, LOG_ERR, "Unknown logging method in flags: '%d'", tConfig->flags); Log(LOG_ERR, "Unknown logging method in flags: '%d'", tConfig->flags);
Log(lc, LOG_ERR, "This is a programmer error; please report it."); Log(LOG_ERR, "This is a programmer error; please report it.");
exit = EXIT_FAILURE; exit = EXIT_FAILURE;
goto finish; goto finish;
} }
Log(lc, LOG_DEBUG, "Configuration:"); Log(LOG_DEBUG, "Configuration:");
LogConfigIndent(lc); LogConfigIndent(LogConfigGlobal());
Log(lc, LOG_DEBUG, "Listen On: %d", tConfig->listenPort); Log(LOG_DEBUG, "Listen On: %d", tConfig->listenPort);
Log(lc, LOG_DEBUG, "Server Name: %s", tConfig->serverName); Log(LOG_DEBUG, "Server Name: %s", tConfig->serverName);
Log(lc, LOG_DEBUG, "Base URL: %s", tConfig->baseUrl); Log(LOG_DEBUG, "Base URL: %s", tConfig->baseUrl);
Log(lc, LOG_DEBUG, "Identity Server: %s", tConfig->identityServer); Log(LOG_DEBUG, "Identity Server: %s", tConfig->identityServer);
Log(lc, LOG_DEBUG, "Run As: %s:%s", tConfig->uid, tConfig->gid); Log(LOG_DEBUG, "Run As: %s:%s", tConfig->uid, tConfig->gid);
Log(lc, LOG_DEBUG, "Data Directory: %s", tConfig->dataDir); Log(LOG_DEBUG, "Data Directory: %s", tConfig->dataDir);
Log(lc, LOG_DEBUG, "Threads: %d", tConfig->threads); Log(LOG_DEBUG, "Threads: %d", tConfig->threads);
Log(lc, LOG_DEBUG, "Max Connections: %d", tConfig->maxConnections); Log(LOG_DEBUG, "Max Connections: %d", tConfig->maxConnections);
Log(lc, LOG_DEBUG, "Max Cache: %ld", tConfig->maxCache); Log(LOG_DEBUG, "Max Cache: %ld", tConfig->maxCache);
Log(lc, LOG_DEBUG, "Flags: %x", tConfig->flags); Log(LOG_DEBUG, "Flags: %x", tConfig->flags);
LogConfigUnindent(lc); LogConfigUnindent(LogConfigGlobal());
/* Arguments to pass into the HTTP handler */ /* Arguments to pass into the HTTP handler */
matrixArgs.lc = lc;
matrixArgs.config = tConfig; matrixArgs.config = tConfig;
/* Bind the socket before possibly dropping permissions */ /* Bind the socket before possibly dropping permissions */
@ -278,13 +274,13 @@ main(int argc, char **argv)
tConfig->maxConnections, MatrixHttpHandler, &matrixArgs); tConfig->maxConnections, MatrixHttpHandler, &matrixArgs);
if (!httpServer) if (!httpServer)
{ {
Log(lc, LOG_ERR, "Unable to create HTTP server on port %d: %s", Log(LOG_ERR, "Unable to create HTTP server on port %d: %s",
tConfig->listenPort, strerror(errno)); tConfig->listenPort, strerror(errno));
exit = EXIT_FAILURE; exit = EXIT_FAILURE;
goto finish; goto finish;
} }
Log(lc, LOG_DEBUG, "Running as uid:gid: %d:%d.", getuid(), getgid()); Log(LOG_DEBUG, "Running as uid:gid: %d:%d.", getuid(), getgid());
if (tConfig->uid && tConfig->gid) if (tConfig->uid && tConfig->gid)
{ {
@ -293,18 +289,18 @@ main(int argc, char **argv)
if (!userInfo || !groupInfo) if (!userInfo || !groupInfo)
{ {
Log(lc, LOG_ERR, "Unable to locate the user/group specified in the configuration."); Log(LOG_ERR, "Unable to locate the user/group specified in the configuration.");
exit = EXIT_FAILURE; exit = EXIT_FAILURE;
goto finish; goto finish;
} }
else else
{ {
Log(lc, LOG_DEBUG, "Found user/group information using getpwnam() and getgrnam()."); Log(LOG_DEBUG, "Found user/group information using getpwnam() and getgrnam().");
} }
} }
else else
{ {
Log(lc, LOG_DEBUG, "No user/group info specified in the config."); Log(LOG_DEBUG, "No user/group info specified in the config.");
} }
if (getuid() == 0) if (getuid() == 0)
@ -313,35 +309,35 @@ main(int argc, char **argv)
{ {
if (setgid(groupInfo->gr_gid) != 0 || setuid(userInfo->pw_uid) != 0) if (setgid(groupInfo->gr_gid) != 0 || setuid(userInfo->pw_uid) != 0)
{ {
Log(lc, LOG_ERR, "Unable to set process uid/gid."); Log(LOG_ERR, "Unable to set process uid/gid.");
exit = EXIT_FAILURE; exit = EXIT_FAILURE;
goto finish; goto finish;
} }
else else
{ {
Log(lc, LOG_DEBUG, "Set uid/gid to %s:%s.", tConfig->uid, tConfig->gid); Log(LOG_DEBUG, "Set uid/gid to %s:%s.", tConfig->uid, tConfig->gid);
} }
} }
else else
{ {
Log(lc, LOG_WARNING, "We are running as root, and we are not dropping to another user"); Log(LOG_WARNING, "We are running as root, and we are not dropping to another user");
Log(lc, LOG_WARNING, "because none was specified in the configuration file."); Log(LOG_WARNING, "because none was specified in the configuration file.");
Log(lc, LOG_WARNING, "This is probably a security issue."); Log(LOG_WARNING, "This is probably a security issue.");
} }
} }
else else
{ {
Log(lc, LOG_WARNING, "Not setting root directory, because we are not root."); Log(LOG_WARNING, "Not setting root directory, because we are not root.");
if (tConfig->uid && tConfig->gid) if (tConfig->uid && tConfig->gid)
{ {
if (getuid() != userInfo->pw_uid || getgid() != groupInfo->gr_gid) if (getuid() != userInfo->pw_uid || getgid() != groupInfo->gr_gid)
{ {
Log(lc, LOG_WARNING, "Not running as the uid/gid specified in the configuration."); Log(LOG_WARNING, "Not running as the uid/gid specified in the configuration.");
} }
else else
{ {
Log(lc, LOG_DEBUG, "Running as the uid/gid specified in the configuration."); Log(LOG_DEBUG, "Running as the uid/gid specified in the configuration.");
} }
} }
} }
@ -359,18 +355,16 @@ main(int argc, char **argv)
if (!tConfig->maxCache) if (!tConfig->maxCache)
{ {
Log(lc, LOG_WARNING, "Database caching is disabled."); Log(LOG_WARNING, "Database caching is disabled.");
Log(lc, LOG_WARNING, Log(LOG_WARNING, "If this is not what you intended, check the config file");
"If this is not what you intended, check the config file"); Log(LOG_WARNING, "and ensure that maxCache is a valid number of bytes.");
Log(lc, LOG_WARNING,
"and ensure that maxCache is a valid number of bytes.");
} }
matrixArgs.db = DbOpen(".", tConfig->maxCache); matrixArgs.db = DbOpen(".", tConfig->maxCache);
if (!matrixArgs.db) if (!matrixArgs.db)
{ {
Log(lc, LOG_ERR, "Unable to open data directory as a database."); Log(LOG_ERR, "Unable to open data directory as a database.");
exit = EXIT_FAILURE; exit = EXIT_FAILURE;
goto finish; goto finish;
} }
@ -378,28 +372,28 @@ main(int argc, char **argv)
cron = CronCreate(60 * 1000); /* 1-minute tick */ cron = CronCreate(60 * 1000); /* 1-minute tick */
if (!cron) if (!cron)
{ {
Log(lc, LOG_ERR, "Unable to set up job scheduler."); Log(LOG_ERR, "Unable to set up job scheduler.");
exit = EXIT_FAILURE; exit = EXIT_FAILURE;
goto finish; goto finish;
} }
Log(lc, LOG_DEBUG, "Registering jobs..."); Log(LOG_DEBUG, "Registering jobs...");
CronEvery(cron, 30 * 60 * 1000, (JobFunc *) UiaCleanup, &matrixArgs); CronEvery(cron, 30 * 60 * 1000, (JobFunc *) UiaCleanup, &matrixArgs);
Log(lc, LOG_NOTICE, "Starting job scheduler..."); Log(LOG_NOTICE, "Starting job scheduler...");
CronStart(cron); CronStart(cron);
Log(lc, LOG_NOTICE, "Starting server..."); Log(LOG_NOTICE, "Starting server...");
if (!HttpServerStart(httpServer)) if (!HttpServerStart(httpServer))
{ {
Log(lc, LOG_ERR, "Unable to start HTTP server."); Log(LOG_ERR, "Unable to start HTTP server.");
exit = EXIT_FAILURE; exit = EXIT_FAILURE;
goto finish; goto finish;
} }
Log(lc, LOG_INFO, "Listening on port: %d", tConfig->listenPort); Log(LOG_INFO, "Listening on port: %d", tConfig->listenPort);
sigAction.sa_handler = TelodendriaSignalHandler; sigAction.sa_handler = TelodendriaSignalHandler;
sigfillset(&sigAction.sa_mask); sigfillset(&sigAction.sa_mask);
@ -407,7 +401,7 @@ main(int argc, char **argv)
if (sigaction(SIGINT, &sigAction, NULL) < 0) if (sigaction(SIGINT, &sigAction, NULL) < 0)
{ {
Log(lc, LOG_ERR, "Unable to install signal handler."); Log(LOG_ERR, "Unable to install signal handler.");
exit = EXIT_FAILURE; exit = EXIT_FAILURE;
goto finish; goto finish;
} }
@ -417,18 +411,18 @@ main(int argc, char **argv)
HttpServerJoin(httpServer); HttpServerJoin(httpServer);
finish: finish:
Log(lc, LOG_NOTICE, "Shutting down..."); Log(LOG_NOTICE, "Shutting down...");
if (httpServer) if (httpServer)
{ {
HttpServerFree(httpServer); HttpServerFree(httpServer);
Log(lc, LOG_DEBUG, "Freed HTTP Server."); Log(LOG_DEBUG, "Freed HTTP Server.");
} }
if (cron) if (cron)
{ {
CronStop(cron); CronStop(cron);
CronFree(cron); CronFree(cron);
Log(lc, LOG_DEBUG, "Stopped and freed job scheduler."); Log(LOG_DEBUG, "Stopped and freed job scheduler.");
} }
/* /*
@ -442,11 +436,9 @@ finish:
DbClose(matrixArgs.db); DbClose(matrixArgs.db);
LogConfigTimeStampFormatSet(lc, NULL);
TelodendriaConfigFree(tConfig); TelodendriaConfigFree(tConfig);
Log(LOG_DEBUG, "Exiting with code '%d'.", exit);
Log(lc, LOG_DEBUG, "Exiting with code '%d'.", exit);
/* /*
* Uninstall the memory hook because it uses the Log * Uninstall the memory hook because it uses the Log
@ -455,7 +447,7 @@ finish:
*/ */
MemoryHook(NULL, NULL); MemoryHook(NULL, NULL);
LogConfigFree(lc); LogConfigFree(LogConfigGlobal());
/* Standard error should never have been opened, but just in case /* Standard error should never have been opened, but just in case
* it was, this doesn't hurt anything. */ * it was, this doesn't hurt anything. */

View file

@ -38,7 +38,6 @@ void
MatrixHttpHandler(HttpServerContext * context, void *argp) MatrixHttpHandler(HttpServerContext * context, void *argp)
{ {
MatrixHttpHandlerArgs *args = (MatrixHttpHandlerArgs *) argp; MatrixHttpHandlerArgs *args = (MatrixHttpHandlerArgs *) argp;
LogConfig *lc = args->lc;
Stream *stream; Stream *stream;
HashMap *response = NULL; HashMap *response = NULL;
@ -52,12 +51,10 @@ MatrixHttpHandler(HttpServerContext * context, void *argp)
requestPath = HttpRequestPath(context); requestPath = HttpRequestPath(context);
Log(lc, LOG_INFO, "%s %s", Log(LOG_INFO, "%s %s",
HttpRequestMethodToString(HttpRequestMethodGet(context)), HttpRequestMethodToString(HttpRequestMethodGet(context)),
requestPath); requestPath);
LogConfigIndent(lc);
HttpResponseStatus(context, HTTP_OK); HttpResponseStatus(context, HTTP_OK);
HttpResponseHeader(context, "Server", "Telodendria/" TELODENDRIA_VERSION); HttpResponseHeader(context, "Server", "Telodendria/" TELODENDRIA_VERSION);
@ -78,7 +75,7 @@ MatrixHttpHandler(HttpServerContext * context, void *argp)
HttpResponseStatus(context, HTTP_NO_CONTENT); HttpResponseStatus(context, HTTP_NO_CONTENT);
HttpSendHeaders(context); HttpSendHeaders(context);
goto finish; return;
} }
pathParts = MATRIX_PATH_CREATE(); pathParts = MATRIX_PATH_CREATE();
@ -146,9 +143,6 @@ MatrixHttpHandler(HttpServerContext * context, void *argp)
} }
MATRIX_PATH_FREE(pathParts); MATRIX_PATH_FREE(pathParts);
finish:
LogConfigUnindent(lc);
} }
HashMap * HashMap *

View file

@ -45,7 +45,6 @@ ROUTE_IMPL(RouteRefresh, args)
char *deviceId; char *deviceId;
Db *db = args->matrixArgs->db; Db *db = args->matrixArgs->db;
LogConfig *lc = args->matrixArgs->lc;
User *user = NULL; User *user = NULL;
DbRef *rtRef = NULL; DbRef *rtRef = NULL;
@ -96,9 +95,9 @@ ROUTE_IMPL(RouteRefresh, args)
if (!oAtRef) if (!oAtRef)
{ {
Log(lc, LOG_ERR, "Refresh token '%s' points to an access token that doesn't exist.", Log(LOG_ERR, "Refresh token '%s' points to an access token that doesn't exist.",
refreshToken); refreshToken);
Log(lc, LOG_WARNING, "This refresh token will be deleted."); Log(LOG_WARNING, "This refresh token will be deleted.");
HttpResponseStatus(args->context, HTTP_INTERNAL_SERVER_ERROR); HttpResponseStatus(args->context, HTTP_INTERNAL_SERVER_ERROR);
response = MatrixErrorCreate(M_UNKNOWN); response = MatrixErrorCreate(M_UNKNOWN);
@ -114,9 +113,9 @@ ROUTE_IMPL(RouteRefresh, args)
user = UserLock(db, JsonValueAsString(HashMapGet(DbJson(oAtRef), "user"))); user = UserLock(db, JsonValueAsString(HashMapGet(DbJson(oAtRef), "user")));
if (!user) if (!user)
{ {
Log(lc, LOG_ERR, "Access token '%s' points to a user that doesn't exist.", Log(LOG_ERR, "Access token '%s' points to a user that doesn't exist.",
oldAccessToken); oldAccessToken);
Log(lc, LOG_WARNING, "This access token will be deleted."); Log(LOG_WARNING, "This access token will be deleted.");
HttpResponseStatus(args->context, HTTP_INTERNAL_SERVER_ERROR); HttpResponseStatus(args->context, HTTP_INTERNAL_SERVER_ERROR);
response = MatrixErrorCreate(M_UNKNOWN); response = MatrixErrorCreate(M_UNKNOWN);

View file

@ -66,7 +66,6 @@ ROUTE_IMPL(RouteRegister, args)
char *fullUsername; char *fullUsername;
Db *db = args->matrixArgs->db; Db *db = args->matrixArgs->db;
LogConfig *lc = args->matrixArgs->lc;
User *user = NULL; User *user = NULL;
@ -249,7 +248,7 @@ ROUTE_IMPL(RouteRegister, args)
Free(loginInfo); Free(loginInfo);
} }
Log(lc, LOG_INFO, "Registered user '%s'", UserGetName(user)); Log(LOG_INFO, "Registered user '%s'", UserGetName(user));
UserUnlock(user); UserUnlock(user);
finish: finish:

View file

@ -67,9 +67,10 @@ const char
void void
TelodendriaMemoryHook(MemoryAction a, MemoryInfo * i, void *args) TelodendriaMemoryHook(MemoryAction a, MemoryInfo * i, void *args)
{ {
LogConfig *lc = (LogConfig *) args;
char *action; char *action;
(void) args;
switch (a) switch (a)
{ {
case MEMORY_ALLOCATE: case MEMORY_ALLOCATE:
@ -89,7 +90,7 @@ TelodendriaMemoryHook(MemoryAction a, MemoryInfo * i, void *args)
break; break;
} }
Log(lc, a == MEMORY_BAD_POINTER ? LOG_WARNING : LOG_DEBUG, Log(a == MEMORY_BAD_POINTER ? LOG_WARNING : LOG_DEBUG,
"%s:%d: %s %lu bytes of memory at %p.", "%s:%d: %s %lu bytes of memory at %p.",
MemoryInfoGetFile(i), MemoryInfoGetLine(i), MemoryInfoGetFile(i), MemoryInfoGetLine(i),
action, MemoryInfoGetSize(i), action, MemoryInfoGetSize(i),
@ -171,25 +172,25 @@ TelodendriaGenerateMemReport(void)
} }
void void
TelodendriaPrintHeader(LogConfig * lc) TelodendriaPrintHeader(void)
{ {
size_t i; size_t i;
for (i = 0; i < TELODENDRIA_LOGO_HEIGHT; i++) for (i = 0; i < TELODENDRIA_LOGO_HEIGHT; i++)
{ {
Log(lc, LOG_INFO, "%s", TelodendriaLogo[i]); Log(LOG_INFO, "%s", TelodendriaLogo[i]);
} }
for (i = 0; i < TELODENDRIA_HEADER_HEIGHT; i++) for (i = 0; i < TELODENDRIA_HEADER_HEIGHT; i++)
{ {
Log(lc, LOG_INFO, "%s", TelodendriaHeader[i]); Log(LOG_INFO, "%s", TelodendriaHeader[i]);
} }
Log(lc, LOG_INFO, "Telodendria v" TELODENDRIA_VERSION); Log(LOG_INFO, "Telodendria v" TELODENDRIA_VERSION);
Log(lc, LOG_INFO, ""); Log(LOG_INFO, "");
Log(lc, LOG_INFO, Log(LOG_INFO,
"Copyright (C) 2023 Jordan Bancino <@jordan:bancino.net>"); "Copyright (C) 2023 Jordan Bancino <@jordan:bancino.net>");
Log(lc, LOG_INFO, Log(LOG_INFO,
"Documentation/Support: https://telodendria.io"); "Documentation/Support: https://telodendria.io");
Log(lc, LOG_INFO, ""); Log(LOG_INFO, "");
} }

View file

@ -38,17 +38,17 @@
value = HashMapGet(config, key); \ value = HashMapGet(config, key); \
if (!value) \ if (!value) \
{ \ { \
Log(lc, LOG_ERR, "Missing required " key " directive."); \ Log(LOG_ERR, "Missing required " key " directive."); \
goto error; \ goto error; \
} \ } \
if (JsonValueType(value) == JSON_NULL) \ if (JsonValueType(value) == JSON_NULL) \
{ \ { \
Log(lc, LOG_ERR, "Missing value for " key " directive."); \ Log(LOG_ERR, "Missing value for " key " directive."); \
goto error; \ goto error; \
} \ } \
if (JsonValueType(value) != type) \ if (JsonValueType(value) != type) \
{ \ { \
Log(lc, LOG_ERR, "Expected " key " to be of type " #type); \ Log(LOG_ERR, "Expected " key " to be of type " #type); \
goto error; \ goto error; \
} }
@ -61,14 +61,14 @@
{ \ { \
if (JsonValueType(value) != JSON_STRING) \ if (JsonValueType(value) != JSON_STRING) \
{ \ { \
Log(lc, LOG_ERR, "Expected " key " to be of type JSON_STRING"); \ Log(LOG_ERR, "Expected " key " to be of type JSON_STRING"); \
goto error; \ goto error; \
} \ } \
into = StrDuplicate(JsonValueAsString(value)); \ into = StrDuplicate(JsonValueAsString(value)); \
} \ } \
else \ else \
{ \ { \
Log(lc, LOG_INFO, "Using default value " #default " for " key "."); \ Log(LOG_INFO, "Using default value " #default " for " key "."); \
into = default ? StrDuplicate(default) : NULL; \ into = default ? StrDuplicate(default) : NULL; \
} }
@ -78,14 +78,14 @@
{ \ { \
if (JsonValueType(value) != JSON_INTEGER) \ if (JsonValueType(value) != JSON_INTEGER) \
{ \ { \
Log(lc, LOG_ERR, "Expected " key " to be of type JSON_INTEGER"); \ Log(LOG_ERR, "Expected " key " to be of type JSON_INTEGER"); \
goto error; \ goto error; \
} \ } \
into = JsonValueAsInteger(value); \ into = JsonValueAsInteger(value); \
} \ } \
else \ else \
{ \ { \
Log(lc, LOG_INFO, "Using default value " #default " for " key "."); \ Log(LOG_INFO, "Using default value " #default " for " key "."); \
into = default; \ into = default; \
} }
@ -128,7 +128,7 @@ ConfigParseLog(LogConfig * lc, TelodendriaConfig * tConfig, HashMap * config)
} }
else else
{ {
Log(lc, LOG_ERR, "Invalid value for log.output: '%s'.", str); Log(LOG_ERR, "Invalid value for log.output: '%s'.", str);
goto error; goto error;
} }
@ -156,7 +156,7 @@ ConfigParseLog(LogConfig * lc, TelodendriaConfig * tConfig, HashMap * config)
} }
else else
{ {
Log(lc, LOG_ERR, "Invalid value for log.level: '%s'.", tConfig->logLevel); Log(LOG_ERR, "Invalid value for log.level: '%s'.", tConfig->logLevel);
goto error; goto error;
} }
@ -175,7 +175,7 @@ ConfigParseLog(LogConfig * lc, TelodendriaConfig * tConfig, HashMap * config)
{ {
if (JsonValueType(value) != JSON_BOOLEAN) if (JsonValueType(value) != JSON_BOOLEAN)
{ {
Log(lc, LOG_ERR, "Expected type JSON_BOOLEAN for log.color."); Log(LOG_ERR, "Expected type JSON_BOOLEAN for log.color.");
goto error; goto error;
} }
@ -222,11 +222,11 @@ TelodendriaConfigParse(HashMap * config, LogConfig * lc)
} }
else else
{ {
Log(lc, LOG_WARNING, "Base URL not specified. Assuming it's 'https://%s'.", tConfig->serverName); Log(LOG_WARNING, "Base URL not specified. Assuming it's 'https://%s'.", tConfig->serverName);
tConfig->baseUrl = Malloc(strlen(tConfig->serverName) + 10); tConfig->baseUrl = Malloc(strlen(tConfig->serverName) + 10);
if (!tConfig->baseUrl) if (!tConfig->baseUrl)
{ {
Log(lc, LOG_ERR, "Error allocating memory for default config value 'baseUrl'."); Log(LOG_ERR, "Error allocating memory for default config value 'baseUrl'.");
goto error; goto error;
} }
@ -247,8 +247,8 @@ TelodendriaConfigParse(HashMap * config, LogConfig * lc)
} }
else else
{ {
Log(lc, LOG_ERR, "Config directive 'runAs' should be a JSON object"); Log(LOG_ERR, "Config directive 'runAs' should be a JSON object");
Log(lc, LOG_ERR, "that contains a 'uid' and 'gid'."); Log(LOG_ERR, "that contains a 'uid' and 'gid'.");
goto error; goto error;
} }
} }

View file

@ -26,6 +26,8 @@
#if TLS_IMPL == TLS_LIBRESSL #if TLS_IMPL == TLS_LIBRESSL
#include <Memory.h> #include <Memory.h>
#include <Log.h>
#include <tls.h> /* LibreSSL TLS */ #include <tls.h> /* LibreSSL TLS */
typedef struct LibreSSLCookie typedef struct LibreSSLCookie
@ -77,6 +79,11 @@ TlsInitClient(int fd, const char *serverName)
error: error:
if (cookie->ctx) if (cookie->ctx)
{ {
if (tls_error(cookie->ctx))
{
Log(LOG_ERR, "TlsInitClient(): %s", tls_error(cookie->ctx));
}
tls_free(cookie->ctx); tls_free(cookie->ctx);
} }
@ -135,11 +142,20 @@ TlsInitServer(int fd, const char *crt, const char *key)
error: error:
if (cookie->ctx) if (cookie->ctx)
{ {
if (tls_error(cookie->ctx))
{
Log(LOG_ERR, "TlsInitServer(): %s", tls_error(cookie->ctx));
}
tls_free(cookie->ctx); tls_free(cookie->ctx);
} }
if (cookie->cctx) if (cookie->cctx)
{ {
if (tls_error(cookie->cctx))
{
Log(LOG_ERR, "TlsInitServer(): %s", tls_error(cookie->cctx));
}
tls_free(cookie->cctx); tls_free(cookie->cctx);
} }
@ -157,16 +173,28 @@ ssize_t
TlsRead(void *cookie, void *buf, size_t nBytes) TlsRead(void *cookie, void *buf, size_t nBytes)
{ {
LibreSSLCookie *tls = cookie; LibreSSLCookie *tls = cookie;
ssize_t ret = tls_read(tls->cctx ? tls->cctx : tls->ctx, buf, nBytes);
return tls_read(tls->cctx ? tls->cctx : tls->ctx, buf, nBytes); if (ret == -1)
{
Log(LOG_ERR, "TlsRead(): %s", tls_error(tls->cctx ? tls->cctx : tls->ctx));
}
return ret;
} }
ssize_t ssize_t
TlsWrite(void *cookie, void *buf, size_t nBytes) TlsWrite(void *cookie, void *buf, size_t nBytes)
{ {
LibreSSLCookie *tls = cookie; LibreSSLCookie *tls = cookie;
ssize_t ret = tls_write(tls->cctx ? tls->cctx : tls->ctx, buf, nBytes);
return tls_write(tls->cctx ? tls->cctx : tls->ctx, buf, nBytes); if (ret == -1)
{
Log(LOG_ERR, "TlsWrite(): %s", tls_error(tls->cctx ? tls->cctx : tls->ctx));
}
return ret;
} }
int int

View file

@ -491,7 +491,7 @@ UiaCleanup(MatrixHttpHandlerArgs * args)
Array *sessions = DbList(args->db, 1, "user_interactive"); Array *sessions = DbList(args->db, 1, "user_interactive");
size_t i; size_t i;
Log(args->lc, LOG_DEBUG, "User Interactive Auth sessions: %lu", Log(LOG_DEBUG, "User Interactive Auth sessions: %lu",
ArraySize(sessions)); ArraySize(sessions));
for (i = 0; i < ArraySize(sessions); i++) for (i = 0; i < ArraySize(sessions); i++)
{ {
@ -502,7 +502,7 @@ UiaCleanup(MatrixHttpHandlerArgs * args)
if (!ref) if (!ref)
{ {
Log(args->lc, LOG_ERR, "Unable to lock uia %s for inspection.", Log(LOG_ERR, "Unable to lock uia %s for inspection.",
session); session);
continue; continue;
} }
@ -515,7 +515,7 @@ UiaCleanup(MatrixHttpHandlerArgs * args)
{ {
DbUnlock(args->db, ref); DbUnlock(args->db, ref);
DbDelete(args->db, 2, "user_interactive", session); DbDelete(args->db, 2, "user_interactive", session);
Log(args->lc, LOG_DEBUG, "Deleted session %s", session); Log(LOG_DEBUG, "Deleted session %s", session);
} }
DbUnlock(args->db, ref); DbUnlock(args->db, ref);

View file

@ -39,6 +39,9 @@ typedef struct LogConfig LogConfig;
extern LogConfig * extern LogConfig *
LogConfigCreate(void); LogConfigCreate(void);
extern LogConfig *
LogConfigGlobal(void);
extern void extern void
LogConfigFree(LogConfig *); LogConfigFree(LogConfig *);
@ -67,6 +70,12 @@ extern void
LogConfigTimeStampFormatSet(LogConfig *, char *); LogConfigTimeStampFormatSet(LogConfig *, char *);
extern void extern void
Log(LogConfig *, int, const char *,...); Logv(LogConfig *, int, const char *, va_list);
extern void
LogTo(LogConfig *, int, const char *,...);
extern void
Log(int, const char *, ...);
#endif #endif

View file

@ -69,7 +69,6 @@ typedef enum MatrixError
typedef struct MatrixHttpHandlerArgs typedef struct MatrixHttpHandlerArgs
{ {
LogConfig *lc;
TelodendriaConfig *config; TelodendriaConfig *config;
Db *db; Db *db;
} MatrixHttpHandlerArgs; } MatrixHttpHandlerArgs;

View file

@ -46,6 +46,6 @@ extern void
TelodendriaGenerateMemReport(void); TelodendriaGenerateMemReport(void);
extern void extern void
TelodendriaPrintHeader(LogConfig *); TelodendriaPrintHeader(void);
#endif #endif