log-connection.c revision 5f5870385cff47efd2f58e7892f251cf13761528
c25356d5978632df6203437e1953bcb29e0c736fTimo Sirainen/* Copyright (c) 2005-2012 Dovecot authors, see the included COPYING file */
c25356d5978632df6203437e1953bcb29e0c736fTimo Sirainen
e8a59a1671127f87e2d22f42e84c572f28299d81Timo Sirainen#include "lib.h"
dbb1fb1c51727e2050792f8c333b212e22a36d69Timo Sirainen#include "array.h"
6789ed17e7ca4021713507baf0dcf6979bb42e0cTimo Sirainen#include "ioloop.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "istream.h"
dbb1fb1c51727e2050792f8c333b212e22a36d69Timo Sirainen#include "llist.h"
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen#include "hash.h"
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen#include "master-interface.h"
e667602217af55105d44d8d9b75f09a8a9ac2f14Timo Sirainen#include "master-service.h"
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen#include "log-error-buffer.h"
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen#include "log-connection.h"
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen#include <stdio.h>
d67fde1a8ebc1d85704c5986d8f93aae97eccef3Timo Sirainen#include <stdlib.h>
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen#include <unistd.h>
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
55773f17bccf6361d6599ffcbe072d7c9fe205bfTimo Sirainen#define FATAL_QUEUE_TIMEOUT_MSECS 500
55773f17bccf6361d6599ffcbe072d7c9fe205bfTimo Sirainen
55773f17bccf6361d6599ffcbe072d7c9fe205bfTimo Sirainenstruct log_client {
4b95b3147352f12e5f5df7267c3021ac6cfa8debTimo Sirainen struct ip_addr ip;
147a788fea2a88f7125b27226451271d55cf5b01Timo Sirainen char *prefix;
b19a1420da0618a10edf67c2cfd13c8c8633057aTimo Sirainen unsigned int fatal_logged:1;
bb6a0eeab27569790d58a036f67dcd2a965fc539Timo Sirainen};
6e8f0036cad59d1d6bcd9ef69bfe712d01656ca3Timo Sirainen
52fbebc87d7ae4fc4585863d38cb87f166a6521aTimo Sirainenstruct log_connection {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen struct log_connection *prev, *next;
31be5ed1551c98cddeb2295a594f010aaf4b76bcTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen struct log_error_buffer *errorbuf;
31be5ed1551c98cddeb2295a594f010aaf4b76bcTimo Sirainen int fd;
31be5ed1551c98cddeb2295a594f010aaf4b76bcTimo Sirainen int listen_fd;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen struct io *io;
1b4441e3e6f9e78ebeae8218de971959cd55bf60Timo Sirainen struct istream *input;
1b4441e3e6f9e78ebeae8218de971959cd55bf60Timo Sirainen
1b4441e3e6f9e78ebeae8218de971959cd55bf60Timo Sirainen char *default_prefix;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen /* pid -> struct log_client* */
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen struct hash_table *clients;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen unsigned int master:1;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen unsigned int handshaked:1;
e667602217af55105d44d8d9b75f09a8a9ac2f14Timo Sirainen};
e667602217af55105d44d8d9b75f09a8a9ac2f14Timo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenstatic struct log_connection *log_connections = NULL;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenstatic ARRAY_DEFINE(logs_by_fd, struct log_connection *);
e667602217af55105d44d8d9b75f09a8a9ac2f14Timo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenstatic struct log_client *log_client_get(struct log_connection *log, pid_t pid)
884228e5496378bada39a932db67aa3d9478198fTimo Sirainen{
884228e5496378bada39a932db67aa3d9478198fTimo Sirainen struct log_client *client;
884228e5496378bada39a932db67aa3d9478198fTimo Sirainen
1b4441e3e6f9e78ebeae8218de971959cd55bf60Timo Sirainen client = hash_table_lookup(log->clients, POINTER_CAST(pid));
1b4441e3e6f9e78ebeae8218de971959cd55bf60Timo Sirainen if (client == NULL) {
1b4441e3e6f9e78ebeae8218de971959cd55bf60Timo Sirainen client = i_new(struct log_client, 1);
1b4441e3e6f9e78ebeae8218de971959cd55bf60Timo Sirainen hash_table_insert(log->clients, POINTER_CAST(pid), client);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen }
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen return client;
55773f17bccf6361d6599ffcbe072d7c9fe205bfTimo Sirainen}
55773f17bccf6361d6599ffcbe072d7c9fe205bfTimo Sirainen
55773f17bccf6361d6599ffcbe072d7c9fe205bfTimo Sirainenstatic void log_client_free(struct log_connection *log,
55773f17bccf6361d6599ffcbe072d7c9fe205bfTimo Sirainen struct log_client *client, pid_t pid)
55773f17bccf6361d6599ffcbe072d7c9fe205bfTimo Sirainen{
55773f17bccf6361d6599ffcbe072d7c9fe205bfTimo Sirainen hash_table_remove(log->clients, POINTER_CAST(pid));
55773f17bccf6361d6599ffcbe072d7c9fe205bfTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen i_free(client->prefix);
e192a3b1ca8ae857e7d87298ea507d32977ba570Timo Sirainen i_free(client);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen}
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenstatic void log_parse_option(struct log_connection *log,
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen const struct failure_line *failure)
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen{
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen struct log_client *client;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen client = log_client_get(log, failure->pid);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (strncmp(failure->text, "ip=", 3) == 0)
dbb1fb1c51727e2050792f8c333b212e22a36d69Timo Sirainen (void)net_addr2ip(failure->text + 3, &client->ip);
dbb1fb1c51727e2050792f8c333b212e22a36d69Timo Sirainen else if (strncmp(failure->text, "prefix=", 7) == 0) {
e8a59a1671127f87e2d22f42e84c572f28299d81Timo Sirainen i_free(client->prefix);
90adcaa0a00eba29b7fbd50ca66be11c8d086d6aTimo Sirainen client->prefix = i_strdup(failure->text + 7);
d67fde1a8ebc1d85704c5986d8f93aae97eccef3Timo Sirainen }
e8a59a1671127f87e2d22f42e84c572f28299d81Timo Sirainen}
6789ed17e7ca4021713507baf0dcf6979bb42e0cTimo Sirainen
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenstatic void
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainenclient_log_ctx(struct log_connection *log,
6789ed17e7ca4021713507baf0dcf6979bb42e0cTimo Sirainen const struct failure_context *ctx, time_t log_time,
e8a59a1671127f87e2d22f42e84c572f28299d81Timo Sirainen const char *prefix, const char *text)
6e8f0036cad59d1d6bcd9ef69bfe712d01656ca3Timo Sirainen{
46c903eac3abcc7d32780da76ee6a79c26d185b6Timo Sirainen struct log_error err;
52fbebc87d7ae4fc4585863d38cb87f166a6521aTimo Sirainen
b674bd911aaab7e8b1a77c106a0b5bccb603439fStephan Bosch switch (ctx->type) {
e8a59a1671127f87e2d22f42e84c572f28299d81Timo Sirainen case LOG_TYPE_DEBUG:
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen case LOG_TYPE_INFO:
e667602217af55105d44d8d9b75f09a8a9ac2f14Timo Sirainen case LOG_TYPE_COUNT:
f46885a5b78b15a8d2419f6e5d13b643bd85e41fTimo Sirainen case LOG_TYPE_OPTION:
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen break;
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen case LOG_TYPE_WARNING:
ae1b268ffff743ad9927c304a1344c5cbd7f909dTimo Sirainen case LOG_TYPE_ERROR:
942312f81841c0e3a8b5609c7530826afa5a7f3bTimo Sirainen case LOG_TYPE_FATAL:
ecd69c4e8371853667e01b0c16d436ef7f7393e2Timo Sirainen case LOG_TYPE_PANIC:
ecd69c4e8371853667e01b0c16d436ef7f7393e2Timo Sirainen memset(&err, 0, sizeof(err));
6389aeec8c26b585e583c364b48ad12adf741898Timo Sirainen err.type = ctx->type;
1af0a59380337d4d9adc634da47888c150869f65Timo Sirainen err.timestamp = log_time;
1af0a59380337d4d9adc634da47888c150869f65Timo Sirainen err.prefix = prefix;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen err.text = text;
6f6f3dc5b33b09097192124bce17b7017d6bbfcfTimo Sirainen log_error_buffer_add(log->errorbuf, &err);
96541d31299bb40b5a6efdbf9b4cb3d4f4b4a069Timo Sirainen break;
49be238e250e99af8c69321264a461d8f6ceef62Timo Sirainen }
96541d31299bb40b5a6efdbf9b4cb3d4f4b4a069Timo Sirainen i_set_failure_prefix(prefix);
644268f7848a7c4221146d0b11feb8ed5bbed233Timo Sirainen i_log_type(ctx, "%s", text);
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen i_set_failure_prefix("log: ");
a757f31393b9d6fc7760a9dec8363404ab3ae576Timo Sirainen}
e8a59a1671127f87e2d22f42e84c572f28299d81Timo Sirainen
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainenstatic void
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainenclient_log_fatal(struct log_connection *log, struct log_client *client,
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen const char *line, time_t log_time, const struct tm *tm)
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen{
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen struct failure_context failure_ctx;
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen const char *prefix = log->default_prefix;
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen memset(&failure_ctx, 0, sizeof(failure_ctx));
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen failure_ctx.type = LOG_TYPE_FATAL;
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen failure_ctx.timestamp = tm;
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen if (client != NULL) {
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen if (client->prefix != NULL)
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen prefix = client->prefix;
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen else if (client->ip.family != 0) {
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen line = t_strdup_printf("%s [last ip=%s]",
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen line, net_ip2addr(&client->ip));
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen }
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen }
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen client_log_ctx(log, &failure_ctx, log_time, prefix,
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen t_strconcat("master: ", line, NULL));
e8a59a1671127f87e2d22f42e84c572f28299d81Timo Sirainen}
e8a59a1671127f87e2d22f42e84c572f28299d81Timo Sirainen
e8a59a1671127f87e2d22f42e84c572f28299d81Timo Sirainenstatic void
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainenlog_parse_master_line(const char *line, time_t log_time, const struct tm *tm)
e8a59a1671127f87e2d22f42e84c572f28299d81Timo Sirainen{
d22301419109ed4a38351715e6760011421dadecTimo Sirainen struct log_connection *const *logs, *log;
e8a59a1671127f87e2d22f42e84c572f28299d81Timo Sirainen struct log_client *client;
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen const char *p, *p2;
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen unsigned int count;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen int service_fd;
98dd8e6e81f11f1e6040ca72f4916242d246c863Timo Sirainen long pid;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
4ee00532a265bdfb38539d811fcd12d51210ac35Timo Sirainen p = strchr(line, ' ');
86ad841251a38aa9ffcf4db4ee2c9fd449121bcbTimo Sirainen if (p == NULL || (p2 = strchr(++p, ' ')) == NULL) {
86ad841251a38aa9ffcf4db4ee2c9fd449121bcbTimo Sirainen i_error("Received invalid input from master: %s", line);
86ad841251a38aa9ffcf4db4ee2c9fd449121bcbTimo Sirainen return;
86ad841251a38aa9ffcf4db4ee2c9fd449121bcbTimo Sirainen }
4ee00532a265bdfb38539d811fcd12d51210ac35Timo Sirainen service_fd = atoi(t_strcut(line, ' '));
4ee00532a265bdfb38539d811fcd12d51210ac35Timo Sirainen pid = strtol(t_strcut(p, ' '), NULL, 10);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen
c36ec256c1bd1abe1c12e792cf64f0b7e3b3135aTimo Sirainen logs = array_get(&logs_by_fd, &count);
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen if (service_fd >= (int)count || logs[service_fd] == NULL) {
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainen i_error("Received master input for invalid service_fd %d: %s",
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen service_fd, line);
4906414a3e02e7750b0e702ec992afba20a0338aTimo Sirainen return;
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen }
e8a59a1671127f87e2d22f42e84c572f28299d81Timo Sirainen log = logs[service_fd];
e8a59a1671127f87e2d22f42e84c572f28299d81Timo Sirainen client = hash_table_lookup(log->clients, POINTER_CAST(pid));
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen line = p2 + 1;
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen if (strcmp(line, "BYE") == 0) {
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen if (client == NULL) {
4bab017ff69d6877253dde54b5a5f1f3f5e92fdfTimo Sirainen /* we haven't seen anything important from this client.
4bab017ff69d6877253dde54b5a5f1f3f5e92fdfTimo Sirainen it's not an error. */
4bab017ff69d6877253dde54b5a5f1f3f5e92fdfTimo Sirainen return;
4bab017ff69d6877253dde54b5a5f1f3f5e92fdfTimo Sirainen }
4bab017ff69d6877253dde54b5a5f1f3f5e92fdfTimo Sirainen log_client_free(log, client, pid);
7631f16156aca373004953fe6b01a7f343fb47e0Timo Sirainen } else if (strncmp(line, "FATAL ", 6) == 0) {
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen client_log_fatal(log, client, line + 6, log_time, tm);
aa247243412a49f9bdebf7255e131dc6ece4ed46Timo Sirainen } else if (strncmp(line, "DEFAULT-FATAL ", 14) == 0) {
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen /* If the client has logged a fatal/panic, don't log this
ecd69c4e8371853667e01b0c16d436ef7f7393e2Timo Sirainen message. */
ecd69c4e8371853667e01b0c16d436ef7f7393e2Timo Sirainen if (client == NULL || !client->fatal_logged)
ecd69c4e8371853667e01b0c16d436ef7f7393e2Timo Sirainen client_log_fatal(log, client, line + 14, log_time, tm);
823af4a2cc4e2ce90d12f9ec362160546aa4c4b8Timo Sirainen } else {
823af4a2cc4e2ce90d12f9ec362160546aa4c4b8Timo Sirainen i_error("Received unknown command from master: %s", line);
0d86aa0d47f7393c669c084b34c0537b193688adTimo Sirainen }
15979d11259a2391c943bb47af4d174df52d9eb9Timo Sirainen}
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen
489301ee88b2174e3171875e979e667de2c4a174Timo Sirainenstatic void
e8a59a1671127f87e2d22f42e84c572f28299d81Timo Sirainenlog_it(struct log_connection *log, const char *line,
77af0bd168cf3e3ddc3ae68abc82bfad7e9b5ff4Timo Sirainen time_t log_time, const struct tm *tm)
6789ed17e7ca4021713507baf0dcf6979bb42e0cTimo Sirainen{
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen struct failure_line failure;
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen struct failure_context failure_ctx;
d2b94d25f842cd1b7acaf4dd7de858f7c6a821c9Timo Sirainen struct log_client *client = NULL;
d2b94d25f842cd1b7acaf4dd7de858f7c6a821c9Timo Sirainen const char *prefix;
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen
2aecf7be5834e7f6520f8deaad683a6fa1de4d61Timo Sirainen if (log->master) {
02b78558dc03daa2e7da2010b63f247b49936a38Timo Sirainen T_BEGIN {
02b78558dc03daa2e7da2010b63f247b49936a38Timo Sirainen log_parse_master_line(line, log_time, tm);
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen } T_END;
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen return;
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen }
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen i_failure_parse_line(line, &failure);
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen switch (failure.log_type) {
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen case LOG_TYPE_FATAL:
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen case LOG_TYPE_PANIC:
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen client = log_client_get(log, failure.pid);
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen client->fatal_logged = TRUE;
573f0491a5733fe21fa062a455acb4790b4e0499Timo Sirainen break;
1bdda5c0c30463160c47151537e6bb2c6c994841Timo Sirainen case LOG_TYPE_OPTION:
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen log_parse_option(log, &failure);
a2f250a332dfc1e6cd4ffd196c621eb9dbf7b8a1Timo Sirainen return;
f46885a5b78b15a8d2419f6e5d13b643bd85e41fTimo Sirainen default:
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen client = hash_table_lookup(log->clients,
a757f31393b9d6fc7760a9dec8363404ab3ae576Timo Sirainen POINTER_CAST(failure.pid));
a757f31393b9d6fc7760a9dec8363404ab3ae576Timo Sirainen break;
c0225f7f6b43d34dc58c17d3304f0fd60ab89894Timo Sirainen }
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen i_assert(failure.log_type < LOG_TYPE_COUNT);
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen memset(&failure_ctx, 0, sizeof(failure_ctx));
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen failure_ctx.type = failure.log_type;
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen failure_ctx.timestamp = tm;
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen prefix = client != NULL && client->prefix != NULL ?
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen client->prefix : log->default_prefix;
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen client_log_ctx(log, &failure_ctx, log_time, prefix, failure.text);
306b3f41b05da642d87e7ca7a1496efce9f5902fTimo Sirainen}
306b3f41b05da642d87e7ca7a1496efce9f5902fTimo Sirainen
306b3f41b05da642d87e7ca7a1496efce9f5902fTimo Sirainenstatic int log_connection_handshake(struct log_connection *log)
e53ab6c7081246c865917f9aa0eff031a08ad1e7Timo Sirainen{
e53ab6c7081246c865917f9aa0eff031a08ad1e7Timo Sirainen struct log_service_handshake handshake;
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen const unsigned char *data;
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen size_t size;
21aaa6affb9f134112b75b5db737309fc35ef1cfMartti Rannanjärvi ssize_t ret;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen ret = i_stream_read(log->input);
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen if (ret < 0) {
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen i_error("read(log pipe) failed: %m");
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen return -1;
ad48319996942463675b53877092ab7e13a7a75aTimo Sirainen }
f46885a5b78b15a8d2419f6e5d13b643bd85e41fTimo Sirainen if ((size_t)ret < sizeof(handshake)) {
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen /* this isn't a handshake */
421d30619384e72a27e2a5d13ff6525aff4d17feTimo Sirainen return 0;
838e367716bbd5e44b4a1691db9cbf72af53e9f0Timo Sirainen }
0206dc57f2c04da69599dea5816235cfeb2b897aMartti Rannanjärvi
0206dc57f2c04da69599dea5816235cfeb2b897aMartti Rannanjärvi data = i_stream_get_data(log->input, &size);
6564208826b0f46a00f010d1b5711d85944c3c88Timo Sirainen i_assert(size >= sizeof(handshake));
50de46721446795c42943c572625f2f1a9abfe01Timo Sirainen memcpy(&handshake, data, sizeof(handshake));
d052dcfff0c96a0af17a3158e51f709edf4b93a1Timo Sirainen
d052dcfff0c96a0af17a3158e51f709edf4b93a1Timo Sirainen if (handshake.log_magic != MASTER_LOG_MAGIC) {
bc15c6934f69be09cca1e9f87f9dc344f77e8b7cTimo Sirainen /* this isn't a handshake */
01404d41657a104c5ea1c12bb87f9c321e9c1ac4Timo Sirainen return 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen if (handshake.prefix_len > size - sizeof(handshake)) {
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen i_error("Missing prefix data in handshake");
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen return -1;
b2723d68898e4a6a6e6ba2a06926dcaa1911daf5Timo Sirainen }
b2723d68898e4a6a6e6ba2a06926dcaa1911daf5Timo Sirainen log->default_prefix = i_strndup(data + sizeof(handshake),
b2723d68898e4a6a6e6ba2a06926dcaa1911daf5Timo Sirainen handshake.prefix_len);
424633d1a1e22139a5ab9345f807a89d0792ead3Timo Sirainen i_stream_skip(log->input, sizeof(handshake) + handshake.prefix_len);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
5cda0bfea032000c4a51134c748d9efe6614870bTimo Sirainen if (strcmp(log->default_prefix, MASTER_LOG_PREFIX_NAME) == 0) {
97511ac4d7607e1ba64ce151eda3d9b5f9775519Timo Sirainen if (log->listen_fd != MASTER_LISTEN_FD_FIRST) {
5cda0bfea032000c4a51134c748d9efe6614870bTimo Sirainen i_error("Received master prefix in handshake "
5cda0bfea032000c4a51134c748d9efe6614870bTimo Sirainen "from non-master fd %d", log->fd);
97511ac4d7607e1ba64ce151eda3d9b5f9775519Timo Sirainen return -1;
e54512a5189192fe72d1e2c53927c98c5ac920b4Timo Sirainen }
e54512a5189192fe72d1e2c53927c98c5ac920b4Timo Sirainen log->master = TRUE;
2ebeb22b9a8a8bb7fbe2f2e2908478a220792b87Timo Sirainen }
2d1663351e67fd778ed34df09b8ad5fe29da23d9Timo Sirainen log->handshaked = TRUE;
2d1663351e67fd778ed34df09b8ad5fe29da23d9Timo Sirainen return 0;
2ebeb22b9a8a8bb7fbe2f2e2908478a220792b87Timo Sirainen}
b0a901f1dbe9e05ac1c92a0974af6bce0274f31aTimo Sirainen
b0a901f1dbe9e05ac1c92a0974af6bce0274f31aTimo Sirainenstatic void log_connection_input(struct log_connection *log)
e8dc3747de75e2bf208f0f2dbdbae4a279b5ee6fTimo Sirainen{
b0a901f1dbe9e05ac1c92a0974af6bce0274f31aTimo Sirainen const char *line;
02b78558dc03daa2e7da2010b63f247b49936a38Timo Sirainen ssize_t ret;
02b78558dc03daa2e7da2010b63f247b49936a38Timo Sirainen time_t now;
e8a59a1671127f87e2d22f42e84c572f28299d81Timo Sirainen struct tm tm;
if (!log->handshaked) {
if (log_connection_handshake(log) < 0) {
log_connection_destroy(log);
return;
}
}
while ((ret = i_stream_read(log->input)) > 0 || ret == -2) {
/* get new timestamps for every read() */
now = time(NULL);
tm = *localtime(&now);
while ((line = i_stream_next_line(log->input)) != NULL)
log_it(log, line, now, &tm);
}
if (log->input->eof)
log_connection_destroy(log);
else if (log->input->stream_errno != 0) {
i_error("read(log pipe) failed: %m");
log_connection_destroy(log);
} else {
i_assert(!log->input->closed);
}
}
struct log_connection *
log_connection_create(struct log_error_buffer *errorbuf, int fd, int listen_fd)
{
struct log_connection *log;
log = i_new(struct log_connection, 1);
log->errorbuf = errorbuf;
log->fd = fd;
log->listen_fd = listen_fd;
log->io = io_add(fd, IO_READ, log_connection_input, log);
log->input = i_stream_create_fd(fd, PIPE_BUF, FALSE);
log->clients = hash_table_create(default_pool, default_pool, 0,
NULL, NULL);
array_idx_set(&logs_by_fd, listen_fd, &log);
DLLIST_PREPEND(&log_connections, log);
log_connection_input(log);
return log;
}
void log_connection_destroy(struct log_connection *log)
{
struct hash_iterate_context *iter;
void *key, *value;
array_idx_clear(&logs_by_fd, log->listen_fd);
DLLIST_REMOVE(&log_connections, log);
iter = hash_table_iterate_init(log->clients);
while (hash_table_iterate(iter, &key, &value))
i_free(value);
hash_table_iterate_deinit(&iter);
hash_table_destroy(&log->clients);
i_stream_unref(&log->input);
if (log->io != NULL)
io_remove(&log->io);
if (close(log->fd) < 0)
i_error("close(log connection fd) failed: %m");
i_free(log->default_prefix);
i_free(log);
}
void log_connections_init(void)
{
i_array_init(&logs_by_fd, 64);
}
void log_connections_deinit(void)
{
/* normally we don't exit until all log connections are gone,
but we could get here when we're being killed by a signal */
while (log_connections != NULL)
log_connection_destroy(log_connections);
array_free(&logs_by_fd);
}