/*- * Copyright 2016 Vsevolod Stakhov * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "config.h" #include "libutil/util.h" #include "libserver/cfg_file.h" #include "libserver/cfg_rcl.h" #include "libserver/worker_util.h" #include "libserver/rspamd_control.h" #include "libutil/addr.h" #include "unix-std.h" #ifdef HAVE_GLOB_H #include #endif static gpointer init_log_helper (struct rspamd_config *cfg); static void start_log_helper (struct rspamd_worker *worker); worker_t log_helper_worker = { "log_helper", /* Name */ init_log_helper, /* Init function */ start_log_helper, /* Start function */ RSPAMD_WORKER_UNIQUE | RSPAMD_WORKER_KILLABLE, SOCK_STREAM, /* TCP socket */ RSPAMD_WORKER_VER /* Version info */ }; static const guint64 rspamd_log_helper_magic = 0x1090bb46aaa74c9aULL; /* * Worker's context */ struct log_helper_ctx { guint64 magic; struct rspamd_config *cfg; struct event_base *ev_base; struct event log_ev; gint pair[2]; }; static gpointer init_log_helper (struct rspamd_config *cfg) { struct log_helper_ctx *ctx; GQuark type; type = g_quark_try_string ("log_helper"); ctx = g_malloc0 (sizeof (*ctx)); ctx->magic = rspamd_log_helper_magic; ctx->cfg = cfg; return ctx; } static void rspamd_log_helper_read (gint fd, short what, gpointer ud) { struct log_helper_ctx *ctx = ud; guchar buf[1024]; gssize r; guint32 n, i; struct rspamd_protocol_log_message_sum *sm; GString *out; r = read (fd, buf, sizeof (buf)); if (r >= (gssize)sizeof (struct rspamd_protocol_log_message_sum)) { memcpy (&n, buf, sizeof (n)); if (n != (r - sizeof (guint32)) / sizeof (guint32)) { msg_warn ("cannot read data from log pipe: bad length: %d elements " "announced but %d available", n, (r - sizeof (guint32)) / sizeof (guint32)); } else { sm = g_malloc (r); memcpy (sm, buf, r); out = g_string_sized_new (31); for (i = 0; i < n; i ++) { rspamd_printf_gstring (out, "%s%d", i == 0 ? "" : ", ", sm->results[i]); } msg_info ("got log line: %V", out); g_string_free (out, TRUE); g_free (sm); } } else if (r == -1) { msg_warn ("cannot read data from log pipe: %s", strerror (errno)); } } static void rspamd_log_helper_reply_handler (struct rspamd_worker *worker, struct rspamd_srv_reply *rep, gint rep_fd, gpointer ud) { struct log_helper_ctx *ctx = ud; close (ctx->pair[1]); event_set (&ctx->log_ev, ctx->pair[0], EV_READ | EV_PERSIST, rspamd_log_helper_read, ctx); event_base_set (ctx->ev_base, &ctx->log_ev); event_add (&ctx->log_ev, NULL); } static void start_log_helper (struct rspamd_worker *worker) { struct log_helper_ctx *ctx = worker->ctx; gssize r = -1; static struct rspamd_srv_command srv_cmd; ctx->ev_base = rspamd_prepare_worker (worker, "log_helper", NULL); #ifdef HAVE_SOCK_SEQPACKET r = socketpair (AF_LOCAL, SOCK_SEQPACKET, 0, ctx->pair); #endif if (r == -1 && socketpair (AF_LOCAL, SOCK_DGRAM, 0, ctx->pair) == -1) { msg_err ("cannot create socketpair: %s, exiting now", strerror (errno)); /* Prevent new processes spawning */ exit (EXIT_SUCCESS); } srv_cmd.type = RSPAMD_SRV_LOG_PIPE; srv_cmd.cmd.log_pipe.type = RSPAMD_LOG_PIPE_SYMBOLS; rspamd_srv_send_command (worker, ctx->ev_base, &srv_cmd, ctx->pair[1], rspamd_log_helper_reply_handler, ctx); event_base_loop (ctx->ev_base, 0); close (ctx->pair[0]); rspamd_worker_block_signals (); rspamd_log_close (worker->srv->logger); exit (EXIT_SUCCESS); }