123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335 |
- /*
- * Copyright (c) 2009, Rambler media
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY Rambler media ''AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL Rambler BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
- #include "config.h"
- #include "util.h"
- #include "main.h"
- #include "message.h"
- #include "protocol.h"
- #include "upstream.h"
- #include "cfg_file.h"
- #include "cfg_xml.h"
- #include "map.h"
- #include "dns.h"
- #include "tokenizers/tokenizers.h"
- #include "classifiers/classifiers.h"
- #include "binlog.h"
- #include "statfile_sync.h"
- #include "lua/lua_common.h"
-
- #define END "END" CRLF
-
- /* 120 seconds for controller's IO */
- #define CONTROLLER_IO_TIMEOUT 120
-
- /* Init functions */
- gpointer init_controller ();
- void start_controller (struct rspamd_worker *worker);
-
- worker_t controller_worker = {
- "controller", /* Name */
- init_controller, /* Init function */
- start_controller, /* Start function */
- TRUE, /* Has socket */
- FALSE, /* Non unique */
- FALSE, /* Non threaded */
- TRUE /* Killable */
- };
-
- enum command_type {
- COMMAND_PASSWORD,
- COMMAND_QUIT,
- COMMAND_RELOAD,
- COMMAND_STAT,
- COMMAND_SHUTDOWN,
- COMMAND_UPTIME,
- COMMAND_LEARN,
- COMMAND_LEARN_SPAM,
- COMMAND_LEARN_HAM,
- COMMAND_HELP,
- COMMAND_COUNTERS,
- COMMAND_SYNC,
- COMMAND_WEIGHTS
- };
-
- struct controller_command {
- gchar *command;
- gboolean privilleged;
- enum command_type type;
- };
-
- struct custom_controller_command {
- const gchar *command;
- gboolean privilleged;
- gboolean require_message;
- controller_func_t handler;
- };
-
- struct rspamd_controller_ctx {
- char *password;
- guint32 timeout;
- struct rspamd_dns_resolver *resolver;
- struct event_base *ev_base;
- };
-
- static struct controller_command commands[] = {
- {"password", FALSE, COMMAND_PASSWORD},
- {"quit", FALSE, COMMAND_QUIT},
- {"reload", TRUE, COMMAND_RELOAD},
- {"stat", FALSE, COMMAND_STAT},
- {"shutdown", TRUE, COMMAND_SHUTDOWN},
- {"uptime", FALSE, COMMAND_UPTIME},
- {"learn", TRUE, COMMAND_LEARN},
- {"weights", FALSE, COMMAND_WEIGHTS},
- {"help", FALSE, COMMAND_HELP},
- {"counters", FALSE, COMMAND_COUNTERS},
- {"sync", FALSE, COMMAND_SYNC},
- {"learn_spam", TRUE, COMMAND_LEARN_SPAM},
- {"learn_ham", TRUE, COMMAND_LEARN_HAM}
- };
-
- static GList *custom_commands = NULL;
-
- static time_t start_time;
-
- static gchar greetingbuf[1024];
- static sig_atomic_t wanna_die = 0;
- extern rspamd_hash_t *counters;
-
- static gboolean controller_write_socket (void *arg);
-
- #ifndef HAVE_SA_SIGINFO
- static void
- sig_handler (gint signo)
- #else
- static void
- sig_handler (gint signo, siginfo_t *info, void *unused)
- #endif
- {
- struct timeval tv;
- switch (signo) {
- case SIGINT:
- case SIGTERM:
- if (!wanna_die) {
- wanna_die = 1;
- tv.tv_sec = 0;
- tv.tv_usec = 0;
- event_loopexit (&tv);
-
- #ifdef WITH_GPERF_TOOLS
- ProfilerStop ();
- #endif
- }
- break;
- }
- }
-
- static void
- sigusr2_handler (gint fd, short what, void *arg)
- {
- struct rspamd_worker *worker = (struct rspamd_worker *)arg;
- /* Do not accept new connections, preparing to end worker's process */
- struct timeval tv;
- tv.tv_sec = 2;
- tv.tv_usec = 0;
- event_del (&worker->sig_ev_usr1);
- event_del (&worker->sig_ev_usr2);
- event_del (&worker->bind_ev);
- msg_info ("controller's shutdown is pending in %d sec", 2);
- event_loopexit (&tv);
- return;
- }
-
- /*
- * Reopen log is designed by sending sigusr1 to active workers and pending shutdown of them
- */
- static void
- sigusr1_handler (gint fd, short what, void *arg)
- {
- struct rspamd_worker *worker = (struct rspamd_worker *) arg;
-
- reopen_log (worker->srv->logger);
-
- return;
- }
-
- static void
- free_session (void *ud)
- {
- GList *part;
- struct mime_part *p;
- struct controller_session *session = ud;
-
- msg_debug ("freeing session %p", session);
-
- while ((part = g_list_first (session->parts))) {
- session->parts = g_list_remove_link (session->parts, part);
- p = (struct mime_part *)part->data;
- g_byte_array_free (p->content, FALSE);
- g_list_free_1 (part);
- }
- rspamd_remove_dispatcher (session->dispatcher);
-
- close (session->sock);
-
- memory_pool_delete (session->session_pool);
- g_free (session);
- }
-
- static gint
- check_auth (struct controller_command *cmd, struct controller_session *session)
- {
- gchar out_buf[128];
- gint r;
-
- if (cmd->privilleged && !session->authorized) {
- r = rspamd_snprintf (out_buf, sizeof (out_buf), "not authorized" CRLF);
- if (! rspamd_dispatcher_write (session->dispatcher, out_buf, r, FALSE, FALSE)) {
- return 0;
- }
- return 0;
- }
-
- return 1;
- }
-
- static void
- counter_write_callback (gpointer key, gpointer value, void *data)
- {
- struct controller_session *session = data;
- struct counter_data *cd = value;
- gchar *name = key;
- gchar out_buf[128];
- gint r;
-
- r = rspamd_snprintf (out_buf, sizeof (out_buf), "%s: %uD" CRLF, name, (guint32)cd->value);
- if (! rspamd_dispatcher_write (session->dispatcher, out_buf, r, TRUE, FALSE)) {
- msg_warn ("cannot write to socket");
- }
- }
-
- static gboolean
- write_whole_statfile (struct controller_session *session, gchar *symbol, struct classifier_config *ccf)
- {
- stat_file_t *statfile;
- struct statfile *st;
- gchar out_buf[BUFSIZ];
- guint i;
- guint64 rev, ti, len, pos, blocks;
- gchar *out;
- struct rspamd_binlog_element log_elt;
- struct stat_file_block *stat_elt;
-
- statfile = get_statfile_by_symbol (session->worker->srv->statfile_pool, ccf,
- symbol, &st, FALSE);
- if (statfile == NULL) {
- return FALSE;
- }
-
- /* Begin to copy all blocks into array */
- statfile_get_revision (statfile, &rev, (time_t *)&ti);
- if (ti == 0) {
- /* Not tracked file */
- ti = time (NULL);
- statfile_set_revision (statfile, rev, ti);
- }
- msg_info ("send a whole statfile %s with version %uL to slave", symbol, rev);
-
- blocks = statfile_get_total_blocks (statfile);
- len = blocks * sizeof (struct rspamd_binlog_element);
- out = memory_pool_alloc (session->session_pool, len);
-
- for (i = 0, pos = 0; i < blocks; i ++) {
- stat_elt = (struct stat_file_block *)((u_char *)statfile->map + statfile->seek_pos + i * sizeof (struct stat_file_block));
- if (fabs (stat_elt->value) > 0.001) {
- /* Write only those values which value is not 0 */
- log_elt.h1 = stat_elt->hash1;
- log_elt.h2 = stat_elt->hash2;
- log_elt.value = stat_elt->value;
-
- memcpy (out + pos, &log_elt, sizeof (log_elt));
- pos += sizeof (struct rspamd_binlog_element);
- }
- }
-
- i = rspamd_snprintf (out_buf, sizeof (out_buf), "%uL %uL %uL" CRLF, rev, ti, pos);
- if (! rspamd_dispatcher_write (session->dispatcher, out_buf, i, TRUE, FALSE)) {
- return FALSE;
- }
-
- if (!rspamd_dispatcher_write (session->dispatcher, out, pos, TRUE, TRUE)) {
- return FALSE;
- }
-
- return TRUE;
- }
-
- static gboolean
- process_sync_command (struct controller_session *session, gchar **args)
- {
- gchar out_buf[BUFSIZ], *arg, *err_str, *symbol;
- gint r;
- guint64 rev, time;
- struct statfile *st = NULL;
- struct classifier_config *ccf;
- GList *cur;
- struct rspamd_binlog *binlog;
- GByteArray *data = NULL;
-
- arg = *args;
- if (!arg || *arg == '\0') {
- msg_info ("bad arguments to sync command, need symbol");
- return FALSE;
- }
- symbol = arg;
- arg = *(args + 1);
- if (!arg || *arg == '\0') {
- msg_info ("bad arguments to sync command, need revision");
- return FALSE;
- }
- rev = strtoull (arg, &err_str, 10);
- if (err_str && *err_str != 0) {
- msg_info ("bad arguments to sync command: %s", arg);
- return FALSE;
- }
- arg = *(args + 2);
- if (!arg || *arg == '\0') {
- msg_info ("bad arguments to sync command, need time");
- return FALSE;
- }
- time = strtoull (arg, &err_str, 10);
- if (err_str && *err_str != 0) {
- msg_info ("bad arguments to sync command: %s", arg);
- return FALSE;
- }
-
- ccf = g_hash_table_lookup (session->cfg->classifiers_symbols, symbol);
- if (ccf == NULL) {
- msg_info ("bad symbol: %s", symbol);
- return FALSE;
- }
-
- cur = g_list_first (ccf->statfiles);
- while (cur) {
- st = cur->data;
- if (strcmp (symbol, st->symbol) == 0) {
- break;
- }
- st = NULL;
- cur = g_list_next (cur);
- }
- if (st == NULL) {
- msg_info ("bad symbol: %s", symbol);
- return FALSE;
- }
-
- binlog = get_binlog_by_statfile (st);
- if (binlog == NULL) {
- msg_info ("cannot open binlog: %s", symbol);
- return FALSE;
- }
-
- while (binlog_sync (binlog, rev, &time, &data)) {
- rev ++;
- r = rspamd_snprintf (out_buf, sizeof (out_buf), "%uL %uL %z" CRLF, rev, time, data->len);
- if (! rspamd_dispatcher_write (session->dispatcher, out_buf, r, FALSE, FALSE)) {
- if (data != NULL) {
- g_free (data);
- }
- return FALSE;
- }
- if (data->data != NULL) {
- if (!rspamd_dispatcher_write (session->dispatcher, data->data, data->len, TRUE, FALSE)) {
- if (data != NULL) {
- g_free (data);
- }
- return FALSE;
- }
- }
- }
-
- if (time == 0) {
- if (data != NULL) {
- g_free (data);
- }
- return write_whole_statfile (session, symbol, ccf);
- }
-
- if (data != NULL) {
- g_free (data);
- }
-
- return TRUE;
- }
-
- static gboolean
- process_stat_command (struct controller_session *session)
- {
- gchar out_buf[BUFSIZ];
- gint r;
- guint64 used, total, rev;
- time_t ti;
- memory_pool_stat_t mem_st;
- struct classifier_config *ccf;
- stat_file_t *statfile;
- struct statfile *st;
- GList *cur_cl, *cur_st;
-
- memory_pool_stat (&mem_st);
- r = rspamd_snprintf (out_buf, sizeof (out_buf), "Messages scanned: %ud" CRLF, session->worker->srv->stat->messages_scanned);
- if (session->worker->srv->stat->messages_scanned > 0) {
- r += rspamd_snprintf (out_buf + r, sizeof (out_buf) - r, "Messages treated as spam: %ud, %.2f%%" CRLF, session->worker->srv->stat->messages_spam,
- (double)session->worker->srv->stat->messages_spam / (double)session->worker->srv->stat->messages_scanned * 100.);
- r += rspamd_snprintf (out_buf + r, sizeof (out_buf) - r, "Messages treated as ham: %ud, %.2f%%" CRLF, session->worker->srv->stat->messages_ham,
- (double)session->worker->srv->stat->messages_ham / (double)session->worker->srv->stat->messages_scanned * 100.);
- }
- r += rspamd_snprintf (out_buf + r, sizeof (out_buf) - r, "Messages learned: %ud" CRLF, session->worker->srv->stat->messages_learned);
- r += rspamd_snprintf (out_buf + r, sizeof (out_buf) - r, "Connections count: %ud" CRLF, session->worker->srv->stat->connections_count);
- r += rspamd_snprintf (out_buf + r, sizeof (out_buf) - r, "Control connections count: %ud" CRLF, session->worker->srv->stat->control_connections_count);
- r += rspamd_snprintf (out_buf + r, sizeof (out_buf) - r, "Pools allocated: %z" CRLF, mem_st.pools_allocated);
- r += rspamd_snprintf (out_buf + r, sizeof (out_buf) - r, "Pools freed: %z" CRLF, mem_st.pools_freed);
- r += rspamd_snprintf (out_buf + r, sizeof (out_buf) - r, "Bytes allocated: %z" CRLF, mem_st.bytes_allocated);
- r += rspamd_snprintf (out_buf + r, sizeof (out_buf) - r, "Memory chunks allocated: %z" CRLF, mem_st.chunks_allocated);
- r += rspamd_snprintf (out_buf + r, sizeof (out_buf) - r, "Shared chunks allocated: %z" CRLF, mem_st.shared_chunks_allocated);
- r += rspamd_snprintf (out_buf + r, sizeof (out_buf) - r, "Chunks freed: %z" CRLF, mem_st.chunks_freed);
- r += rspamd_snprintf (out_buf + r, sizeof (out_buf) - r, "Oversized chunks: %z" CRLF, mem_st.oversized_chunks);
- r += rspamd_snprintf (out_buf + r, sizeof (out_buf) - r, "Fuzzy hashes stored: %ud" CRLF, session->worker->srv->stat->fuzzy_hashes);
- r += rspamd_snprintf (out_buf + r, sizeof (out_buf) - r, "Fuzzy hashes expired: %ud" CRLF, session->worker->srv->stat->fuzzy_hashes_expired);
- /* Now write statistics for each statfile */
- cur_cl = g_list_first (session->cfg->classifiers);
- while (cur_cl) {
- ccf = cur_cl->data;
- cur_st = g_list_first (ccf->statfiles);
- while (cur_st) {
- st = cur_st->data;
- if ((statfile = statfile_pool_is_open (session->worker->srv->statfile_pool, st->path)) == NULL) {
- statfile = statfile_pool_open (session->worker->srv->statfile_pool, st->path, st->size, FALSE);
- }
- if (statfile) {
- used = statfile_get_used_blocks (statfile);
- total = statfile_get_total_blocks (statfile);
- statfile_get_revision (statfile, &rev, &ti);
- if (total != (guint64)-1 && used != (guint64)-1) {
- r += rspamd_snprintf (out_buf + r, sizeof (out_buf) - r,
- "Statfile: %s (version %uL); length: %Hz; free blocks: %uL; total blocks: %uL; free: %.2f%%" CRLF,
- st->symbol, rev, st->size,
- (total - used), total,
- (double)((double)(total - used) / (double)total) * 100.);
- }
- }
- cur_st = g_list_next (cur_st);
- }
- cur_cl = g_list_next (cur_cl);
- }
-
- return rspamd_dispatcher_write (session->dispatcher, out_buf, r, FALSE, FALSE);
- }
-
- static gboolean
- process_command (struct controller_command *cmd, gchar **cmd_args, struct controller_session *session)
- {
- gchar out_buf[BUFSIZ], *arg, *err_str;
- gint r = 0, days, hours, minutes;
- time_t uptime;
- guint32 size = 0;
- struct classifier_config *cl;
- struct rspamd_controller_ctx *ctx = session->worker->ctx;
-
- switch (cmd->type) {
- case COMMAND_PASSWORD:
- arg = *cmd_args;
- if (!arg || *arg == '\0') {
- msg_debug ("empty password passed");
- r = rspamd_snprintf (out_buf, sizeof (out_buf), "password command requires one argument" CRLF);
- if (! rspamd_dispatcher_write (session->dispatcher, out_buf, r, FALSE, FALSE)) {
- return FALSE;
- }
- return TRUE;
- }
- if (ctx->password == NULL) {
- r = rspamd_snprintf (out_buf, sizeof (out_buf), "password command disabled in config, authorized access unallowed" CRLF);
- if (! rspamd_dispatcher_write (session->dispatcher, out_buf, r, FALSE, FALSE)) {
- return FALSE;
- }
- return TRUE;
- }
- if (strncmp (arg, ctx->password, strlen (arg)) == 0) {
- session->authorized = 1;
- r = rspamd_snprintf (out_buf, sizeof (out_buf), "password accepted" CRLF);
- if (! rspamd_dispatcher_write (session->dispatcher, out_buf, r, FALSE, FALSE)) {
- return FALSE;
- }
- }
- else {
- session->authorized = 0;
- r = rspamd_snprintf (out_buf, sizeof (out_buf), "password NOT accepted" CRLF);
- if (! rspamd_dispatcher_write (session->dispatcher, out_buf, r, FALSE, FALSE)) {
- return FALSE;
- }
- }
- break;
- case COMMAND_QUIT:
- session->state = STATE_QUIT;
- break;
- case COMMAND_RELOAD:
- if (check_auth (cmd, session)) {
- r = rspamd_snprintf (out_buf, sizeof (out_buf), "reload request sent" CRLF);
- if (! rspamd_dispatcher_write (session->dispatcher, out_buf, r, FALSE, FALSE)) {
- return FALSE;
- }
- kill (getppid (), SIGHUP);
- }
- break;
- case COMMAND_STAT:
- if (check_auth (cmd, session)) {
- return process_stat_command (session);
- }
- break;
- case COMMAND_SHUTDOWN:
- if (check_auth (cmd, session)) {
- r = rspamd_snprintf (out_buf, sizeof (out_buf), "shutdown request sent" CRLF);
- if (! rspamd_dispatcher_write (session->dispatcher, out_buf, r, FALSE, FALSE)) {
- return FALSE;
- }
- kill (getppid (), SIGTERM);
- }
- break;
- case COMMAND_UPTIME:
- if (check_auth (cmd, session)) {
- uptime = time (NULL) - start_time;
- /* If uptime more than 2 hours, print as a number of days. */
- if (uptime >= 2 * 3600) {
- days = uptime / 86400;
- hours = uptime / 3600 - days * 24;
- minutes = uptime / 60 - hours * 60 - days * 1440;
- r = rspamd_snprintf (out_buf, sizeof (out_buf), "%d day%s %d hour%s %d minute%s" CRLF, days, days > 1 ? "s" : " ", hours, hours > 1 ? "s" : " ", minutes, minutes > 1 ? "s" : " ");
- }
- /* If uptime is less than 1 minute print only seconds */
- else if (uptime / 60 == 0) {
- r = rspamd_snprintf (out_buf, sizeof (out_buf), "%d second%s" CRLF, (gint)uptime, (gint)uptime > 1 ? "s" : " ");
- }
- /* Else print the minutes and seconds. */
- else {
- hours = uptime / 3600;
- minutes = uptime / 60 - hours * 60;
- uptime -= hours * 3600 + minutes * 60;
- r = rspamd_snprintf (out_buf, sizeof (out_buf), "%d hour%s %d minute%s %d second%s" CRLF, hours, hours > 1 ? "s" : " ", minutes, minutes > 1 ? "s" : " ", (gint)uptime, uptime > 1 ? "s" : " ");
- }
- if (! rspamd_dispatcher_write (session->dispatcher, out_buf, r, FALSE, FALSE)) {
- return FALSE;
- }
- }
- break;
- case COMMAND_LEARN_SPAM:
- if (check_auth (cmd, session)) {
- arg = *cmd_args;
- if (!arg || *arg == '\0') {
- msg_debug ("no statfile specified in learn command");
- r = rspamd_snprintf (out_buf, sizeof (out_buf), "learn command requires at least two arguments: stat filename and its size" CRLF);
- if (! rspamd_dispatcher_write (session->dispatcher, out_buf, r, FALSE, FALSE)) {
- return FALSE;
- }
- return TRUE;
- }
- arg = *(cmd_args + 1);
- if (arg == NULL || *arg == '\0') {
- msg_debug ("no message size specified in learn command");
- r = rspamd_snprintf (out_buf, sizeof (out_buf), "learn command requires at least two arguments: symbol and message size" CRLF);
- if (! rspamd_dispatcher_write (session->dispatcher, out_buf, r, FALSE, FALSE)) {
- return FALSE;
- }
- return TRUE;
- }
- size = strtoul (arg, &err_str, 10);
- if (err_str && *err_str != '\0') {
- msg_debug ("message size is invalid: %s", arg);
- r = rspamd_snprintf (out_buf, sizeof (out_buf), "learn size is invalid" CRLF);
- if (! rspamd_dispatcher_write (session->dispatcher, out_buf, r, FALSE, FALSE)) {
- return FALSE;
- }
- return TRUE;
- }
- cl = find_classifier_conf (session->cfg, *cmd_args);
- if (cl == NULL) {
- r = rspamd_snprintf (out_buf, sizeof (out_buf), "classifier %s is not defined" CRLF, *cmd_args);
- if (! rspamd_dispatcher_write (session->dispatcher, out_buf, r, FALSE, FALSE)) {
- return FALSE;
- }
- return TRUE;
-
- }
- session->learn_classifier = cl;
-
- /* By default learn positive */
- session->in_class = TRUE;
- rspamd_set_dispatcher_policy (session->dispatcher, BUFFER_CHARACTER, size);
- session->state = STATE_LEARN_SPAM_PRE;
- }
- break;
- case COMMAND_LEARN_HAM:
- if (check_auth (cmd, session)) {
- arg = *cmd_args;
- if (!arg || *arg == '\0') {
- msg_debug ("no statfile specified in learn command");
- r = rspamd_snprintf (out_buf, sizeof (out_buf), "learn command requires at least two arguments: stat filename and its size" CRLF);
- if (! rspamd_dispatcher_write (session->dispatcher, out_buf, r, FALSE, FALSE)) {
- return FALSE;
- }
- return TRUE;
- }
- arg = *(cmd_args + 1);
- if (arg == NULL || *arg == '\0') {
- msg_debug ("no message size specified in learn command");
- r = rspamd_snprintf (out_buf, sizeof (out_buf), "learn command requires at least two arguments: symbol and message size" CRLF);
- if (! rspamd_dispatcher_write (session->dispatcher, out_buf, r, FALSE, FALSE)) {
- return FALSE;
- }
- return TRUE;
- }
- size = strtoul (arg, &err_str, 10);
- if (err_str && *err_str != '\0') {
- msg_debug ("message size is invalid: %s", arg);
- r = rspamd_snprintf (out_buf, sizeof (out_buf), "learn size is invalid" CRLF);
- if (! rspamd_dispatcher_write (session->dispatcher, out_buf, r, FALSE, FALSE)) {
- return FALSE;
- }
- return TRUE;
- }
- cl = find_classifier_conf (session->cfg, *cmd_args);
- if (cl == NULL) {
- r = rspamd_snprintf (out_buf, sizeof (out_buf), "classifier %s is not defined" CRLF, *cmd_args);
- if (! rspamd_dispatcher_write (session->dispatcher, out_buf, r, FALSE, FALSE)) {
- return FALSE;
- }
- return TRUE;
-
- }
- session->learn_classifier = cl;
-
- /* By default learn positive */
- session->in_class = FALSE;
- rspamd_set_dispatcher_policy (session->dispatcher, BUFFER_CHARACTER, size);
- session->state = STATE_LEARN_SPAM_PRE;
- }
- break;
- case COMMAND_LEARN:
- if (check_auth (cmd, session)) {
- arg = *cmd_args;
- if (!arg || *arg == '\0') {
- msg_debug ("no statfile specified in learn command");
- r = rspamd_snprintf (out_buf, sizeof (out_buf), "learn command requires at least two arguments: stat filename and its size" CRLF);
- if (! rspamd_dispatcher_write (session->dispatcher, out_buf, r, FALSE, FALSE)) {
- return FALSE;
- }
- return TRUE;
- }
- arg = *(cmd_args + 1);
- if (arg == NULL || *arg == '\0') {
- msg_debug ("no message size specified in learn command");
- r = rspamd_snprintf (out_buf, sizeof (out_buf), "learn command requires at least two arguments: symbol and message size" CRLF);
- if (! rspamd_dispatcher_write (session->dispatcher, out_buf, r, FALSE, FALSE)) {
- return FALSE;
- }
- return TRUE;
- }
- size = strtoul (arg, &err_str, 10);
- if (err_str && *err_str != '\0') {
- msg_debug ("message size is invalid: %s", arg);
- r = rspamd_snprintf (out_buf, sizeof (out_buf), "learn size is invalid" CRLF);
- if (! rspamd_dispatcher_write (session->dispatcher, out_buf, r, FALSE, FALSE)) {
- return FALSE;
- }
- return TRUE;
- }
-
- session->learn_symbol = memory_pool_strdup (session->session_pool, *cmd_args);
- cl = g_hash_table_lookup (session->cfg->classifiers_symbols, *cmd_args);
- if (cl == NULL) {
- r = rspamd_snprintf (out_buf, sizeof (out_buf), "statfile %s is not defined" CRLF, *cmd_args);
- if (! rspamd_dispatcher_write (session->dispatcher, out_buf, r, FALSE, FALSE)) {
- return FALSE;
- }
- return TRUE;
-
- }
- session->learn_classifier = cl;
-
- /* By default learn positive */
- session->in_class = 1;
- session->learn_multiplier = 1.;
- /* Get all arguments */
- while (*cmd_args++) {
- arg = *cmd_args;
- if (arg && *arg == '-') {
- switch (*(arg + 1)) {
- case 'r':
- arg = *(cmd_args + 1);
- if (!arg || *arg == '\0') {
- r = rspamd_snprintf (out_buf, sizeof (out_buf), "recipient is not defined" CRLF);
- if (! rspamd_dispatcher_write (session->dispatcher, out_buf, r, FALSE, FALSE)) {
- return FALSE;
- }
- }
- session->learn_rcpt = memory_pool_strdup (session->session_pool, arg);
- break;
- case 'f':
- arg = *(cmd_args + 1);
- if (!arg || *arg == '\0') {
- r = rspamd_snprintf (out_buf, sizeof (out_buf), "from is not defined" CRLF);
- if (! rspamd_dispatcher_write (session->dispatcher, out_buf, r, FALSE, FALSE)) {
- return FALSE;
- }
- }
- session->learn_from = memory_pool_strdup (session->session_pool, arg);
- break;
- case 'n':
- session->in_class = 0;
- break;
- case 'm':
- arg = *(cmd_args + 1);
- if (!arg || *arg == '\0') {
- r = rspamd_snprintf (out_buf, sizeof (out_buf), "multiplier is not defined" CRLF);
- if (! rspamd_dispatcher_write (session->dispatcher, out_buf, r, FALSE, FALSE)) {
- return FALSE;
- }
- }
- else {
- session->learn_multiplier = strtod (arg, NULL);
- }
- break;
- default:
- r = rspamd_snprintf (out_buf, sizeof (out_buf), "tokenizer is not defined" CRLF);
- if (! rspamd_dispatcher_write (session->dispatcher, out_buf, r, FALSE, FALSE)) {
- return FALSE;
- }
- return TRUE;
- }
- }
- }
- rspamd_set_dispatcher_policy (session->dispatcher, BUFFER_CHARACTER, size);
- session->state = STATE_LEARN;
- }
- break;
-
- case COMMAND_WEIGHTS:
- arg = *cmd_args;
- if (!arg || *arg == '\0') {
- msg_debug ("no statfile specified in weights command");
- r = rspamd_snprintf (out_buf, sizeof (out_buf), "weights command requires two arguments: statfile and message size" CRLF);
- if (! rspamd_dispatcher_write (session->dispatcher, out_buf, r, FALSE, FALSE)) {
- return FALSE;
- }
- return TRUE;
- }
- arg = *(cmd_args + 1);
- if (arg == NULL || *arg == '\0') {
- msg_debug ("no message size specified in weights command");
- r = rspamd_snprintf (out_buf, sizeof (out_buf), "weights command requires two arguments: statfile and message size" CRLF);
- if (! rspamd_dispatcher_write (session->dispatcher, out_buf, r, FALSE, FALSE)) {
- return FALSE;
- }
- return TRUE;
- }
- size = strtoul (arg, &err_str, 10);
- if (err_str && *err_str != '\0') {
- msg_debug ("message size is invalid: %s", arg);
- r = rspamd_snprintf (out_buf, sizeof (out_buf), "message size is invalid" CRLF);
- if (! rspamd_dispatcher_write (session->dispatcher, out_buf, r, FALSE, FALSE)) {
- return FALSE;
- }
- return TRUE;
- }
-
- cl = g_hash_table_lookup (session->cfg->classifiers_symbols, *cmd_args);
- if (cl == NULL) {
- r = rspamd_snprintf (out_buf, sizeof (out_buf), "statfile %s is not defined" CRLF, *cmd_args);
- if (! rspamd_dispatcher_write (session->dispatcher, out_buf, r, FALSE, FALSE)) {
- return FALSE;
- }
- return TRUE;
-
- }
- session->learn_classifier = cl;
-
- rspamd_set_dispatcher_policy (session->dispatcher, BUFFER_CHARACTER, size);
- session->state = STATE_WEIGHTS;
- break;
- case COMMAND_SYNC:
- if (!process_sync_command (session, cmd_args)) {
- r = rspamd_snprintf (out_buf, sizeof (out_buf), "FAIL" CRLF);
- if (! rspamd_dispatcher_write (session->dispatcher, out_buf, r, FALSE, FALSE)) {
- return FALSE;
- }
- return TRUE;
- }
- break;
- case COMMAND_HELP:
- r = rspamd_snprintf (out_buf, sizeof (out_buf),
- "Rspamd CLI commands (* - privileged command):" CRLF
- " help - this help message" CRLF
- "(*) learn <statfile> <size> [-r recipient] [-m multiplier] [-f from] [-n] - learn message to specified statfile" CRLF
- " quit - quit CLI session" CRLF
- " password <password> - authenticate yourself for privileged commands" CRLF
- "(*) reload - reload rspamd" CRLF
- "(*) shutdown - shutdown rspamd" CRLF
- " stat - show different rspamd stat" CRLF
- " sync - run synchronization of statfiles" CRLF
- " counters - show rspamd counters" CRLF
- " uptime - rspamd uptime" CRLF
- " weights <statfile> <size> - weight of message in all statfiles" CRLF);
- if (! rspamd_dispatcher_write (session->dispatcher, out_buf, r, FALSE, FALSE)) {
- return FALSE;
- }
- break;
- case COMMAND_COUNTERS:
- rspamd_hash_foreach (counters, counter_write_callback, session);
- break;
- }
- return TRUE;
- }
-
- static gboolean
- process_custom_command (gchar *line, gchar **cmd_args, struct controller_session *session)
- {
- GList *cur;
- struct custom_controller_command *cmd;
-
- cur = custom_commands;
- while (cur) {
- cmd = cur->data;
- if (g_ascii_strcasecmp (cmd->command, line) == 0) {
- /* Call handler */
- cmd->handler (cmd_args, session);
- return TRUE;
- }
- cur = g_list_next (cur);
- }
-
- return FALSE;
- }
-
- static struct controller_command *
- process_normal_command (const gchar *line)
- {
- guint i;
- struct controller_command *c;
-
- for (i = 0; i < G_N_ELEMENTS (commands); i ++) {
- c = &commands[i];
- if (g_ascii_strcasecmp (line, c->command) == 0) {
- return c;
- }
- }
-
- return NULL;
- }
-
- /*
- * Called if all filters are processed
- */
- static void
- fin_learn_task (void *arg)
- {
- struct worker_task *task = (struct worker_task *) arg;
-
- if (task->state != WRITING_REPLY) {
- task->state = WRITE_REPLY;
- /* Process all statfiles */
- process_statfiles (task);
- /* Call post filters */
- lua_call_post_filters (task);
- }
-
- /* Check if we have all events finished */
- if (task->state != WRITING_REPLY) {
- if (task->fin_callback) {
- task->fin_callback (task->fin_arg);
- }
- else {
- rspamd_dispatcher_restore (task->dispatcher);
- }
- }
- }
-
- /*
- * Called if session was restored inside fin callback
- */
- static void
- restore_learn_task (void *arg)
- {
- struct worker_task *task = (struct worker_task *) arg;
-
- /* Special state */
- task->state = WRITING_REPLY;
-
- rspamd_dispatcher_pause (task->dispatcher);
- }
-
- static gboolean
- controller_read_socket (f_str_t * in, void *arg)
- {
- struct controller_session *session = (struct controller_session *)arg;
- struct classifier_ctx *cls_ctx;
- gint len, i, r;
- gchar *s, **params, *cmd, out_buf[128];
- struct controller_command *command;
- struct worker_task *task;
- struct mime_text_part *part;
- GList *cur = NULL;
- GTree *tokens = NULL;
- GError *err = NULL;
- f_str_t c;
-
- switch (session->state) {
- case STATE_COMMAND:
- s = fstrcstr (in, session->session_pool);
- params = g_strsplit_set (s, " ", -1);
-
- memory_pool_add_destructor (session->session_pool, (pool_destruct_func) g_strfreev, params);
-
- len = g_strv_length (params);
- if (len > 0) {
- cmd = g_strstrip (params[0]);
-
- command = process_normal_command (cmd);
- if (command != NULL) {
- if (! process_command (command, ¶ms[1], session)) {
- return FALSE;
- }
- }
- else {
- if (!process_custom_command (cmd, ¶ms[1], session)) {
- msg_debug ("'%s'", cmd);
- i = rspamd_snprintf (out_buf, sizeof (out_buf), "Unknown command" CRLF);
- if (!rspamd_dispatcher_write (session->dispatcher, out_buf, i, FALSE, FALSE)) {
- return FALSE;
- }
- }
- }
- }
- if (session->state == STATE_COMMAND) {
- session->state = STATE_REPLY;
- }
- if (session->state != STATE_LEARN && session->state != STATE_LEARN_SPAM_PRE
- && session->state != STATE_WEIGHTS && session->state != STATE_OTHER) {
- if (!rspamd_dispatcher_write (session->dispatcher, END, sizeof (END) - 1, FALSE, TRUE)) {
- return FALSE;
- }
- }
-
- break;
- case STATE_LEARN:
- session->learn_buf = in;
- task = construct_task (session->worker);
-
- task->msg = memory_pool_alloc (task->task_pool, sizeof (f_str_t));
- task->msg->begin = in->begin;
- task->msg->len = in->len;
- task->ev_base = session->ev_base;
-
- r = process_message (task);
- if (r == -1) {
- msg_warn ("processing of message failed");
- free_task (task, FALSE);
- session->state = STATE_REPLY;
- r = rspamd_snprintf (out_buf, sizeof (out_buf), "cannot process message" CRLF);
- if (! rspamd_dispatcher_write (session->dispatcher, out_buf, r, FALSE, FALSE)) {
- return FALSE;
- }
- return FALSE;
- }
-
- if (!learn_task (session->learn_symbol, task, &err)) {
- if (err) {
- i = rspamd_snprintf (out_buf, sizeof (out_buf), "learn failed, learn classifier error: %s" CRLF END, err->message);
- g_error_free (err);
- }
- else {
- i = rspamd_snprintf (out_buf, sizeof (out_buf), "learn failed, unknown learn classifier error" CRLF END);
- }
- free_task (task, FALSE);
- if (!rspamd_dispatcher_write (session->dispatcher, out_buf, i, FALSE, FALSE)) {
- return FALSE;
- }
- session->state = STATE_REPLY;
- return TRUE;
- }
-
- free_task (task, FALSE);
- i = rspamd_snprintf (out_buf, sizeof (out_buf), "learn ok" CRLF END);
- session->state = STATE_REPLY;
- if (!rspamd_dispatcher_write (session->dispatcher, out_buf, i, FALSE, FALSE)) {
- return FALSE;
- }
- break;
- case STATE_LEARN_SPAM_PRE:
- session->learn_buf = in;
- task = construct_task (session->worker);
-
- task->msg = memory_pool_alloc (task->task_pool, sizeof (f_str_t));
- task->msg->begin = in->begin;
- task->msg->len = in->len;
-
- task->resolver = session->resolver;
- task->ev_base = session->ev_base;
-
- r = process_message (task);
- if (r == -1) {
- msg_warn ("processing of message failed");
- session->state = STATE_REPLY;
- r = rspamd_snprintf (out_buf, sizeof (out_buf), "cannot process message" CRLF);
- if (! rspamd_dispatcher_write (session->dispatcher, out_buf, r, FALSE, FALSE)) {
- return FALSE;
- }
- return FALSE;
- }
- /* Set up async session */
- task->s = new_async_session (task->task_pool, fin_learn_task, restore_learn_task, free_task_hard, task);
- r = process_filters (task);
- if (r == -1) {
- session->state = STATE_REPLY;
- r = rspamd_snprintf (out_buf, sizeof (out_buf), "cannot process message" CRLF);
- destroy_session (task->s);
- if (! rspamd_dispatcher_write (session->dispatcher, out_buf, r, FALSE, FALSE)) {
- return FALSE;
- }
- }
- else {
- session->state = STATE_LEARN_SPAM;
- task->dispatcher = session->dispatcher;
- session->learn_task = task;
- rspamd_dispatcher_pause (session->dispatcher);
- }
- break;
- case STATE_WEIGHTS:
- session->learn_buf = in;
- task = construct_task (session->worker);
-
- task->msg = memory_pool_alloc (task->task_pool, sizeof (f_str_t));
- task->msg->begin = in->begin;
- task->msg->len = in->len;
- task->ev_base = session->ev_base;
-
- r = process_message (task);
- if (r == -1) {
- msg_warn ("processing of message failed");
- free_task (task, FALSE);
- session->state = STATE_REPLY;
- r = rspamd_snprintf (out_buf, sizeof (out_buf), "cannot process message" CRLF END);
- if (! rspamd_dispatcher_write (session->dispatcher, out_buf, r, FALSE, FALSE)) {
- return FALSE;
- }
- return FALSE;
- }
-
- cur = g_list_first (task->text_parts);
- while (cur) {
- part = cur->data;
- if (part->is_empty) {
- cur = g_list_next (cur);
- continue;
- }
-
- c.begin = part->content->data;
- c.len = part->content->len;
- if (!session->learn_classifier->tokenizer->tokenize_func (session->learn_classifier->tokenizer,
- session->session_pool, &c, &tokens, FALSE, part->is_utf, part->urls_offset)) {
- i = rspamd_snprintf (out_buf, sizeof (out_buf), "weights failed, tokenizer error" CRLF END);
- free_task (task, FALSE);
- if (!rspamd_dispatcher_write (session->dispatcher, out_buf, i, FALSE, FALSE)) {
- return FALSE;
- }
- session->state = STATE_REPLY;
- return TRUE;
- }
- cur = g_list_next (cur);
- }
-
- /* Handle messages without text */
- if (tokens == NULL) {
- i = rspamd_snprintf (out_buf, sizeof (out_buf), "weights failed, no tokens can be extracted (no text data)" CRLF END);
- free_task (task, FALSE);
- if (!rspamd_dispatcher_write (session->dispatcher, out_buf, i, FALSE, FALSE)) {
- return FALSE;
- }
- session->state = STATE_REPLY;
- return TRUE;
- }
-
-
- /* Init classifier */
- cls_ctx = session->learn_classifier->classifier->init_func (session->session_pool, session->learn_classifier);
-
- cur = session->learn_classifier->classifier->weights_func (cls_ctx, session->worker->srv->statfile_pool,
- tokens, task);
- i = 0;
- struct classify_weight *w;
-
- while (cur) {
- w = cur->data;
- i += rspamd_snprintf (out_buf + i, sizeof (out_buf) - i, "%s: %G" CRLF, w->name, w->weight);
- cur = g_list_next (cur);
- }
- i += rspamd_snprintf (out_buf + i, sizeof (out_buf) - i, END);
- if (i != 0) {
- if (!rspamd_dispatcher_write (session->dispatcher, out_buf, i, FALSE, FALSE)) {
- return FALSE;
- }
- }
- else {
- if (!rspamd_dispatcher_write (session->dispatcher, "weights failed: classifier error" CRLF END, 0, FALSE, TRUE)) {
- return FALSE;
- }
- }
-
- free_task (task, FALSE);
-
- session->state = STATE_REPLY;
- break;
- case STATE_OTHER:
- if (session->other_handler) {
- session->other_handler (session, in);
- }
- rspamd_dispatcher_pause (session->dispatcher);
- break;
- case STATE_WAIT:
- rspamd_dispatcher_pause (session->dispatcher);
- break;
- default:
- msg_debug ("unknown state while reading %d", session->state);
- break;
- }
-
- if (session->state == STATE_REPLY || session->state == STATE_QUIT) {
- rspamd_dispatcher_restore (session->dispatcher);
- }
-
- return TRUE;
- }
-
- static gboolean
- controller_write_socket (void *arg)
- {
- struct controller_session *session = (struct controller_session *)arg;
- gint i;
- gchar out_buf[1024];
- GError *err = NULL;
-
- if (session->state == STATE_QUIT) {
- /* Free buffers */
- destroy_session (session->s);
- return FALSE;
- }
- else if (session->state == STATE_LEARN_SPAM) {
- /* Perform actual learn here */
- if (! learn_task_spam (session->learn_classifier, session->learn_task, session->in_class, &err)) {
- if (err) {
- i = rspamd_snprintf (out_buf, sizeof (out_buf), "learn failed, learn classifier error: %s" CRLF END, err->message);
- g_error_free (err);
- }
- else {
- i = rspamd_snprintf (out_buf, sizeof (out_buf), "learn failed, unknown learn classifier error" CRLF END);
- }
- }
- else {
- i = rspamd_snprintf (out_buf, sizeof (out_buf), "learn ok" CRLF END);
- }
- session->learn_task->dispatcher = NULL;
- destroy_session (session->learn_task->s);
- session->state = STATE_REPLY;
- if (!rspamd_dispatcher_write (session->dispatcher, out_buf, i, FALSE, FALSE)) {
- return FALSE;
- }
- return TRUE;
- }
- else if (session->state == STATE_REPLY) {
- session->state = STATE_COMMAND;
- rspamd_set_dispatcher_policy (session->dispatcher, BUFFER_LINE, BUFSIZ);
- }
- rspamd_dispatcher_restore (session->dispatcher);
- return TRUE;
- }
-
- static void
- controller_err_socket (GError * err, void *arg)
- {
- struct controller_session *session = (struct controller_session *)arg;
-
- if (err->code != EOF) {
- msg_info ("abnormally closing control connection, error: %s", err->message);
- }
- g_error_free (err);
- /* Free buffers */
- destroy_session (session->s);
- }
-
- static void
- accept_socket (gint fd, short what, void *arg)
- {
- struct rspamd_worker *worker = (struct rspamd_worker *)arg;
- union sa_union su;
- struct controller_session *new_session;
- struct timeval *io_tv;
- socklen_t addrlen = sizeof (su.ss);
- gint nfd;
- struct rspamd_controller_ctx *ctx;
-
- ctx = worker->ctx;
-
- if ((nfd = accept_from_socket (fd, (struct sockaddr *)&su.ss, &addrlen)) == -1) {
- return;
- }
-
- new_session = g_malloc (sizeof (struct controller_session));
- if (new_session == NULL) {
- msg_err ("cannot allocate memory for task, %s", strerror (errno));
- return;
- }
- bzero (new_session, sizeof (struct controller_session));
- new_session->worker = worker;
- new_session->sock = nfd;
- new_session->cfg = worker->srv->cfg;
- new_session->state = STATE_COMMAND;
- new_session->session_pool = memory_pool_new (memory_pool_get_size () - 1);
- new_session->resolver = ctx->resolver;
- new_session->ev_base = ctx->ev_base;
- worker->srv->stat->control_connections_count++;
-
- /* Set up dispatcher */
- io_tv = memory_pool_alloc (new_session->session_pool, sizeof (struct timeval));
- io_tv->tv_sec = ctx->timeout / 1000;
- io_tv->tv_usec = ctx->timeout - io_tv->tv_sec * 1000;
-
- new_session->s = new_async_session (new_session->session_pool, NULL, NULL, free_session, new_session);
-
- new_session->dispatcher = rspamd_create_dispatcher (ctx->ev_base, nfd, BUFFER_LINE, controller_read_socket,
- controller_write_socket, controller_err_socket, io_tv, (void *)new_session);
-
- if (su.ss.ss_family == AF_UNIX) {
- msg_info ("accepted connection from unix socket");
- new_session->dispatcher->peer_addr = INADDR_LOOPBACK;
- }
- else if (su.ss.ss_family == AF_INET) {
- msg_info ("accepted connection from %s port %d",
- inet_ntoa (su.s4.sin_addr), ntohs (su.s4.sin_port));
- memcpy (&new_session->dispatcher->peer_addr, &su.s4.sin_addr,
- sizeof (guint32));
- }
- if (! rspamd_dispatcher_write (new_session->dispatcher, greetingbuf, strlen (greetingbuf), FALSE, FALSE)) {
- msg_warn ("cannot write greeting");
- }
- }
-
- gpointer
- init_controller ()
- {
- struct rspamd_controller_ctx *ctx;
- GQuark type;
-
- type = g_quark_try_string ("controller");
- ctx = g_malloc0 (sizeof (struct rspamd_controller_ctx));
-
- ctx->timeout = CONTROLLER_IO_TIMEOUT * 1000;
-
- register_worker_opt (type, "password", xml_handle_string, ctx, G_STRUCT_OFFSET (struct rspamd_controller_ctx, password));
- register_worker_opt (type, "timeout", xml_handle_seconds, ctx, G_STRUCT_OFFSET (struct rspamd_controller_ctx, timeout));
-
- return ctx;
- }
-
- void
- start_controller (struct rspamd_worker *worker)
- {
- struct sigaction signals;
- gchar *hostbuf;
- gsize hostmax;
- struct rspamd_controller_ctx *ctx;
-
- worker->srv->pid = getpid ();
- ctx = worker->ctx;
-
- ctx->ev_base = event_init ();
- g_mime_init (0);
-
- init_signals (&signals, sig_handler);
- sigprocmask (SIG_UNBLOCK, &signals.sa_mask, NULL);
-
- /* SIGUSR2 handler */
- signal_set (&worker->sig_ev_usr2, SIGUSR2, sigusr2_handler, (void *) worker);
- event_base_set (ctx->ev_base, &worker->sig_ev_usr2);
- signal_add (&worker->sig_ev_usr2, NULL);
-
- /* SIGUSR1 handler */
- signal_set (&worker->sig_ev_usr1, SIGUSR1, sigusr1_handler, (void *) worker);
- event_base_set (ctx->ev_base, &worker->sig_ev_usr1);
- signal_add (&worker->sig_ev_usr1, NULL);
-
-
- start_time = time (NULL);
-
- /* Start statfile synchronization */
- if (!start_statfile_sync (worker->srv->statfile_pool, worker->srv->cfg, ctx->ev_base)) {
- msg_info ("cannot start statfile synchronization, statfiles would not be synchronized");
- }
-
- /* Fill hostname buf */
- hostmax = sysconf (_SC_HOST_NAME_MAX) + 1;
- hostbuf = alloca (hostmax);
- gethostname (hostbuf, hostmax);
- hostbuf[hostmax - 1] = '\0';
- rspamd_snprintf (greetingbuf, sizeof (greetingbuf), "Rspamd version %s is running on %s" CRLF, RVERSION, hostbuf);
- /* Accept event */
- event_set (&worker->bind_ev, worker->cf->listen_sock, EV_READ | EV_PERSIST, accept_socket, (void *)worker);
- event_base_set (ctx->ev_base, &worker->bind_ev);
- event_add (&worker->bind_ev, NULL);
-
- start_map_watch (ctx->ev_base);
- ctx->resolver = dns_resolver_init (ctx->ev_base, worker->srv->cfg);
-
- gperf_profiler_init (worker->srv->cfg, "controller");
-
- event_base_loop (ctx->ev_base, 0);
-
- close_log (worker->srv->logger);
-
- exit (EXIT_SUCCESS);
- }
-
- void
- register_custom_controller_command (const gchar *name, controller_func_t handler, gboolean privilleged, gboolean require_message)
- {
- struct custom_controller_command *cmd;
-
- cmd = g_malloc (sizeof (struct custom_controller_command));
- cmd->command = name;
- cmd->handler = handler;
- cmd->privilleged = privilleged;
- cmd->require_message = require_message;
-
- custom_commands = g_list_prepend (custom_commands, cmd);
- }
-
- /*
- * vi:ts=4
- */
|