From 44b9ea9f740e5ba5a4af45874e9a96becf7f8325 Mon Sep 17 00:00:00 2001 From: Vsevolod Stakhov Date: Sun, 19 Jan 2014 16:11:34 +0000 Subject: [PATCH] Remove legacy client and rework build system. --HG-- rename : lib/CMakeLists.txt => src/CMakeLists.txt --- CMakeLists.txt | 3 +- lib/CMakeLists.txt | 193 ---- lib/client/librspamdclient.c | 1561 ---------------------------- lib/client/librspamdclient.h | 158 --- lib/kvstorage/libkvstorageclient.c | 1179 --------------------- lib/kvstorage/libkvstorageclient.h | 158 --- src/CMakeLists.txt | 146 +++ src/client/CMakeLists.txt | 23 + src/client/rspamdclient.c | 23 + src/client/rspamdclient.h | 32 + 10 files changed, 225 insertions(+), 3251 deletions(-) delete mode 100644 lib/CMakeLists.txt delete mode 100644 lib/client/librspamdclient.c delete mode 100644 lib/client/librspamdclient.h delete mode 100644 lib/kvstorage/libkvstorageclient.c delete mode 100644 lib/kvstorage/libkvstorageclient.h create mode 100644 src/CMakeLists.txt create mode 100644 src/client/rspamdclient.c create mode 100644 src/client/rspamdclient.h diff --git a/CMakeLists.txt b/CMakeLists.txt index f5a69f040..7b9413f3e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -920,8 +920,7 @@ ADD_SUBDIRECTORY(src/json) ADD_SUBDIRECTORY(src/cdb) ADD_SUBDIRECTORY(src/ucl) ADD_SUBDIRECTORY(contrib/http-parser) -ADD_SUBDIRECTORY(lib) - +ADD_SUBDIRECTORY(src) ADD_SUBDIRECTORY(src/client) ADD_SUBDIRECTORY(utils) diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt deleted file mode 100644 index 0f3cba7b4..000000000 --- a/lib/CMakeLists.txt +++ /dev/null @@ -1,193 +0,0 @@ -# Librspamdclient -SET(LIBRSPAMDCLIENTSRC client/librspamdclient.c) - -# Librspamd-util -SET(LIBRSPAMDUTILSRC ../src/aio_event.c - ../src/bloom.c - ../src/diff.c - ../src/fstring.c - ../src/fuzzy.c - ../src/hash.c - ../src/http.c - ../src/logger.c - ../src/map.c - ../src/memcached.c - ../src/mem_pool.c - ../src/printf.c - ../src/radix.c - ../src/rrd.c - ../src/trie.c - ../src/upstream.c - ../src/util.c) - -# kvstorageclient - -SET(LIBRKVSTORAGESRC kvstorage/libkvstorageclient.c) - -# Librspamdserver -SET(LIBRSPAMDSERVERSRC - ../src/binlog.c - ../src/buffer.c - ../src/cfg_utils.c - ../src/cfg_rcl.c - ../src/cfg_xml.c - ../src/dkim.c - ../src/dns.c - ../src/dynamic_cfg.c - ../src/events.c - ../src/html.c - ../src/proxy.c - ../src/roll_history.c - ../src/settings.c - ../src/spf.c - ../src/statfile.c - ../src/statfile_sync.c - ../src/symbols_cache.c - ../src/url.c - ../src/view.c) - -# Librspamd mime -SET(LIBRSPAMDMIMESRC - ../src/expressions.c - ../src/filter.c - ../src/images.c - ../src/message.c - ../src/protocol.c - ../src/smtp_utils.c - ../src/smtp_proto.c - ../src/worker_util.c) - -SET(TOKENIZERSSRC ../src/tokenizers/tokenizers.c - ../src/tokenizers/osb.c) - -SET(CLASSIFIERSSRC ../src/classifiers/classifiers.c - ../src/classifiers/bayes.c - ../src/classifiers/winnow.c) -# Add targets - -# Rspamdutil -ADD_LIBRARY(rspamd-util ${LINK_TYPE} ${LIBRSPAMDUTILSRC}) -IF(CMAKE_COMPILER_IS_GNUCC) -SET_TARGET_PROPERTIES(rspamd-util PROPERTIES COMPILE_FLAGS "-fno-strict-aliasing") -ENDIF(CMAKE_COMPILER_IS_GNUCC) - -TARGET_LINK_LIBRARIES(rspamd-util ${RSPAMD_REQUIRED_LIBRARIES}) -TARGET_LINK_LIBRARIES(rspamd-util pcre) -TARGET_LINK_LIBRARIES(rspamd-util rspamd-ucl) -TARGET_LINK_LIBRARIES(rspamd-util rspamd-http-parser) -TARGET_LINK_LIBRARIES(rspamd-util event) - -IF(NOT DEBIAN_BUILD) -SET_TARGET_PROPERTIES(rspamd-util PROPERTIES VERSION ${RSPAMD_VERSION}) -ENDIF(NOT DEBIAN_BUILD) - -IF(GLIB_COMPAT) - INCLUDE_DIRECTORIES("${CMAKE_CURRENT_SOURCE_DIR}/contrib/lgpl") - TARGET_LINK_LIBRARIES(rspamd-util glibadditions) -ENDIF(GLIB_COMPAT) - -IF(NO_SHARED MATCHES "OFF") - INSTALL(TARGETS rspamd-util - LIBRARY DESTINATION ${LIBDIR} - PUBLIC_HEADER DESTINATION include) -ENDIF(NO_SHARED MATCHES "OFF") - -# Rspamd client -IF(NOT DEBIAN_BUILD) - ADD_LIBRARY(rspamdclient SHARED ${LIBRSPAMDCLIENTSRC}) - ADD_LIBRARY(rspamdclient_static STATIC ${LIBRSPAMDCLIENTSRC}) - SET_TARGET_PROPERTIES(rspamdclient PROPERTIES PUBLIC_HEADER "client/librspamdclient.h") - IF(CMAKE_COMPILER_IS_GNUCC) - SET_TARGET_PROPERTIES(rspamdclient PROPERTIES COMPILE_FLAGS "-fno-strict-aliasing") - SET_TARGET_PROPERTIES(rspamdclient_static PROPERTIES COMPILE_FLAGS "-fno-strict-aliasing") - ENDIF(CMAKE_COMPILER_IS_GNUCC) - TARGET_LINK_LIBRARIES(rspamdclient rspamd-util) - TARGET_LINK_LIBRARIES(rspamdclient ${RSPAMD_REQUIRED_LIBRARIES}) - TARGET_LINK_LIBRARIES(rspamdclient_static rspamd-util) - TARGET_LINK_LIBRARIES(rspamdclient_static ${RSPAMD_REQUIRED_LIBRARIES}) -ELSE(NOT DEBIAN_BUILD) - ADD_LIBRARY(rspamdclient STATIC ${LIBRSPAMDCLIENTSRC}) - IF(CMAKE_COMPILER_IS_GNUCC) - SET_TARGET_PROPERTIES(rspamdclient PROPERTIES COMPILE_FLAGS "-fno-strict-aliasing") - ENDIF(CMAKE_COMPILER_IS_GNUCC) - TARGET_LINK_LIBRARIES(rspamdclient rspamd-util) - TARGET_LINK_LIBRARIES(rspamdclient ${RSPAMD_REQUIRED_LIBRARIES}) -ENDIF(NOT DEBIAN_BUILD) - -IF(NOT DEBIAN_BUILD) - SET_TARGET_PROPERTIES(rspamdclient PROPERTIES VERSION ${RSPAMD_VERSION}) - SET_TARGET_PROPERTIES(rspamdclient_static PROPERTIES VERSION ${RSPAMD_VERSION}) -ENDIF(NOT DEBIAN_BUILD) - -IF(GLIB_COMPAT) - INCLUDE_DIRECTORIES("${CMAKE_CURRENT_SOURCE_DIR}/contrib/lgpl") - TARGET_LINK_LIBRARIES(rspamdclient glibadditions) -ENDIF(GLIB_COMPAT) - -IF(NOT DEBIAN_BUILD) - INSTALL(TARGETS rspamdclient rspamdclient_static LIBRARY PUBLIC_HEADER - LIBRARY DESTINATION ${LIBDIR} - PUBLIC_HEADER DESTINATION ${INCLUDEDIR} - ARCHIVE DESTINATION ${LIBDIR}) -ENDIF(NOT DEBIAN_BUILD) - - -# Librspamd-server - -#IF(WITH_DB) -# LIST(APPEND LIBRSPAMDSERVERSRC ../src/kvstorage_bdb.c) -#ENDIF(WITH_DB) -#IF(WITH_SQLITE) -# LIST(APPEND LIBRSPAMDSERVERSRC ../src/kvstorage_sqlite.c) -#ENDIF(WITH_SQLITE) - -ADD_LIBRARY(rspamd-server ${LINK_TYPE} ${LIBRSPAMDSERVERSRC} ${TOKENIZERSSRC} ${CLASSIFIERSSRC}) -IF(NOT DEBIAN_BUILD) -SET_TARGET_PROPERTIES(rspamd-server PROPERTIES VERSION ${RSPAMD_VERSION}) -ENDIF(NOT DEBIAN_BUILD) -SET_TARGET_PROPERTIES(rspamd-server PROPERTIES LINKER_LANGUAGE C COMPILE_FLAGS "-DRSPAMD_LIB") -TARGET_LINK_LIBRARIES(rspamd-server rspamd-lua) -TARGET_LINK_LIBRARIES(rspamd-server rspamd-json) -TARGET_LINK_LIBRARIES(rspamd-server rspamd-cdb) -TARGET_LINK_LIBRARIES(rspamd-server rspamd-util) -IF(LIBJUDY_LIBRARY) - TARGET_LINK_LIBRARIES(rspamd-server Judy) -ENDIF(LIBJUDY_LIBRARY) -IF(CMAKE_COMPILER_IS_GNUCC) -SET_TARGET_PROPERTIES(rspamd-server PROPERTIES COMPILE_FLAGS "-DRSPAMD_LIB -fno-strict-aliasing") -ENDIF(CMAKE_COMPILER_IS_GNUCC) - -IF(WITH_DB) - TARGET_LINK_LIBRARIES(rspamd-server db) -ENDIF(WITH_DB) - -IF(OPENSSL_FOUND) - TARGET_LINK_LIBRARIES(rspamd-server ${OPENSSL_LIBRARIES}) -ENDIF(OPENSSL_FOUND) - -IF(NO_SHARED MATCHES "OFF") - INSTALL(TARGETS rspamd-server - LIBRARY DESTINATION ${LIBDIR} - PUBLIC_HEADER DESTINATION ${INCLUDEDIR}) -ENDIF(NO_SHARED MATCHES "OFF") - -# Librspamdmime -ADD_LIBRARY(rspamd-mime ${LINK_TYPE} ${LIBRSPAMDMIMESRC}) -IF(NOT DEBIAN_BUILD) -SET_TARGET_PROPERTIES(rspamd-mime PROPERTIES VERSION ${RSPAMD_VERSION}) -ENDIF(NOT DEBIAN_BUILD) -SET_TARGET_PROPERTIES(rspamd-mime PROPERTIES LINKER_LANGUAGE C) -SET_TARGET_PROPERTIES(rspamd-mime PROPERTIES COMPILE_FLAGS "-DRSPAMD_LIB") -TARGET_LINK_LIBRARIES(rspamd-mime rspamd-server) -TARGET_LINK_LIBRARIES(rspamd-mime rspamd-util) -IF(CMAKE_COMPILER_IS_GNUCC) -SET_TARGET_PROPERTIES(rspamd-mime PROPERTIES COMPILE_FLAGS "-DRSPAMD_LIB -fno-strict-aliasing") -ENDIF(CMAKE_COMPILER_IS_GNUCC) - -IF(NO_SHARED MATCHES "OFF") - INSTALL(TARGETS rspamd-mime - LIBRARY DESTINATION ${LIBDIR} - PUBLIC_HEADER DESTINATION ${INCLUDEDIR}) -ENDIF(NO_SHARED MATCHES "OFF") - -INCLUDE_DIRECTORIES("${CMAKE_CURRENT_SOURCE_DIR}/src") \ No newline at end of file diff --git a/lib/client/librspamdclient.c b/lib/client/librspamdclient.c deleted file mode 100644 index 52620e1c3..000000000 --- a/lib/client/librspamdclient.c +++ /dev/null @@ -1,1561 +0,0 @@ -/* - * Copyright (c) 2011, Vsevolod Stakhov - * 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 ''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 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 "librspamdclient.h" -#include "config.h" -#include "upstream.h" -#include "util.h" -#include "cfg_file.h" -#include "logger.h" - -#define MAX_RSPAMD_SERVERS 255 -#define DEFAULT_CONNECT_TIMEOUT 500 -#define DEFAULT_READ_TIMEOUT 5000 -/* Default connect timeout for sync sockets */ -#define CONNECT_TIMEOUT 3 -#define G_RSPAMD_ERROR rspamd_error_quark () - -#ifndef CRLF -# define CRLF "\r\n" -#endif - -struct rspamd_server { - struct upstream up; - guint16 client_port; - guint16 controller_port; - gchar *name; - gchar *controller_name; - gchar *host; -}; - -struct rspamd_client { - struct rspamd_server servers[MAX_RSPAMD_SERVERS]; - guint servers_num; - guint connect_timeout; - guint read_timeout; - struct in_addr *bind_addr; -}; - -struct rspamd_connection { - struct rspamd_server *server; - struct rspamd_client *client; - time_t connection_time; - gint socket; - union { - struct { - struct rspamd_result *result; - struct rspamd_metric *cur_metric; - } normal; - struct { - struct rspamd_controller_result *result; - enum { - CONTROLLER_READ_REPLY, - CONTROLLER_READ_HEADER, - CONTROLLER_READ_DATA - } state; - } controller; - } res; - gboolean is_controller; - GString *in_buf; - gint version; -}; - -/** Private functions **/ -static inline GQuark -rspamd_error_quark (void) -{ - return g_quark_from_static_string ("g-rspamd-error-quark"); -} - -static void -metric_free_func (gpointer arg) -{ - struct rspamd_metric *m = arg; - - g_hash_table_destroy (m->symbols); - g_free (m); -} - -static void -symbol_free_func (gpointer arg) -{ - struct rspamd_symbol *s = arg; - GList *cur = s->options; - - while (cur) { - g_free (cur->data); - cur = g_list_next (cur); - } - g_list_free (s->options); - g_free (s); -} - -static struct rspamd_connection * -rspamd_connect_specific_server (struct rspamd_client *client, gboolean is_control, GError **err, struct rspamd_server *serv) -{ - struct rspamd_connection *new; - - /* Allocate connection */ - new = g_malloc0 (sizeof (struct rspamd_connection)); - new->server = serv; - new->connection_time = time (NULL); - new->client = client; - /* Create socket */ - new->socket = make_universal_socket (serv->host, is_control ? serv->controller_port : serv->client_port, - SOCK_STREAM, TRUE, FALSE, TRUE); - if (new->socket == -1) { - goto err; - } - /* Poll waiting for writing */ - if (poll_sync_socket (new->socket, client->connect_timeout , POLLOUT) <= 0) { - errno = ETIMEDOUT; - goto err; - } - - new->in_buf = g_string_sized_new (BUFSIZ); - return new; - - err: - if (*err == NULL) { - *err = g_error_new (G_RSPAMD_ERROR, errno, "Could not connect to server %s: %s", - serv->name, strerror (errno)); - } - upstream_fail (&serv->up, time (NULL)); - g_free (new); - return NULL; -} - -static struct rspamd_connection * -rspamd_connect_random_server (struct rspamd_client *client, gboolean is_control, GError **err) -{ - struct rspamd_server *selected = NULL; - - if (client->servers_num == 0) { - errno = EINVAL; - if (*err == NULL) { - *err = g_error_new (G_RSPAMD_ERROR, 1, "No servers can be reached"); - } - return NULL; - } - /* Select random server */ - selected = (struct rspamd_server *)get_random_upstream (client->servers, - client->servers_num, sizeof (struct rspamd_server), - time (NULL), DEFAULT_UPSTREAM_ERROR_TIME, DEFAULT_UPSTREAM_DEAD_TIME, DEFAULT_UPSTREAM_MAXERRORS); - if (selected == NULL) { - errno = EINVAL; - if (*err == NULL) { - *err = g_error_new (G_RSPAMD_ERROR, 1, "No servers can be reached"); - } - return NULL; - } - - return rspamd_connect_specific_server (client, is_control, err, selected); -} - -static struct rspamd_metric * -rspamd_create_metric (const gchar *begin, guint len) -{ - struct rspamd_metric *new; - - new = g_malloc0 (sizeof (struct rspamd_metric)); - new->symbols = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, symbol_free_func); - new->name = g_malloc (len + 1); - memcpy (new->name, begin, len); - new->name[len] = '\0'; - - return new; -} - -static struct rspamd_result * -rspamd_create_result (struct rspamd_connection *c) -{ - struct rspamd_result *new; - - new = g_malloc (sizeof (struct rspamd_result)); - new->conn = c; - new->headers = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); - new->metrics = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, metric_free_func); - new->is_ok = FALSE; - - return new; -} - -static struct rspamd_controller_result * -rspamd_create_controller_result (struct rspamd_connection *c) -{ - struct rspamd_controller_result *new; - - new = g_malloc (sizeof (struct rspamd_controller_result)); - new->conn = c; - new->headers = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); - new->data = NULL; - new->result = g_string_new (NULL); - new->code = 0; - - return new; -} - -/* - * Parse line like RSPAMD/{version} {code} {message} - */ -static gboolean -parse_rspamd_first_line (struct rspamd_connection *conn, guint len, GError **err) -{ - gchar *b = conn->in_buf->str + sizeof("RSPAMD/") - 1, *p, *c; - guint remain = len - sizeof("RSPAMD/") + 1, state = 0, next_state = 0; - gdouble dver; - - p = b; - c = p; - while (p - b <= (gint)remain) { - switch (state) { - case 0: - /* Read version */ - if (g_ascii_isspace (*p)) { - state = 99; - next_state = 1; - dver = strtod (c, NULL); - conn->version = floor (dver * 10 + 0.5); - } - else if (!g_ascii_isdigit (*p) && *p != '.') { - goto err; - } - p ++; - break; - case 1: - /* Read code */ - if (g_ascii_isspace (*p)) { - state = 99; - next_state = 2; - if (*c == '0') { - conn->res.normal.result->is_ok = TRUE; - } - } - else if (!g_ascii_isdigit (*p)) { - goto err; - } - p ++; - break; - case 2: - /* Read message */ - if (g_ascii_isspace (*p) || p - b == (gint)remain) { - state = 99; - next_state = 3; - } - p ++; - break; - case 3: - goto err; - case 99: - /* Skip spaces */ - if (!g_ascii_isspace (*p)) { - state = next_state; - c = p; - } - else { - p ++; - } - break; - } - } - - if (state != 99) { - goto err; - } - - return TRUE; -err: - if (*err == NULL) { - *err = g_error_new (G_RSPAMD_ERROR, errno, "Invalid protocol line: %*s at pos: %d", - remain, b, (int)(p - b)); - } - upstream_fail (&conn->server->up, conn->connection_time); - return FALSE; -} - -/* - * Parse line like Metric: ; ; / [ / ] - */ -static gboolean -parse_rspamd_metric_line (struct rspamd_connection *conn, guint len, GError **err) -{ - gchar *b = conn->in_buf->str + sizeof("Metric:") - 1, *p, *c, *err_str; - guint remain = len - sizeof("Metric:") + 1, state = 0, next_state = 0; - struct rspamd_metric *new = NULL; - - p = b; - - while (g_ascii_isspace (*p)) { - p ++; - } - c = p; - - while (p - b <= (gint)remain) { - switch (state) { - case 0: - /* Read metric's name */ - if (*p == ';') { - if (p - c <= 1) { - /* Empty metric name */ - goto err; - } - else { - /* Create new metric */ - new = rspamd_create_metric (c, p - c); - if (g_hash_table_lookup (conn->res.normal.result->metrics, new->name) != NULL) { - /* Duplicate metric */ - metric_free_func (new); - goto err; - } - g_hash_table_insert (conn->res.normal.result->metrics, new->name, new); - conn->res.normal.cur_metric = new; - state = 99; - next_state = 1; - } - } - p ++; - break; - case 1: - /* Read boolean result */ - if (*p == ';') { - if (p - c >= (gint)sizeof("Skip")) { - if (memcmp (c, "Skip", p - c - 1) == 0) { - new->is_skipped = TRUE; - } - } - state = 99; - next_state = 2; - } - p ++; - break; - case 2: - /* Read score */ - if (g_ascii_isspace (*p)) { - new->score = strtod (c, &err_str); - if (*err_str != *p) { - /* Invalid score */ - goto err; - } - state = 99; - next_state = 3; - } - p ++; - break; - case 3: - /* Read / */ - if (g_ascii_isspace (*p)) { - state = 99; - next_state = 4; - } - else if (*p != '/') { - goto err; - } - p ++; - break; - case 4: - /* Read required score */ - if (g_ascii_isspace (*p) || p - b == (gint)remain) { - new->required_score = strtod (c, &err_str); - if (*err_str != *p && *err_str != *(p + 1)) { - /* Invalid score */ - goto err; - } - state = 99; - next_state = 5; - } - p ++; - break; - case 5: - /* Read / if it exists */ - if (g_ascii_isspace (*p)) { - state = 99; - next_state = 6; - } - else if (*p != '/') { - goto err; - } - p ++; - break; - case 6: - /* Read reject score */ - if (g_ascii_isspace (*p) || p - b == (gint)remain) { - new->reject_score = strtod (c, &err_str); - if (*err_str != *p && *err_str != *(p + 1)) { - /* Invalid score */ - goto err; - } - state = 99; - } - p ++; - break; - case 99: - /* Skip spaces */ - if (!g_ascii_isspace (*p)) { - state = next_state; - c = p; - } - else { - p ++; - } - break; - } - } - - if (state != 99) { - goto err; - } - return TRUE; - -err: - if (*err == NULL) { - *err = g_error_new (G_RSPAMD_ERROR, errno, "Invalid metric line: %*s at pos: %d, state: %d", - remain, b, (int)(p - b), state); - } - upstream_fail (&conn->server->up, conn->connection_time); - return FALSE; -} - -/* - * Parse line like Symbol: [(score)]; [option1, [option2 ...]] - */ -static gboolean -parse_rspamd_symbol_line (struct rspamd_connection *conn, guint len, GError **err) -{ - gchar *b = conn->in_buf->str + sizeof("Symbol:") - 1, *p, *c, *err_str, *sym; - guint remain = len - sizeof("Symbol:") + 1, state = 0, next_state = 0, l; - struct rspamd_symbol *new = NULL; - - p = b; - while (g_ascii_isspace (*p)) { - p ++; - } - c = p; - while (p - b < (gint)remain) { - switch (state) { - case 0: - /* Read symbol's name */ - if (p - b == (gint)remain - 1 || *p == ';' || *p == '(') { - if (p - c <= 1) { - /* Empty symbol name */ - goto err; - } - else { - if (p - b == (gint)remain) { - l = p - c + 1; - } - else { - if (*p == '(') { - next_state = 1; - } - else if (*p == ';' ) { - next_state = 2; - } - l = p - c; - } - /* Create new symbol */ - sym = g_malloc (l + 1); - sym[l] = '\0'; - memcpy (sym, c, l); - - if (g_hash_table_lookup (conn->res.normal.cur_metric->symbols, sym) != NULL) { - /* Duplicate symbol */ - g_free (sym); - goto err; - } - new = g_malloc0 (sizeof (struct rspamd_symbol)); - new->name = sym; - g_hash_table_insert (conn->res.normal.cur_metric->symbols, sym, new); - state = 99; - } - } - p ++; - break; - case 1: - /* Read symbol's weight */ - if (*p == ')') { - new->weight = strtod (c, &err_str); - if (*err_str != *p) { - /* Invalid weight */ - goto err; - } - if (*(p + 1) == ';') { - p ++; - } - state = 99; - if (conn->version >= 13) { - next_state = 2; - } - else { - next_state = 3; - } - } - p ++; - break; - case 2: - /* Read description */ - if (*p == ';' || p - b == (gint)remain - 1) { - if (*p == ';') { - l = p - c; - } - else { - l = p - c + 1; - } - - if (l > 0) { - sym = g_malloc (l + 1); - sym[l] = '\0'; - memcpy (sym, c, l); - new->description = sym; - } - state = 99; - next_state = 3; - } - p ++; - break; - case 3: - /* Read option */ - if (*p == ',' || p - b == (gint)remain - 1) { - /* Insert option into linked list */ - l = p - c; - if (p - b == (gint)remain - 1) { - l ++; - } - sym = g_malloc (l + 1); - sym[l] = '\0'; - memcpy (sym, c, l); - new->options = g_list_prepend (new->options, sym); - state = 99; - next_state = 2; - } - p ++; - break; - case 99: - /* Skip spaces */ - if (!g_ascii_isspace (*p)) { - state = next_state; - c = p; - } - else { - p ++; - } - break; - } - } - - if (state != 99) { - goto err; - } - return TRUE; - - err: - if (*err == NULL) { - *err = g_error_new (G_RSPAMD_ERROR, errno, "Invalid symbol line: %*s at pos: %d, at state: %d", - remain, b, (int)(p - b), state); - } - upstream_fail (&conn->server->up, conn->connection_time); - return FALSE; -} - -/* - * Parse line like Action: - */ -static gboolean -parse_rspamd_action_line (struct rspamd_connection *conn, guint len, GError **err) -{ - gchar *b = conn->in_buf->str + sizeof("Action:") - 1, *p, *c, *sym; - guint remain = len - sizeof("Action:") + 1, state = 0, next_state = 0; - - p = b; - c = b; - while (p - b <= (gint)remain) { - switch (state) { - case 0: - /* Read action */ - if (g_ascii_isspace (*p)) { - state = 99; - next_state = 1; - } - else { - state = 1; - } - break; - case 1: - if (p - b == (gint)remain) { - if (p - c <= 1) { - /* Empty action name */ - goto err; - } - else { - /* Create new action */ - sym = g_malloc (p - c + 2); - sym[p - c + 1] = '\0'; - memcpy (sym, c, p - c + 1); - conn->res.normal.cur_metric->action = sym; - state = 99; - } - } - p ++; - break; - case 99: - /* Skip spaces */ - if (!g_ascii_isspace (*p)) { - state = next_state; - c = p; - } - else { - p ++; - } - break; - } - } - - if (state != 99) { - goto err; - } - return TRUE; - - err: - if (*err == NULL) { - *err = g_error_new (G_RSPAMD_ERROR, errno, "Invalid action line: %*s at pos: %d", - remain, b, (int)(p - b)); - } - upstream_fail (&conn->server->up, conn->connection_time); - return FALSE; -} - -/* - * Parse line like Header: - */ -static gboolean -parse_rspamd_header_line (struct rspamd_connection *conn, guint len, GError **err) -{ - gchar *b = conn->in_buf->str, *p, *c, *hname = NULL, *hvalue = NULL; - guint remain = len, state = 0, next_state = 0, clen; - - p = b; - c = b; - while (p - b <= (gint)remain) { - switch (state) { - case 0: - /* Read header name */ - if (*p == ':') { - if (p - c <= 1) { - /* Empty header name */ - goto err; - } - else { - /* Create header name */ - hname = g_malloc (p - c + 1); - hname[p - c] = '\0'; - memcpy (hname, c, p - c); - next_state = 1; - state = 99; - } - } - p ++; - break; - case 1: - if (p - b == (gint)remain) { - if (p - c <= 1) { - /* Empty action name */ - goto err; - } - else { - /* Create header value */ - hvalue = g_malloc (p - c + 2); - hvalue[p - c + 1] = '\0'; - memcpy (hvalue, c, p - c + 1); - if (conn->is_controller) { - if (g_ascii_strcasecmp (hname, "Content-Length") == 0) { - /* Preallocate data buffer */ - errno = 0; - clen = strtoul (hvalue, NULL, 10); - if (errno == 0 && clen > 0) { - conn->res.controller.result->data = g_string_sized_new (clen); - } - } - g_hash_table_replace (conn->res.controller.result->headers, hname, hvalue); - } - else { - g_hash_table_replace (conn->res.normal.result->headers, hname, hvalue); - } - state = 99; - } - } - p ++; - break; - case 99: - /* Skip spaces */ - if (!g_ascii_isspace (*p)) { - state = next_state; - c = p; - } - else { - p ++; - } - break; - } - } - - if (state != 99) { - goto err; - } - return TRUE; - -err: - if (*err == NULL) { - *err = g_error_new (G_RSPAMD_ERROR, errno, "Invalid header line: %*s at pos: %d", - remain, b, (int)(p - b)); - } - if (hname) { - g_free (hname); - } - if (hvalue) { - g_free (hvalue); - } - upstream_fail (&conn->server->up, conn->connection_time); - return FALSE; -} - -static gboolean -parse_rspamd_controller_reply (struct rspamd_connection *conn, guint len, GError **err) -{ - gchar *b = conn->in_buf->str, *p, *c; - const gchar http_rep[] = "HTTP/1.0 "; - guint remain = len, state = 0, next_state = 0; - - /* First of all skip "HTTP/1.0 " line */ - if (len < sizeof (http_rep) || memcmp (b, http_rep, sizeof (http_rep) - 1) != 0) { - g_set_error (err, G_RSPAMD_ERROR, -1, "Invalid reply line"); - return FALSE; - } - b += sizeof (http_rep) - 1; - p = b; - c = b; - remain -= sizeof (http_rep) - 1; - - while (p - b <= (gint)remain) { - switch (state) { - case 0: - /* Try to get code */ - if (g_ascii_isdigit (*p)) { - p ++; - } - else if (g_ascii_isspace (*p)) { - conn->res.controller.result->code = atoi (c); - next_state = 1; - state = 99; - } - else { - goto err; - } - break; - case 1: - /* Get reply string */ - if (p - b == (gint)remain) { - if (p - c <= 0) { - /* Empty action name */ - goto err; - } - else { - /* Create header value */ - conn->res.controller.result->result = g_string_sized_new (p - c + 1); - g_string_append_len (conn->res.controller.result->result, c, p - c); - state = 99; - } - } - p ++; - break; - case 99: - /* Skip spaces */ - if (!g_ascii_isspace (*p)) { - state = next_state; - c = p; - } - else { - p ++; - } - break; - } - } - - if (state != 99) { - goto err; - } - - conn->res.controller.state = CONTROLLER_READ_HEADER; - - return TRUE; - -err: - if (*err == NULL) { - *err = g_error_new (G_RSPAMD_ERROR, errno, "Invalid reply line: %*s at pos: %d", - remain, b, (int)(p - b)); - } - return FALSE; -} - -static gboolean -parse_rspamd_reply_line (struct rspamd_connection *c, guint len, GError **err) -{ - gchar *p = c->in_buf->str; - - if (c->is_controller) { - switch (c->res.controller.state) { - case CONTROLLER_READ_REPLY: - return parse_rspamd_controller_reply (c, len, err); - break; - case CONTROLLER_READ_HEADER: - if (len == 0) { - /* End of headers */ - c->res.controller.state = CONTROLLER_READ_DATA; - if (c->res.controller.result->data == NULL) { - /* Cannot detect size as controller didn't send Content-Length header, so guess it */ - c->res.controller.result->data = g_string_new (NULL); - } - return TRUE; - } - else { - return parse_rspamd_header_line (c, len, err); - } - break; - case CONTROLLER_READ_DATA: - g_string_append_len (c->res.controller.result->data, p, len); - g_string_append_len (c->res.controller.result->data, CRLF, 2); - return TRUE; - break; - } - } - else { - /* - * In fact we have 3 states of parsing: - * 1) we have current metric and parse symbols - * 2) we have no current metric and skip everything to headers hash - * 3) we have current metric but got not symbol but header -> put it into headers hash - * Line is parsed using specific state machine - */ - if (len > 0) { - if (c->res.normal.cur_metric == NULL) { - if (len > sizeof ("RSPAMD/") && memcmp (p, "RSPAMD/", sizeof ("RSPAMD/") - 1) == 0) { - return parse_rspamd_first_line (c, len, err); - } - else if (len > sizeof ("Metric:") && memcmp (p, "Metric:", sizeof("Metric:") - 1) == 0) { - return parse_rspamd_metric_line (c, len, err); - } - else { - return parse_rspamd_header_line (c, len, err); - } - } - else { - if (len > sizeof ("Metric:") && memcmp (p, "Metric:", sizeof("Metric:") - 1) == 0) { - return parse_rspamd_metric_line (c, len, err); - } - else if (len > sizeof ("Symbol:") && memcmp (p, "Symbol:", sizeof("Symbol:") - 1) == 0) { - return parse_rspamd_symbol_line (c, len, err); - } - else if (len > sizeof ("Action:") && memcmp (p, "Action:", sizeof("Action:") - 1) == 0) { - return parse_rspamd_action_line (c, len, err); - } - else { - return parse_rspamd_header_line (c, len, err); - } - } - } - else { - /* TODO: here we should parse commands that contains data, like PROCESS */ - return TRUE; - } - } - - /* Not reached */ - return FALSE; -} - -static gboolean -read_rspamd_reply_line (struct rspamd_connection *c, GError **err) -{ - gint len, r; - char p; - - /* Try to obtain string from the input buffer */ - if (c->in_buf->len > 0) { - len = 0; - while (len < (gint)c->in_buf->len) { - p = c->in_buf->str[len]; - if (p == '\n') { - if (parse_rspamd_reply_line (c, len - 1, err)) { - /* Move remaining buffer to the begin of string */ - c->in_buf = g_string_erase (c->in_buf, 0, len + 1); - len = 0; - } - else { - return FALSE; - } - } - len ++; - } - } - /* Poll socket */ - if ((r = poll_sync_socket (c->socket, c->client->read_timeout, POLL_IN)) <= 0) { - if (*err == NULL) { - if (r == 0) { - errno = ETIMEDOUT; - } - *err = g_error_new (G_RSPAMD_ERROR, errno, "Cannot read reply from rspamd server %s: %s", - c->server->name, strerror (errno)); - } - upstream_fail (&c->server->up, c->connection_time); - return FALSE; - } - if (c->in_buf->allocated_len - c->in_buf->len < BUFSIZ / 2) { - /* Grow buffer */ - c->in_buf = g_string_set_size (c->in_buf, c->in_buf->allocated_len * 2); - } - /* Read new data to a string */ - if ((r = read (c->socket, - c->in_buf->str + c->in_buf->len, - c->in_buf->allocated_len - c->in_buf->len)) > 0) { - /* Try to parse remaining data */ - c->in_buf->len += r; - return read_rspamd_reply_line (c, err); - } - - return FALSE; -} - -/* - * More or less portable version of sendfile - */ -static gboolean -rspamd_sendfile (gint sock, gint fd, GError **err) -{ - - /* Make socket blocking for further operations */ - make_socket_blocking (sock); -#ifdef HAVE_SENDFILE -# if defined(FREEBSD) || defined(DARWIN) - off_t off = 0; -# if defined(FREEBSD) - /* FreeBSD version */ - if (sendfile (fd, sock, 0, 0, NULL, &off, 0) != 0) { -# elif defined(DARWIN) - /* Darwin version */ - if (sendfile (fd, sock, 0, &off, NULL, 0) != 0) { -# endif - goto err; - } -# else - ssize_t r; - off_t off = 0; - struct stat st; - - fstat (fd, &st); - /* Linux version */ - r = sendfile (sock, fd, &off, st.st_size); - if (r == -1) { - goto err; - } -# endif -#else - /* Emulating version */ - ssize_t r; - gchar buf[BUFSIZ]; - - while ((r = read (fd, buf, sizeof (buf))) > 0) { - if ((r = write (sock, buf, r)) != r) { - goto err; - } - } -#endif - make_socket_nonblocking (sock); - - return TRUE; - -err: - if (*err == NULL) { - *err = g_error_new (G_RSPAMD_ERROR, errno, "Sendfile error: %s", - strerror (errno)); - } - return FALSE; -} - -struct hash_iter_cb { - gchar *buf; - gsize size; - gsize pos; -}; - -static void -rspamd_hash_iter_cb (gpointer key, gpointer value, gpointer ud) -{ - struct hash_iter_cb *cd = ud; - - cd->pos += snprintf (cd->buf + cd->pos, cd->size - cd->pos, - "%s: %s\r\n", (const gchar *)key, (const gchar *)value); -} - -static gboolean -rspamd_send_normal_command (struct rspamd_connection *c, const gchar *command, - gsize clen, GHashTable *headers, GError **err) -{ - gchar outbuf[16384]; - gint r; - struct hash_iter_cb cbdata; - - /* Write command */ - r = snprintf (outbuf, sizeof (outbuf), "%s RSPAMC/1.3\r\n", command); - r += snprintf (outbuf + r, sizeof (outbuf) - r, "Content-Length: %lu\r\n", (unsigned long)clen); - /* Iterate through headers */ - if (headers != NULL) { - cbdata.size = sizeof (outbuf); - cbdata.pos = r; - cbdata.buf = outbuf; - g_hash_table_foreach (headers, rspamd_hash_iter_cb, &cbdata); - r = cbdata.pos; - } - r += snprintf (outbuf + r, sizeof (outbuf) - r, "\r\n"); - - if ((r = write (c->socket, outbuf, r)) == -1) { - if (*err == NULL) { - *err = g_error_new (G_RSPAMD_ERROR, errno, "Write error: %s", - strerror (errno)); - } - return FALSE; - } - - return TRUE; -} - -static void -rspamd_free_connection (struct rspamd_connection *c) -{ - make_socket_blocking (c->socket); - (void)close (c->socket); - g_string_free (c->in_buf, TRUE); - - g_free (c); -} - - - -static gboolean -rspamd_send_controller_command (struct rspamd_connection *c, const gchar *command, const gchar *password, GHashTable *in_headers, gint fd, GByteArray *data, GError **err) -{ - struct iovec iov[2]; - gchar outbuf[BUFSIZ]; - gint r; - struct stat st; - struct hash_iter_cb cbdata; - - /* Form a request */ - r = rspamd_snprintf (outbuf, sizeof (outbuf), "GET / HTTP/1.0" CRLF "Command: %s" CRLF, command); - /* Content length */ - if (fd != -1) { - if (fstat (fd, &st) == -1) { - g_set_error (err, G_RSPAMD_ERROR, errno, "Stat error: %s", strerror (errno)); - goto err; - } - r += rspamd_snprintf (outbuf + r, sizeof (outbuf) - r, "Content-Length: %z" CRLF, st.st_size); - } - else if (data && data->len > 0) { - r += rspamd_snprintf (outbuf + r, sizeof (outbuf) - r, "Content-Length: %z" CRLF, data->len); - } - /* Password */ - if (password != NULL) { - r += rspamd_snprintf (outbuf + r, sizeof (outbuf) - r, "Password: %s" CRLF, password); - } - /* Other headers */ - if (in_headers != NULL) { - cbdata.size = sizeof (outbuf); - cbdata.pos = r; - cbdata.buf = outbuf; - g_hash_table_foreach (in_headers, rspamd_hash_iter_cb, &cbdata); - r = cbdata.pos; - } - r += rspamd_snprintf (outbuf + r, sizeof (outbuf) - r, CRLF); - - - /* Assume that a socket is in blocking mode */ - if (fd != -1) { -#ifdef LINUX - if (send (c->socket, outbuf, r, MSG_MORE) == -1) { - g_set_error (err, G_RSPAMD_ERROR, errno, "Send error: %s", strerror (errno)); - goto err; - } -#else - if (send (c->socket, outbuf, r, 0) == -1) { - g_set_error (err, G_RSPAMD_ERROR, errno, "Send error: %s", strerror (errno)); - goto err; - } -#endif - if (!rspamd_sendfile (c->socket, fd, err)) { - goto err; - } - } - else if (data && data->len > 0) { - /* Use iovec */ - iov[0].iov_base = outbuf; - iov[0].iov_len = r; - iov[1].iov_base = data->data; - iov[1].iov_len = data->len; - - if (writev (c->socket, iov, G_N_ELEMENTS (iov)) == -1) { - g_set_error (err, G_RSPAMD_ERROR, errno, "Writev error: %s", strerror (errno)); - goto err; - } - } - else { - /* Just write request */ - if (send (c->socket, outbuf, r, 0) == -1) { - g_set_error (err, G_RSPAMD_ERROR, errno, "Send error: %s", strerror (errno)); - goto err; - } - } - - return TRUE; -err: - return FALSE; -} - -/** Public API **/ - -/* - * Init rspamd client library - */ -struct rspamd_client* -rspamd_client_init_binded (const struct in_addr *addr) -{ - struct rspamd_client *client; - - client = g_malloc0 (sizeof (struct rspamd_client)); - client->read_timeout = DEFAULT_READ_TIMEOUT; - client->connect_timeout = DEFAULT_CONNECT_TIMEOUT; - - if (addr != NULL) { - client->bind_addr = g_malloc (sizeof (struct in_addr)); - memcpy (client->bind_addr, addr, sizeof (struct in_addr)); - } - - return client; -} - -struct rspamd_client* -rspamd_client_init (void) -{ - return rspamd_client_init_binded (NULL); -} - -/* - * Add rspamd server - */ -gboolean -rspamd_add_server (struct rspamd_client *client, const gchar *host, guint16 port, - guint16 controller_port, GError **err) -{ - struct rspamd_server *new; - gint nlen, i; - - g_assert (client != NULL); - - /* Avoid duplicates */ - for (i = 0; i < (gint)client->servers_num; i ++) { - new = &client->servers[i]; - if (new->client_port == port && new->controller_port == controller_port && strcmp (host, new->host) == 0) { - /* Duplicate */ - return TRUE; - } - } - - if (client->servers_num >= MAX_RSPAMD_SERVERS) { - if (*err == NULL) { - *err = g_error_new (G_RSPAMD_ERROR, 1, "Maximum number of servers reached: %d", MAX_RSPAMD_SERVERS); - } - return FALSE; - } - new = &client->servers[client->servers_num]; - - new->client_port = port; - new->controller_port = controller_port; - new->host = g_strdup (host); - nlen = strlen (host) + sizeof ("65535") + 1; - new->name = g_malloc (nlen); - new->controller_name = g_malloc (nlen); - if (*host != '/') { - rspamd_snprintf (new->name, nlen, "%s:%d", host, (gint)port); - rspamd_snprintf (new->controller_name, nlen, "%s:%d", host, (gint)controller_port); - } - else { - rspamd_snprintf (new->name, nlen, "unix:%s", host); - rspamd_snprintf (new->controller_name, nlen, "unix:%s", host); - } - - client->servers_num ++; - return TRUE; -} - -/* - * Set timeouts (values in milliseconds) - */ -void -rspamd_set_timeout (struct rspamd_client *client, guint connect_timeout, guint read_timeout) -{ - g_assert (client != NULL); - - if (connect_timeout > 0) { - client->connect_timeout = connect_timeout; - } - if (read_timeout > 0) { - client->read_timeout = read_timeout; - } -} - -/* - * Scan message from memory - */ -struct rspamd_result * -rspamd_scan_memory (struct rspamd_client *client, const guchar *message, gsize length, GHashTable *headers, GError **err) -{ - struct rspamd_connection *c; - struct rspamd_result *res = NULL; - - g_assert (client != NULL); - g_assert (length > 0); - - /* Connect to server */ - c = rspamd_connect_random_server (client, FALSE, err); - - if (c == NULL) { - return NULL; - } - - /* Set socket blocking for writing */ - make_socket_blocking (c->socket); - /* Send command */ - if (!rspamd_send_normal_command (c, "SYMBOLS", length, headers, err)) { - return NULL; - } - - /* Send message */ - if (write (c->socket, message, length) == -1) { - if (*err == NULL) { - *err = g_error_new (G_RSPAMD_ERROR, errno, "Write error: %s", - strerror (errno)); - } - return NULL; - } - - /* Create result structure */ - res = rspamd_create_result (c); - c->res.normal.result = res; - c->is_controller = FALSE; - /* Restore non-blocking mode for reading operations */ - make_socket_nonblocking (c->socket); - - /* Read result cycle */ - while (read_rspamd_reply_line (c, err)); - - upstream_ok (&c->server->up, c->connection_time); - return res; -} - -/* - * Scan message from file - */ -struct rspamd_result * -rspamd_scan_file (struct rspamd_client *client, const guchar *filename, GHashTable *headers, GError **err) -{ - gint fd; - g_assert (client != NULL); - - /* Open file */ - if ((fd = open (filename, O_RDONLY)) == -1) { - if (*err == NULL) { - *err = g_error_new (G_RSPAMD_ERROR, errno, "Open error for file %s: %s", - filename, strerror (errno)); - } - return NULL; - } - - return rspamd_scan_fd (client, fd, headers, err); -} - -/* - * Scan message from fd - */ -struct rspamd_result * -rspamd_scan_fd (struct rspamd_client *client, int fd, GHashTable *headers, GError **err) -{ - struct rspamd_connection *c; - struct rspamd_result *res = NULL; - struct stat st; - - g_assert (client != NULL); - - /* Connect to server */ - c = rspamd_connect_random_server (client, FALSE, err); - - if (c == NULL) { - return NULL; - } - - /* Get length */ - if (fstat (fd, &st) == -1) { - if (*err == NULL) { - *err = g_error_new (G_RSPAMD_ERROR, errno, "Stat error: %s", - strerror (errno)); - } - return NULL; - } - if (st.st_size == 0) { - if (*err == NULL) { - *err = g_error_new (G_RSPAMD_ERROR, -1, "File has zero length"); - } - return NULL; - } - /* Set socket blocking for writing */ - make_socket_blocking (c->socket); - /* Send command */ - if (!rspamd_send_normal_command (c, "SYMBOLS", (gsize)st.st_size, headers, err)) { - return NULL; - } - - /* Send message */ - if (!rspamd_sendfile (c->socket, fd, err)) { - return NULL; - } - - /* Create result structure */ - res = rspamd_create_result (c); - c->is_controller = FALSE; - c->res.normal.result = res; - /* Restore non-blocking mode for reading operations */ - make_socket_nonblocking (c->socket); - - /* Read result cycle */ - while (read_rspamd_reply_line (c, err)); - - upstream_ok (&c->server->up, c->connection_time); - return res; -} - -/* - * Send a common controller command to all servers - */ -static void -rspamd_controller_command_single (struct rspamd_client* client, const gchar *command, const gchar *password, - GHashTable *in_headers, GByteArray *mem, gint fd, GError **err, - struct rspamd_controller_result *res, struct rspamd_server *serv) -{ - struct rspamd_connection *c; - - /* Connect to server */ - c = rspamd_connect_specific_server (client, FALSE, err, serv); - - if (c == NULL) { - return; - } - - res->conn = c; - /* Set socket blocking for writing */ - make_socket_blocking (c->socket); - - /* Send command */ - if (!rspamd_send_controller_command (c, command, password, in_headers, fd, mem, err)) { - res->result = g_string_new (*err != NULL ? (*err)->message : "unknown error"); - res->code = 500; - return; - } - c->is_controller = TRUE; - c->res.controller.result = res; - - /* Restore non-blocking mode for reading operations */ - make_socket_nonblocking (c->socket); - - /* Read result cycle */ - while (read_rspamd_reply_line (c, err)); - - upstream_ok (&c->server->up, c->connection_time); -} - -/* - * Send a common controller command to all servers - */ -static GList* -rspamd_controller_command_common (struct rspamd_client* client, const gchar *command, const gchar *password, - GHashTable *in_headers, GByteArray *mem, gint fd, GError **err) -{ - struct rspamd_server *serv; - struct rspamd_controller_result *res; - GList *res_list = NULL; - guint i; - - g_assert (client != NULL); - - for (i = 0; i < client->servers_num; i ++) { - serv = &client->servers[i]; - res = rspamd_create_controller_result (NULL); - res->server_name = serv->controller_name; - res_list = g_list_prepend (res_list, res); - /* Fill result */ - rspamd_controller_command_single (client, command, password, in_headers, mem, fd, err, res, serv); - } - - return res_list; -} - -/** - * Perform a simple controller command on all rspamd servers - * @param client rspamd client - * @param command command to send - * @param password password (NULL if no password required) - * @param in_headers custom in headers, specific for this command (or NULL) - * @param err error object (should be pointer to NULL object) - * @return list of rspamd_controller_result structures for each server - */ -GList* -rspamd_controller_command_simple (struct rspamd_client* client, const gchar *command, const gchar *password, - GHashTable *in_headers, GError **err) -{ - return rspamd_controller_command_common (client, command, password, in_headers, NULL, -1, err); -} - -/** - * Perform a controller command on all rspamd servers with in memory argument - * @param client rspamd client - * @param command command to send - * @param password password (NULL if no password required) - * @param in_headers custom in headers, specific for this command (or NULL) - * @param message data to pass to the controller - * @param length its length - * @param err error object (should be pointer to NULL object) - * @return list of rspamd_controller_result structures for each server - */ -GList* -rspamd_controller_command_memory (struct rspamd_client* client, const gchar *command, const gchar *password, - GHashTable *in_headers, const guchar *message, gsize length, GError **err) -{ - GByteArray ba; - ba.data = (guint8 *)message; - ba.len = length; - return rspamd_controller_command_common (client, command, password, in_headers, &ba, -1, err); -} - -/** - * Perform a controller command on all rspamd servers with descriptor argument - * @param client rspamd client - * @param command command to send - * @param password password (NULL if no password required) - * @param in_headers custom in headers, specific for this command (or NULL) - * @param fd file descriptor of data - * @param err error object (should be pointer to NULL object) - * @return list of rspamd_controller_result structures for each server - */ -GList* -rspamd_controller_command_fd (struct rspamd_client* client, const gchar *command, const gchar *password, - GHashTable *in_headers, gint fd, GError **err) -{ - return rspamd_controller_command_common (client, command, password, in_headers, NULL, fd, err); -} - -/** - * Perform a controller command on all rspamd servers with descriptor argument - * @param client rspamd client - * @param command command to send - * @param password password (NULL if no password required) - * @param in_headers custom in headers, specific for this command (or NULL) - * @param filename filename of data - * @param err error object (should be pointer to NULL object) - * @return list of rspamd_controller_result structures for each server - */ -GList* -rspamd_controller_command_file (struct rspamd_client* client, const gchar *command, const gchar *password, - GHashTable *in_headers, const gchar *filename, GError **err) -{ - gint fd; - - /* Open file */ - if ((fd = open (filename, O_RDONLY)) == -1) { - if (*err == NULL) { - *err = g_error_new (G_RSPAMD_ERROR, errno, "Open error for file %s: %s", - filename, strerror (errno)); - } - return NULL; - } - return rspamd_controller_command_common (client, command, password, in_headers, NULL, fd, err); -} - - -/* - * Free results - */ -void -rspamd_free_result (struct rspamd_result *result) -{ - g_assert (result != NULL); - - g_hash_table_destroy (result->headers); - g_hash_table_destroy (result->metrics); - if (result->conn) { - rspamd_free_connection (result->conn); - } -} - -void -rspamd_free_controller_result (struct rspamd_controller_result *result) -{ - g_assert (result != NULL); - - g_hash_table_destroy (result->headers); - g_string_free (result->result, TRUE); - if (result->data) { - g_string_free (result->data, TRUE); - } - if (result->conn) { - rspamd_free_connection (result->conn); - } -} - -/* - * Close library and free associated resources - */ -void -rspamd_client_close (struct rspamd_client *client) -{ - struct rspamd_server *serv; - guint i; - - if (client->bind_addr) { - g_free (client->bind_addr); - } - - /* Cleanup servers */ - for (i = 0; i < client->servers_num; i ++) { - serv = &client->servers[i]; - g_free (serv->host); - g_free (serv->name); - g_free (serv->controller_name); - } - - g_free (client); -} diff --git a/lib/client/librspamdclient.h b/lib/client/librspamdclient.h deleted file mode 100644 index 828bcd422..000000000 --- a/lib/client/librspamdclient.h +++ /dev/null @@ -1,158 +0,0 @@ -#ifndef LIBRSPAMD_CLIENT_H -#define LIBRSPAMD_CLIENT_H - -#include - -/** - * Struct for representing symbols - */ -struct rspamd_symbol { - gchar *name; /**< name */ - gchar *description; /**< description */ - double weight; /**< weight */ - GList *options; /**< List of options (as const gchar *) */ -}; - -/** - * Struct for representing metrics - */ -struct rspamd_metric { - gchar *name; - gchar *action; - double score; - double required_score; - double reject_score; - gboolean is_skipped; - GHashTable *symbols; -}; - -struct rspamd_connection; -struct rspamd_client; -struct in_addr; - -/** - * Result of scan - */ -struct rspamd_result { - struct rspamd_connection *conn; - gboolean is_ok; - GHashTable *metrics; - GHashTable *headers; -}; - -/** - * Result of controller command - */ -struct rspamd_controller_result { - struct rspamd_connection *conn; - const gchar *server_name; - gint code; - GString *result; - GHashTable *headers; - GString *data; -}; - -/** - * Init rspamd client library - */ -struct rspamd_client* rspamd_client_init (void); - -/** - * Init rspamd client library and bind it - */ -struct rspamd_client* rspamd_client_init_binded (const struct in_addr *local_addr); - -/** - * Add rspamd server - */ -gboolean rspamd_add_server (struct rspamd_client* client, const gchar *host, - guint16 port, guint16 controller_port, GError **err); - -/** - * Set timeouts (values in milliseconds) - */ -void rspamd_set_timeout (struct rspamd_client* client, guint connect_timeout, guint read_timeout); - -/** - * Scan message from memory - */ -struct rspamd_result * rspamd_scan_memory (struct rspamd_client* client, const guchar *message, gsize length, GHashTable *headers, GError **err); - -/** - * Scan message from file - */ -struct rspamd_result * rspamd_scan_file (struct rspamd_client* client, const guchar *filename, GHashTable *headers, GError **err); - -/** - * Scan message from fd - */ -struct rspamd_result * rspamd_scan_fd (struct rspamd_client* client, int fd, GHashTable *headers, GError **err); - -/** - * Perform a simple controller command on all rspamd servers - * @param client rspamd client - * @param command command to send - * @param password password (NULL if no password required) - * @param in_headers custom in headers, specific for this command (or NULL) - * @param err error object (should be pointer to NULL object) - * @return list of rspamd_controller_result structures for each server - */ -GList* rspamd_controller_command_simple (struct rspamd_client* client, const gchar *command, const gchar *password, - GHashTable *in_headers, GError **err); - -/** - * Perform a controller command on all rspamd servers with in memory argument - * @param client rspamd client - * @param command command to send - * @param password password (NULL if no password required) - * @param in_headers custom in headers, specific for this command (or NULL) - * @param message data to pass to the controller - * @param length its length - * @param err error object (should be pointer to NULL object) - * @return list of rspamd_controller_result structures for each server - */ -GList* rspamd_controller_command_memory (struct rspamd_client* client, const gchar *command, const gchar *password, - GHashTable *in_headers, const guchar *message, gsize length, GError **err); - -/** - * Perform a controller command on all rspamd servers with descriptor argument - * @param client rspamd client - * @param command command to send - * @param password password (NULL if no password required) - * @param in_headers custom in headers, specific for this command (or NULL) - * @param fd file descriptor of data - * @param err error object (should be pointer to NULL object) - * @return list of rspamd_controller_result structures for each server - */ -GList* rspamd_controller_command_fd (struct rspamd_client* client, const gchar *command, const gchar *password, - GHashTable *in_headers, gint fd, GError **err); - -/** - * Perform a controller command on all rspamd servers with descriptor argument - * @param client rspamd client - * @param command command to send - * @param password password (NULL if no password required) - * @param in_headers custom in headers, specific for this command (or NULL) - * @param filename filename of data - * @param err error object (should be pointer to NULL object) - * @return list of rspamd_controller_result structures for each server - */ -GList* rspamd_controller_command_file (struct rspamd_client* client, const gchar *command, const gchar *password, - GHashTable *in_headers, const gchar *filename, GError **err); - -/* - * Free results - */ -void rspamd_free_result (struct rspamd_result *result); - -/* - * Free controller results - */ -void rspamd_free_controller_result (struct rspamd_controller_result *result); - -/* - * Close library and free associated resources - */ -void rspamd_client_close (struct rspamd_client *client); - -#endif diff --git a/lib/kvstorage/libkvstorageclient.c b/lib/kvstorage/libkvstorageclient.c deleted file mode 100644 index e0971f22a..000000000 --- a/lib/kvstorage/libkvstorageclient.c +++ /dev/null @@ -1,1179 +0,0 @@ -/* Copyright (c) 2010, Vsevolod Stakhov - * 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 ''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 AUTHOR 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 "mem_pool.h" -#include "util.h" -#include "libkvstorageclient.h" - -#define MAX_KV_LINE 1024 - -#ifdef CRLF -#undef CRLF -#undef CR -#undef LF -#endif - -#define CRLF "\r\n" -#define CR '\r' -#define LF '\n' - -struct kvstorage_buf { - guint pos; - guint len; - guint8 data[1]; -}; - -struct rspamd_kvstorage_connection { - gboolean asynced; - gint sock; - struct timeval tv; - enum { - KV_STATE_NONE = 0, - KV_STATE_CONNECTED, - KV_STATE_SET, - KV_STATE_GET, - KV_STATE_WRITE_DATA, - KV_STATE_READ_DATA, - KV_STATE_READ_ELT, - KV_STATE_READ_REPLY - } state; - struct event ev; - kvstorage_connect_cb conn_cb; - kvstorage_read_cb read_cb; - kvstorage_write_cb write_cb; - memory_pool_t *pool; -}; - -struct rspamd_kvstorage_async_data { - struct rspamd_kvstorage_connection *c; - struct kvstorage_buf *buf; - gchar *key; - guint keylen; - gpointer data; - guint datalen; - guint expire; - gpointer ud; -}; - -/* - * Buffer functions - */ - -/* - * Create new kvstorage_buf - */ -static struct kvstorage_buf * -rspamd_kvstorage_buf_create (guint size, memory_pool_t *pool) -{ - struct kvstorage_buf *new; - - new = memory_pool_alloc (pool, sizeof (struct kvstorage_buf) + size); - new->len = size; - new->pos = 0; - - return new; -} - -/* - * Read a single line synced or asynced - */ -static gint -rspamd_kvstorage_buf_readline (struct kvstorage_buf *buf, struct rspamd_kvstorage_connection *conn) -{ - gint r; - guint8 *p; - - r = read (conn->sock, buf->data, buf->len); - if (r == -1) { - return errno; - } - /* Try to parse what we have */ - p = buf->data; - while (p - buf->data < r) { - if (*p == '\r' || *p == '\n') { - - buf->pos = p - buf->data; - return 0; - } - p ++; - } - - if (r == (gint)buf->len) { - /* Buffer is overflowed */ - return EOVERFLOW; - } - /* Line end not found */ - return EAGAIN; -} - -/* - * Read the whole buffer, return remaining characters or -1 - */ -static gint -rspamd_kvstorage_buf_readall (struct kvstorage_buf *buf, struct rspamd_kvstorage_connection *conn) -{ - gint r; - - if (buf->len - buf->pos == 0) { - return 0; - } - r = read (conn->sock, buf->data + buf->pos, buf->len - buf->pos); - if (r == -1) { - return -1; - } - - buf->pos += r; - - /* Line end not found */ - return buf->len - buf->pos; -} - -/* - * Write the whole buffer, return remaining characters or -1 - */ -static gint -rspamd_kvstorage_buf_writeall (struct kvstorage_buf *buf, struct rspamd_kvstorage_connection *conn) -{ - gint r; - - if (buf->len - buf->pos == 0) { - return 0; - } - r = write (conn->sock, buf->data + buf->pos, buf->len - buf->pos); - if (r == -1) { - return -1; - } - - buf->pos += r; - - /* Line end not found */ - return buf->len - buf->pos; -} - -/* - * Drain line from the begin of buffer, moving it from the beginning of buf - */ -static void -rspamd_kvstorage_buf_drainline (struct kvstorage_buf *buf) -{ - guint8 *p; - - p = buf->data + buf->pos; - /* Skip \r and \n characters */ - while (p - buf->data < (gint)buf->len && (*p == '\r' || *p == '\n')) { - p ++; - } - if (p - buf->data == (gint)buf->len) { - /* Do not move anything */ - buf->pos = 0; - return; - } - memcpy (buf->data, p, buf->len - (p - buf->data)); - buf->pos = buf->len - (p - buf->data); -} - -/* Common utility functions */ - -/* - * Parse reply line that contains an error - */ -static enum rspamd_kvstorage_error -rspamd_kvstorage_parse_reply_error (struct kvstorage_buf *buf) -{ - guint8 *p; - guint l = 0; - - /* Get one word */ - p = buf->data; - while (p - buf->data < (gint)buf->pos) { - if (g_ascii_isspace (*p)) { - while (p - buf->data < (gint)buf->pos && g_ascii_isspace (*p)) { - p ++; - } - break; - } - p ++; - l ++; - } - - /* Get common errors */ - if (g_ascii_strncasecmp (buf->data, "ERROR", MIN (l, sizeof("ERORR") - 1)) == 0) { - return KVSTORAGE_ERROR_INTERNAL_ERROR; - } - else if (g_ascii_strncasecmp (buf->data, "SERVER_ERROR", MIN (l, sizeof("SERVER_ERORR") - 1)) == 0) { - return KVSTORAGE_ERROR_SERVER_ERROR; - } - else if (g_ascii_strncasecmp (buf->data, "CLIENT_ERROR", MIN (l, sizeof("CLIENT_ERORR") - 1)) == 0) { - return KVSTORAGE_ERROR_CLIENT_ERROR; - } - else if (g_ascii_strncasecmp (buf->data, "NOT_STORED", MIN (l, sizeof("NOT_STORED") - 1)) == 0) { - return KVSTORAGE_ERROR_NOT_STORED; - } - else if (g_ascii_strncasecmp (buf->data, "NOT_FOUND", MIN (l, sizeof("NOT_FOUND") - 1)) == 0) { - return KVSTORAGE_ERROR_NOT_FOUND; - } - else if (g_ascii_strncasecmp (buf->data, "EXISTS", MIN (l, sizeof("EXISTS") - 1)) == 0) { - return KVSTORAGE_ERROR_EXISTS; - } - else if (g_ascii_strncasecmp (buf->data, "STORED", MIN (l, sizeof("STORED") - 1)) == 0) { - return KVSTORAGE_ERROR_OK; - } - else if (g_ascii_strncasecmp (buf->data, "DELETED", MIN (l, sizeof("DELETED") - 1)) == 0) { - return KVSTORAGE_ERROR_OK; - } - - return KVSTORAGE_ERROR_INTERNAL_ERROR; -} - -/* - * Parse reply line, store element length - */ -static enum rspamd_kvstorage_error -rspamd_kvstorage_parse_get_line (struct kvstorage_buf *buf, guint *len, guint *flags) -{ - guint8 *p, *c, *end; - gboolean error = TRUE; - gchar *err_str; - - p = buf->data; - end = buf->data + buf->pos; - while (p < end) { - if (g_ascii_isspace (*p)) { - error = FALSE; - while (p - buf->data < (gint)buf->pos && g_ascii_isspace (*p)) { - p ++; - } - break; - } - p ++; - } - /* Here we got a word or error flag */ - if (error) { - /* Something wrong here */ - return KVSTORAGE_ERROR_SERVER_ERROR; - } - if (g_ascii_strncasecmp (buf->data, "VALUE", sizeof ("VALUE") - 1) != 0) { - return rspamd_kvstorage_parse_reply_error (buf); - } - /* Here we got key, flags and size items */ - /* Skip key */ - error = TRUE; - while (p < end) { - if (g_ascii_isspace (*p)) { - error = FALSE; - /* Skip spaces after key */ - while (p < end && g_ascii_isspace (*p)) { - p ++; - } - break; - } - p ++; - } - if (error) { - /* Something wrong here */ - return KVSTORAGE_ERROR_SERVER_ERROR; - } - /* Read flags */ - c = p; - error = TRUE; - while (p < end) { - if (g_ascii_isspace (*p)) { - error = FALSE; - /* Skip spaces after flags */ - while (p - buf->data < (gint)buf->pos && g_ascii_isspace (*p)) { - p ++; - } - break; - } - else if (!g_ascii_isdigit (*p)) { - break; - } - p ++; - } - if (error) { - /* Something wrong here */ - return KVSTORAGE_ERROR_SERVER_ERROR; - } - *flags = strtoul (c, &err_str, 10); - if (!g_ascii_isspace (*err_str)) { - return KVSTORAGE_ERROR_SERVER_ERROR; - } - /* Read len */ - c = p; - while (p < end) { - if (!g_ascii_isdigit (*p)) { - break; - } - p ++; - } - if (error) { - /* Something wrong here */ - return KVSTORAGE_ERROR_SERVER_ERROR; - } - *len = strtoul (c, &err_str, 10); - if (!g_ascii_isspace (*err_str)) { - return KVSTORAGE_ERROR_SERVER_ERROR; - } - - return KVSTORAGE_ERROR_OK; -} - -/* Callbacks for async API */ -static void -rspamd_kvstorage_connect_cb (int fd, short what, gpointer ud) -{ - struct rspamd_kvstorage_async_data *d = ud; - kvstorage_connect_cb cb; - - cb = (kvstorage_connect_cb)d->c->conn_cb; - - if (what == EV_TIMEOUT) { - cb (KVSTORAGE_ERROR_TIMEOUT, d->c, d->ud); - } - else { - d->c->state = KV_STATE_CONNECTED; - cb (KVSTORAGE_ERROR_OK, d->c, d->ud); - } -} - -static void -rspamd_kvstorage_read_cb (int fd, short what, gpointer ud) -{ - struct rspamd_kvstorage_async_data *d = ud; - kvstorage_read_cb cb; - guint buflen, flags; - gint r; - struct kvstorage_buf *databuf; - - cb = (kvstorage_read_cb)d->c->read_cb; - - if (what == EV_TIMEOUT) { - cb (KVSTORAGE_ERROR_TIMEOUT, d->key, d->keylen, NULL, 0, d->c, d->ud); - return; - } - if (d->c->state == KV_STATE_GET) { - /* Create, fill and write buffer */ - buflen = d->keylen + sizeof ("get " CRLF); - d->buf = rspamd_kvstorage_buf_create (buflen, d->c->pool); - - r = rspamd_snprintf (d->buf->data, d->buf->len, "get %*s" CRLF, - d->keylen, d->key); - d->buf->len = r; - r = rspamd_kvstorage_buf_writeall (d->buf, d->c); - if (r > 0) { - /* Write more data at next call of this function */ - d->c->state = KV_STATE_WRITE_DATA; - /* Event magic */ - event_del (&d->c->ev); - event_set (&d->c->ev, d->c->sock, EV_WRITE, rspamd_kvstorage_read_cb, d); - if (d->c->tv.tv_sec != 0 || d->c->tv.tv_usec != 0) { - event_add (&d->c->ev, &d->c->tv); - } - else { - event_add (&d->c->ev, NULL); - } - } - else if (r == 0) { - /* We have written everything */ - d->buf = rspamd_kvstorage_buf_create (MAX_KV_LINE, d->c->pool); - d->c->state = KV_STATE_READ_ELT; - event_del (&d->c->ev); - event_set (&d->c->ev, d->c->sock, EV_READ, rspamd_kvstorage_read_cb, d); - if (d->c->tv.tv_sec != 0 || d->c->tv.tv_usec != 0) { - event_add (&d->c->ev, &d->c->tv); - } - else { - event_add (&d->c->ev, NULL); - } - } - else { - /* Error occured during writing */ - cb (KVSTORAGE_ERROR_INTERNAL_ERROR, d->key, d->keylen, NULL, 0, d->c, d->ud); - } - } - else if (d->c->state == KV_STATE_WRITE_DATA) { - r = rspamd_kvstorage_buf_writeall (d->buf, d->c); - if (r > 0) { - /* Write more data at next call of this function */ - d->c->state = KV_STATE_WRITE_DATA; - /* Event magic */ - event_del (&d->c->ev); - event_set (&d->c->ev, d->c->sock, EV_WRITE, rspamd_kvstorage_read_cb, d); - if (d->c->tv.tv_sec != 0 || d->c->tv.tv_usec != 0) { - event_add (&d->c->ev, &d->c->tv); - } - else { - event_add (&d->c->ev, NULL); - } - } - else if (r == 0) { - /* We have written everything */ - d->c->state = KV_STATE_READ_ELT; - d->buf = rspamd_kvstorage_buf_create (MAX_KV_LINE, d->c->pool); - event_del (&d->c->ev); - event_set (&d->c->ev, d->c->sock, EV_READ, rspamd_kvstorage_read_cb, d); - if (d->c->tv.tv_sec != 0 || d->c->tv.tv_usec != 0) { - event_add (&d->c->ev, &d->c->tv); - } - else { - event_add (&d->c->ev, NULL); - } - } - else { - /* Error occured during writing */ - cb (KVSTORAGE_ERROR_INTERNAL_ERROR, d->key, d->keylen, NULL, 0, d->c, d->ud); - } - } - else if (d->c->state == KV_STATE_READ_ELT) { - /* Read element info */ - r = rspamd_kvstorage_buf_readline (d->buf, d->c); - if (r == EAGAIN) { - /* Read more data */ - event_del (&d->c->ev); - event_set (&d->c->ev, d->c->sock, EV_READ, rspamd_kvstorage_read_cb, d); - if (d->c->tv.tv_sec != 0 || d->c->tv.tv_usec != 0) { - event_add (&d->c->ev, &d->c->tv); - } - else { - event_add (&d->c->ev, NULL); - } - } - else if (r == 0) { - /* Got all data about elt */ - if ((r = rspamd_kvstorage_parse_get_line (d->buf, &d->datalen, &flags)) != KVSTORAGE_ERROR_OK) { - cb (KVSTORAGE_ERROR_INTERNAL_ERROR, d->key, d->keylen, NULL, 0, d->c, d->ud); - return; - } - rspamd_kvstorage_buf_drainline (d->buf); - - /* Now allocate and read the data */ - databuf = rspamd_kvstorage_buf_create (d->datalen, d->c->pool); - memcpy (databuf->data, d->buf->data, d->buf->pos); - d->buf = databuf; - d->c->state = KV_STATE_READ_DATA; - event_del (&d->c->ev); - event_set (&d->c->ev, d->c->sock, EV_READ, rspamd_kvstorage_read_cb, d); - if (d->c->tv.tv_sec != 0 || d->c->tv.tv_usec != 0) { - event_add (&d->c->ev, &d->c->tv); - } - else { - event_add (&d->c->ev, NULL); - } - } - else { - /* Error occured during reading reply line */ - cb (KVSTORAGE_ERROR_INTERNAL_ERROR, d->key, d->keylen, NULL, 0, d->c, d->ud); - } - } - else if (d->c->state == KV_STATE_READ_DATA) { - /* Read data to the buffer */ - r = rspamd_kvstorage_buf_readall (d->buf, d->c); - if (r == 0) { - /* All data read, read the last line */ - d->c->state = KV_STATE_READ_REPLY; - /* Save databuf */ - d->data = d->buf->data; - event_del (&d->c->ev); - event_set (&d->c->ev, d->c->sock, EV_READ, rspamd_kvstorage_read_cb, d); - if (d->c->tv.tv_sec != 0 || d->c->tv.tv_usec != 0) { - event_add (&d->c->ev, &d->c->tv); - } - else { - event_add (&d->c->ev, NULL); - } - } - else if (r > 0) { - /* Read more data into buffer */ - event_del (&d->c->ev); - event_set (&d->c->ev, d->c->sock, EV_READ, rspamd_kvstorage_read_cb, d); - if (d->c->tv.tv_sec != 0 || d->c->tv.tv_usec != 0) { - event_add (&d->c->ev, &d->c->tv); - } - else { - event_add (&d->c->ev, NULL); - } - } - else { - /* Error occured */ - cb (KVSTORAGE_ERROR_INTERNAL_ERROR, d->key, d->keylen, NULL, 0, d->c, d->ud); - } - } - else if (d->c->state == KV_STATE_READ_REPLY) { - /* Got something from server, try to read line */ - r = rspamd_kvstorage_buf_readline (d->buf, d->c); - if (r == EAGAIN) { - /* Read more data */ - event_del (&d->c->ev); - event_set (&d->c->ev, d->c->sock, EV_READ, rspamd_kvstorage_read_cb, d); - if (d->c->tv.tv_sec != 0 || d->c->tv.tv_usec != 0) { - event_add (&d->c->ev, &d->c->tv); - } - else { - event_add (&d->c->ev, NULL); - } - } - else if (r == 0) { - d->c->state = KV_STATE_CONNECTED; - cb (rspamd_kvstorage_parse_reply_error (d->buf), d->key, d->keylen, d->data, d->datalen, d->c, d->ud); - } - else { - /* Error occured during reading reply line */ - cb (KVSTORAGE_ERROR_INTERNAL_ERROR, d->key, d->keylen, NULL, 0, d->c, d->ud); - } - } -} - -static void -rspamd_kvstorage_write_cb (int fd, short what, gpointer ud) -{ - struct rspamd_kvstorage_async_data *d = ud; - kvstorage_write_cb cb; - guint buflen; - gint r; - - cb = (kvstorage_write_cb)d->c->write_cb; - - if (what == EV_TIMEOUT) { - cb (KVSTORAGE_ERROR_TIMEOUT, d->key, d->keylen, d->c, d->ud); - return; - } - if (d->c->state == KV_STATE_SET) { - /* Create, fill and write buffer */ - buflen = d->datalen + d->keylen + sizeof ("set 4294967296 4294967296 4294967296" CRLF); - d->buf = rspamd_kvstorage_buf_create (buflen, d->c->pool); - - r = rspamd_snprintf (d->buf->data, d->buf->len, "set %*s %ud %ud %ud" CRLF "%*s", - d->keylen, d->key, 0, d->expire, d->datalen, d->datalen, d->data); - d->buf->len = r; - r = rspamd_kvstorage_buf_writeall (d->buf, d->c); - if (r > 0) { - /* Write more data at next call of this function */ - d->c->state = KV_STATE_WRITE_DATA; - /* Event magic */ - event_del (&d->c->ev); - event_set (&d->c->ev, d->c->sock, EV_WRITE, rspamd_kvstorage_write_cb, d); - if (d->c->tv.tv_sec != 0 || d->c->tv.tv_usec != 0) { - event_add (&d->c->ev, &d->c->tv); - } - else { - event_add (&d->c->ev, NULL); - } - } - else if (r == 0) { - /* We have written everything */ - d->buf = rspamd_kvstorage_buf_create (MAX_KV_LINE, d->c->pool); - d->c->state = KV_STATE_READ_REPLY; - event_del (&d->c->ev); - event_set (&d->c->ev, d->c->sock, EV_READ, rspamd_kvstorage_write_cb, d); - if (d->c->tv.tv_sec != 0 || d->c->tv.tv_usec != 0) { - event_add (&d->c->ev, &d->c->tv); - } - else { - event_add (&d->c->ev, NULL); - } - } - else { - /* Error occured during writing */ - cb (KVSTORAGE_ERROR_INTERNAL_ERROR, d->key, d->keylen, d->c, d->ud); - } - } - else if (d->c->state == KV_STATE_WRITE_DATA) { - r = rspamd_kvstorage_buf_writeall (d->buf, d->c); - if (r > 0) { - /* Write more data at next call of this function */ - d->c->state = KV_STATE_WRITE_DATA; - /* Event magic */ - event_del (&d->c->ev); - event_set (&d->c->ev, d->c->sock, EV_WRITE, rspamd_kvstorage_write_cb, d); - if (d->c->tv.tv_sec != 0 || d->c->tv.tv_usec != 0) { - event_add (&d->c->ev, &d->c->tv); - } - else { - event_add (&d->c->ev, NULL); - } - } - else if (r == 0) { - /* We have written everything */ - d->c->state = KV_STATE_READ_REPLY; - d->buf = rspamd_kvstorage_buf_create (MAX_KV_LINE, d->c->pool); - event_del (&d->c->ev); - event_set (&d->c->ev, d->c->sock, EV_READ, rspamd_kvstorage_write_cb, d); - if (d->c->tv.tv_sec != 0 || d->c->tv.tv_usec != 0) { - event_add (&d->c->ev, &d->c->tv); - } - else { - event_add (&d->c->ev, NULL); - } - } - else { - /* Error occured during writing */ - cb (KVSTORAGE_ERROR_INTERNAL_ERROR, d->key, d->keylen, d->c, d->ud); - } - } - else if (d->c->state == KV_STATE_READ_REPLY) { - /* Got something from server, try to read line */ - r = rspamd_kvstorage_buf_readline (d->buf, d->c); - if (r == EAGAIN) { - /* Read more data */ - event_del (&d->c->ev); - event_set (&d->c->ev, d->c->sock, EV_READ, rspamd_kvstorage_write_cb, d); - if (d->c->tv.tv_sec != 0 || d->c->tv.tv_usec != 0) { - event_add (&d->c->ev, &d->c->tv); - } - else { - event_add (&d->c->ev, NULL); - } - } - else if (r == 0) { - d->c->state = KV_STATE_CONNECTED; - cb (rspamd_kvstorage_parse_reply_error (d->buf), d->key, d->keylen, d->c, d->ud); - } - else { - /* Error occured during reading reply line */ - cb (KVSTORAGE_ERROR_INTERNAL_ERROR, d->key, d->keylen, d->c, d->ud); - } - } -} - -static void -rspamd_kvstorage_delete_cb (int fd, short what, gpointer ud) -{ - struct rspamd_kvstorage_async_data *d = ud; - kvstorage_write_cb cb; - guint buflen; - gint r; - - cb = (kvstorage_write_cb)d->c->write_cb; - - if (what == EV_TIMEOUT) { - cb (KVSTORAGE_ERROR_TIMEOUT, d->key, d->keylen, d->c, d->ud); - return; - } - if (d->c->state == KV_STATE_SET) { - /* Create, fill and write buffer */ - buflen = MAX (MAX_KV_LINE, d->keylen + sizeof ("delete " CRLF)); - d->buf = rspamd_kvstorage_buf_create (buflen, d->c->pool); - - r = rspamd_snprintf (d->buf->data, d->buf->len, "delete %*s" CRLF, - d->keylen, d->key); - d->buf->len = r; - r = rspamd_kvstorage_buf_writeall (d->buf, d->c); - if (r > 0) { - /* Write more data at next call of this function */ - d->c->state = KV_STATE_WRITE_DATA; - /* Event magic */ - event_del (&d->c->ev); - event_set (&d->c->ev, d->c->sock, EV_WRITE, rspamd_kvstorage_delete_cb, d); - if (d->c->tv.tv_sec != 0 || d->c->tv.tv_usec != 0) { - event_add (&d->c->ev, &d->c->tv); - } - else { - event_add (&d->c->ev, NULL); - } - } - else if (r == 0) { - /* We have written everything */ - d->buf = rspamd_kvstorage_buf_create (MAX_KV_LINE, d->c->pool); - d->c->state = KV_STATE_READ_REPLY; - event_del (&d->c->ev); - event_set (&d->c->ev, d->c->sock, EV_READ, rspamd_kvstorage_delete_cb, d); - if (d->c->tv.tv_sec != 0 || d->c->tv.tv_usec != 0) { - event_add (&d->c->ev, &d->c->tv); - } - else { - event_add (&d->c->ev, NULL); - } - } - else { - /* Error occured during writing */ - cb (KVSTORAGE_ERROR_INTERNAL_ERROR, d->key, d->keylen, d->c, d->ud); - } - } - else if (d->c->state == KV_STATE_WRITE_DATA) { - r = rspamd_kvstorage_buf_writeall (d->buf, d->c); - if (r > 0) { - /* Write more data at next call of this function */ - d->c->state = KV_STATE_WRITE_DATA; - /* Event magic */ - event_del (&d->c->ev); - event_set (&d->c->ev, d->c->sock, EV_WRITE, rspamd_kvstorage_delete_cb, d); - if (d->c->tv.tv_sec != 0 || d->c->tv.tv_usec != 0) { - event_add (&d->c->ev, &d->c->tv); - } - else { - event_add (&d->c->ev, NULL); - } - } - else if (r == 0) { - /* We have written everything */ - d->c->state = KV_STATE_READ_REPLY; - d->buf = rspamd_kvstorage_buf_create (MAX_KV_LINE, d->c->pool); - event_del (&d->c->ev); - event_set (&d->c->ev, d->c->sock, EV_READ, rspamd_kvstorage_delete_cb, d); - if (d->c->tv.tv_sec != 0 || d->c->tv.tv_usec != 0) { - event_add (&d->c->ev, &d->c->tv); - } - else { - event_add (&d->c->ev, NULL); - } - } - else { - /* Error occured during writing */ - cb (KVSTORAGE_ERROR_INTERNAL_ERROR, d->key, d->keylen, d->c, d->ud); - } - } - else if (d->c->state == KV_STATE_READ_REPLY) { - /* Got something from server, try to read line */ - r = rspamd_kvstorage_buf_readline (d->buf, d->c); - if (r == EAGAIN) { - /* Read more data */ - event_del (&d->c->ev); - event_set (&d->c->ev, d->c->sock, EV_READ, rspamd_kvstorage_delete_cb, d); - if (d->c->tv.tv_sec != 0 || d->c->tv.tv_usec != 0) { - event_add (&d->c->ev, &d->c->tv); - } - else { - event_add (&d->c->ev, NULL); - } - } - else if (r == 0) { - d->c->state = KV_STATE_CONNECTED; - cb (rspamd_kvstorage_parse_reply_error (d->buf), d->key, d->keylen, d->c, d->ud); - } - else { - /* Error occured during reading reply line */ - cb (KVSTORAGE_ERROR_INTERNAL_ERROR, d->key, d->keylen, d->c, d->ud); - } - } -} - -/** - * Create async connection with rspamd - * @param host hostname, ip or unix socket for a server - * @param port port number in host byte order - * @param tv timeout for operations - * @param cb callback - * @param ud user data for callback - * @param conn target connection - */ -enum rspamd_kvstorage_error -rspamd_kvstorage_connect_async (const gchar *host, - guint16 port, struct timeval *tv, kvstorage_connect_cb cb, gpointer ud, - struct rspamd_kvstorage_connection **conn) -{ - struct rspamd_kvstorage_connection *new; - struct rspamd_kvstorage_async_data *data; - gint sock; - - /* Here we do NOT try to resolve hostname */ - if ((sock = make_universal_socket (host, port, SOCK_STREAM, TRUE, FALSE, TRUE)) == -1) { - return KVSTORAGE_ERROR_SERVER_ERROR; - } - - /* Allocate new connection structure */ - new = g_malloc (sizeof (struct rspamd_kvstorage_connection)); - - /* Set fields */ - new->sock = sock; - new->state = KV_STATE_NONE; - new->asynced = TRUE; - if (tv != NULL) { - memcpy (&new->tv, tv, sizeof (struct timeval)); - } - else { - memset (&new->tv, 0, sizeof (struct timeval)); - } - - new->conn_cb = cb; - new->pool = memory_pool_new (memory_pool_get_size ()); - data = memory_pool_alloc (new->pool, sizeof (struct rspamd_kvstorage_async_data)); - data->ud = ud; - data->c = new; - - /* Set event */ - event_set (&new->ev, new->sock, EV_WRITE, rspamd_kvstorage_connect_cb, data); - if (tv != NULL) { - event_add (&new->ev, &new->tv); - } - else { - event_add (&new->ev, NULL); - } - - *conn = new; - return KVSTORAGE_ERROR_OK; -} - -/** - * Read key asynced - * @param conn connection structure - * @param key key to read - * @param cb callback - * @param ud user data for callback - */ -enum rspamd_kvstorage_error -rspamd_kvstorage_get_async (struct rspamd_kvstorage_connection *conn, - const gpointer key, guint keylen, kvstorage_read_cb cb, gpointer ud) -{ - struct rspamd_kvstorage_async_data *d; - - if (conn == NULL || conn->state != KV_STATE_CONNECTED) { - return KVSTORAGE_ERROR_INTERNAL_ERROR; - } - else { - conn->read_cb = cb; - d = memory_pool_alloc (conn->pool, sizeof (struct rspamd_kvstorage_async_data)); - d->ud = ud; - d->c = conn; - d->ud = ud; - d->key = memory_pool_strdup (conn->pool, key); - d->keylen = keylen; - conn->state = KV_STATE_GET; - - /* Set event */ - event_set (&conn->ev, conn->sock, EV_WRITE, rspamd_kvstorage_read_cb, d); - if (conn->tv.tv_sec != 0) { - event_add (&conn->ev, &conn->tv); - } - else { - event_add (&conn->ev, NULL); - } - } - return KVSTORAGE_ERROR_OK; -} - -/** - * Write key asynced - * @param conn connection structure - * @param key key to set - * @param value data to write - * @param cb callback - * @param ud user data for callback - */ -enum rspamd_kvstorage_error -rspamd_kvstorage_set_async (struct rspamd_kvstorage_connection *conn, - const gpointer key, guint keylen, const gpointer value, gsize len, guint expire, kvstorage_write_cb cb, - gpointer ud) -{ - struct rspamd_kvstorage_async_data *d; - - if (conn == NULL || conn->state != KV_STATE_CONNECTED) { - return KVSTORAGE_ERROR_INTERNAL_ERROR; - } - else { - conn->write_cb = cb; - d = memory_pool_alloc (conn->pool, sizeof (struct rspamd_kvstorage_async_data)); - d->ud = ud; - d->c = conn; - d->ud = ud; - d->key = memory_pool_strdup (conn->pool, key); - d->keylen = keylen; - d->data = value; - d->datalen = len; - conn->state = KV_STATE_SET; - - /* Set event */ - event_set (&conn->ev, conn->sock, EV_WRITE, rspamd_kvstorage_write_cb, d); - if (conn->tv.tv_sec != 0) { - event_add (&conn->ev, &conn->tv); - } - else { - event_add (&conn->ev, NULL); - } - } - return KVSTORAGE_ERROR_OK; -} - -/** - * Delete key asynced - * @param conn connection structure - * @param key key to delete - * @param cb callback - * @param ud user data for callback - */ -enum rspamd_kvstorage_error -rspamd_kvstorage_delete_async (struct rspamd_kvstorage_connection *conn, - const gpointer key, guint keylen, kvstorage_write_cb cb, gpointer ud) -{ - struct rspamd_kvstorage_async_data *d; - - if (conn == NULL || conn->state != KV_STATE_CONNECTED) { - return KVSTORAGE_ERROR_INTERNAL_ERROR; - } - else { - conn->write_cb = cb; - d = memory_pool_alloc (conn->pool, sizeof (struct rspamd_kvstorage_async_data)); - d->ud = ud; - d->c = conn; - d->ud = ud; - d->key = memory_pool_strdup (conn->pool, key); - d->keylen = keylen; - conn->state = KV_STATE_SET; - - /* Set event */ - event_set (&conn->ev, conn->sock, EV_WRITE, rspamd_kvstorage_delete_cb, d); - if (conn->tv.tv_sec != 0) { - event_add (&conn->ev, &conn->tv); - } - else { - event_add (&conn->ev, NULL); - } - } - return KVSTORAGE_ERROR_OK; -} - -/** - * Close connection - * @param conn connection structure - */ -enum rspamd_kvstorage_error -rspamd_kvstorage_close_async (struct rspamd_kvstorage_connection *conn) -{ - close (conn->sock); - memory_pool_delete (conn->pool); - event_del (&conn->ev); - g_free (conn); - - return KVSTORAGE_ERROR_OK; -} - -/* Synced API */ -/** - * Create sync connection with rspamd - * @param host hostname, ip or unix socket for a server - * @param port port number in host byte order - * @param tv timeout for operations - * @param conn target connection - */ -enum rspamd_kvstorage_error -rspamd_kvstorage_connect_sync (const gchar *host, - guint16 port, struct timeval *tv, - struct rspamd_kvstorage_connection **conn) -{ - struct rspamd_kvstorage_connection *new; - gint sock; - - if ((sock = make_universal_socket (host, port, SOCK_STREAM, FALSE, FALSE, TRUE)) == -1) { - return KVSTORAGE_ERROR_INTERNAL_ERROR; - } - - /* Allocate new connection structure */ - new = g_malloc (sizeof (struct rspamd_kvstorage_connection)); - - /* Set fields */ - new->sock = sock; - new->state = KV_STATE_CONNECTED; - new->asynced = FALSE; - if (tv != NULL) { - memcpy (&new->tv, tv, sizeof (struct timeval)); - } - else { - memset (&new->tv, 0, sizeof (struct timeval)); - } - new->pool = memory_pool_new (memory_pool_get_size ()); - - *conn = new; - return KVSTORAGE_ERROR_OK; -} - -/** - * Read key synced - * @param conn connection structure - * @param key key to read - * @param value value readed - */ -enum rspamd_kvstorage_error -rspamd_kvstorage_get_sync (struct rspamd_kvstorage_connection *conn, - const gpointer key, guint keylen, gpointer **value, guint *len) -{ - struct kvstorage_buf *buf, *databuf; - gint r; - guint flags; - - if (conn == NULL || conn->state != KV_STATE_CONNECTED) { - return KVSTORAGE_ERROR_INTERNAL_ERROR; - } - - buf = rspamd_kvstorage_buf_create (MAX_KV_LINE, conn->pool); - - r = rspamd_snprintf (buf->data, buf->len, "get %*s" CRLF, keylen, key); - buf->len = r; - while ((r = rspamd_kvstorage_buf_writeall (buf, conn)) > 0) { - poll_sync_socket (conn->sock, tv_to_msec (&conn->tv), POLL_OUT); - } - - if (r == -1) { - return KVSTORAGE_ERROR_INTERNAL_ERROR; - } - /* Now read reply and try to parse line */ - buf->len = MAX_KV_LINE; - buf->pos = 0; - while ((r = rspamd_kvstorage_buf_readline (buf, conn)) == EAGAIN) { - poll_sync_socket (conn->sock, tv_to_msec (&conn->tv), POLL_IN); - } - /* A line was read */ - if (r == 0) { - if ((r = rspamd_kvstorage_parse_get_line (buf, len, &flags)) != KVSTORAGE_ERROR_OK) { - return r; - } - rspamd_kvstorage_buf_drainline (buf); - /* Now allocate and read the data */ - databuf = rspamd_kvstorage_buf_create (*len, conn->pool); - memcpy (databuf->data, buf->data, buf->pos); - while ((r = rspamd_kvstorage_buf_readall (databuf, conn)) > 0) { - poll_sync_socket (conn->sock, tv_to_msec (&conn->tv), POLL_IN); - } - if (r == -1) { - return KVSTORAGE_ERROR_INTERNAL_ERROR; - } - /* Now we have data inside buffer, read the last line */ - buf->pos = 0; - while ((r = rspamd_kvstorage_buf_readline (buf, conn)) == EAGAIN) { - poll_sync_socket (conn->sock, tv_to_msec (&conn->tv), POLL_IN); - } - *value = (gpointer)buf->data; - } - - - return KVSTORAGE_ERROR_OK; -} - -/** - * Write key synced - * @param conn connection structure - * @param key key to set - * @param value data to write - */ -enum rspamd_kvstorage_error -rspamd_kvstorage_set_sync (struct rspamd_kvstorage_connection *conn, - const gpointer key, guint keylen, const gpointer value, gsize len, guint expire) -{ - struct kvstorage_buf *buf; - gint r, buflen; - - if (conn == NULL || conn->state != KV_STATE_CONNECTED) { - return KVSTORAGE_ERROR_INTERNAL_ERROR; - } - - /* Create buf */ - buflen = len + keylen + sizeof ("set 4294967296 4294967296 4294967296" CRLF); - buf = rspamd_kvstorage_buf_create (buflen, conn->pool); - - r = rspamd_snprintf (buf->data, buf->len, "set %*s %ud %ud %ud" CRLF "%*s", - keylen, key, 0, expire, len, len, value); - buf->len = r; - while ((r = rspamd_kvstorage_buf_writeall (buf, conn)) > 0) { - poll_sync_socket (conn->sock, tv_to_msec (&conn->tv), POLL_OUT); - } - if (r == -1) { - return KVSTORAGE_ERROR_INTERNAL_ERROR; - } - /* Now we can read reply */ - buf->pos = 0; - buf->len = buflen; - while ((r = rspamd_kvstorage_buf_readline (buf, conn)) == EAGAIN) { - poll_sync_socket (conn->sock, tv_to_msec (&conn->tv), POLL_IN); - } - - return rspamd_kvstorage_parse_reply_error (buf); -} - -/** - * Delete key synced - * @param conn connection structure - * @param key key to delete - */ -enum rspamd_kvstorage_error -rspamd_kvstorage_delete_sync (struct rspamd_kvstorage_connection *conn, - const gpointer key, guint keylen) -{ - struct kvstorage_buf *buf; - gint r, buflen; - - if (conn == NULL || conn->state != KV_STATE_CONNECTED) { - return KVSTORAGE_ERROR_INTERNAL_ERROR; - } - - /* Create buf */ - buflen = MAX (keylen + sizeof ("delete " CRLF), MAX_KV_LINE); - buf = rspamd_kvstorage_buf_create (buflen, conn->pool); - - r = rspamd_snprintf (buf->data, buf->len, "delete %*s" CRLF, - keylen, key); - buf->len = r; - while ((r = rspamd_kvstorage_buf_writeall (buf, conn)) > 0) { - poll_sync_socket (conn->sock, tv_to_msec (&conn->tv), POLL_OUT); - } - if (r == -1) { - return KVSTORAGE_ERROR_INTERNAL_ERROR; - } - /* Now we can read reply */ - buf->len = buflen; - buf->pos = 0; - while ((r = rspamd_kvstorage_buf_readline (buf, conn)) == EAGAIN) { - poll_sync_socket (conn->sock, tv_to_msec (&conn->tv), POLL_IN); - } - - return rspamd_kvstorage_parse_reply_error (buf); -} - -/** - * Close connection - * @param conn connection structure - */ -enum rspamd_kvstorage_error -rspamd_kvstorage_close_sync (struct rspamd_kvstorage_connection *conn) -{ - close (conn->sock); - memory_pool_delete (conn->pool); - g_free (conn); - - return KVSTORAGE_ERROR_OK; -} - -const gchar* -rspamd_kvstorage_strerror (enum rspamd_kvstorage_error err) -{ - switch (err) { - case KVSTORAGE_ERROR_OK: - return "operation completed"; - case KVSTORAGE_ERROR_TIMEOUT: - return "operation timeout"; - case KVSTORAGE_ERROR_NOT_FOUND: - return "key not found"; - case KVSTORAGE_ERROR_NOT_STORED: - return "key not stored"; - case KVSTORAGE_ERROR_EXISTS: - return "key exists"; - case KVSTORAGE_ERROR_SERVER_ERROR: - return "server error"; - case KVSTORAGE_ERROR_CLIENT_ERROR: - return "client error"; - case KVSTORAGE_ERROR_INTERNAL_ERROR: - return "library error"; - } - - /* Not reached */ - return "unknown error"; -} diff --git a/lib/kvstorage/libkvstorageclient.h b/lib/kvstorage/libkvstorageclient.h deleted file mode 100644 index 11145fd49..000000000 --- a/lib/kvstorage/libkvstorageclient.h +++ /dev/null @@ -1,158 +0,0 @@ -/* Copyright (c) 2010, Vsevolod Stakhov - * 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 ''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. - */ - - -#ifndef LIBKVSTORAGECLIENT_H_ -#define LIBKVSTORAGECLIENT_H_ - -#include -#include - -/* Errors */ -enum rspamd_kvstorage_error { - KVSTORAGE_ERROR_OK = 0, - KVSTORAGE_ERROR_TIMEOUT, - KVSTORAGE_ERROR_NOT_FOUND, - KVSTORAGE_ERROR_NOT_STORED, - KVSTORAGE_ERROR_EXISTS, - KVSTORAGE_ERROR_SERVER_ERROR, - KVSTORAGE_ERROR_CLIENT_ERROR, - KVSTORAGE_ERROR_INTERNAL_ERROR -}; - -/* Forwarded definition */ -struct rspamd_kvstorage_connection; - -/* Callbacks for async API */ -typedef void (*kvstorage_connect_cb) (enum rspamd_kvstorage_error code, - struct rspamd_kvstorage_connection *conn, gpointer user_data); -typedef void (*kvstorage_read_cb) (enum rspamd_kvstorage_error code, const gpointer key, guint keylen, - const gpointer value, gsize datalen, struct rspamd_kvstorage_connection *conn, - gpointer user_data); -typedef void (*kvstorage_write_cb) (enum rspamd_kvstorage_error code, const gpointer key, guint keylen, - struct rspamd_kvstorage_connection *conn, - gpointer user_data); - -/* Asynced API */ - -/** - * Create async connection with rspamd - * @param host hostname, ip or unix socket for a server - * @param port port number in host byte order - * @param tv timeout for operations - * @param cb callback - * @param ud user data for callback - * @param conn target connection - */ -enum rspamd_kvstorage_error rspamd_kvstorage_connect_async (const gchar *host, - guint16 port, struct timeval *tv, kvstorage_connect_cb cb, gpointer ud, - struct rspamd_kvstorage_connection **conn); - -/** - * Read key asynced - * @param conn connection structure - * @param key key to read - * @param cb callback - * @param ud user data for callback - */ -enum rspamd_kvstorage_error rspamd_kvstorage_get_async (struct rspamd_kvstorage_connection *conn, - const gpointer key, guint keylen, kvstorage_read_cb cb, gpointer ud); - -/** - * Write key asynced - * @param conn connection structure - * @param key key to set - * @param value data to write - * @param cb callback - * @param ud user data for callback - */ -enum rspamd_kvstorage_error rspamd_kvstorage_set_async (struct rspamd_kvstorage_connection *conn, - const gpointer key, guint keylen, const gpointer value, gsize len, guint expire, kvstorage_write_cb cb, gpointer ud); - -/** - * Delete key asynced - * @param conn connection structure - * @param key key to delete - * @param cb callback - * @param ud user data for callback - */ -enum rspamd_kvstorage_error rspamd_kvstorage_delete_async (struct rspamd_kvstorage_connection *conn, - const gpointer key, guint keylen, kvstorage_write_cb cb, gpointer ud); - -/** - * Close connection - * @param conn connection structure - */ -enum rspamd_kvstorage_error rspamd_kvstorage_close_async (struct rspamd_kvstorage_connection *conn); - -/* Synced API */ -/** - * Create sync connection with rspamd - * @param host hostname, ip or unix socket for a server - * @param port port number in host byte order - * @param tv timeout for operations - * @param conn target connection - */ -enum rspamd_kvstorage_error rspamd_kvstorage_connect_sync (const gchar *host, - guint16 port, struct timeval *tv, - struct rspamd_kvstorage_connection **conn); - -/** - * Read key synced - * @param conn connection structure - * @param key key to read - * @param value value readed - */ -enum rspamd_kvstorage_error rspamd_kvstorage_get_sync (struct rspamd_kvstorage_connection *conn, - const gpointer key, guint keylen, gpointer **value, guint *len); - -/** - * Write key synced - * @param conn connection structure - * @param key key to set - * @param value data to write - */ -enum rspamd_kvstorage_error rspamd_kvstorage_set_sync (struct rspamd_kvstorage_connection *conn, - const gpointer key, guint keylen, const gpointer value, gsize len, guint expire); - -/** - * Delete key synced - * @param conn connection structure - * @param key key to delete - */ -enum rspamd_kvstorage_error rspamd_kvstorage_delete_sync (struct rspamd_kvstorage_connection *conn, - const gpointer key, guint keylen); - -/** - * Close connection - * @param conn connection structure - */ -enum rspamd_kvstorage_error rspamd_kvstorage_close_sync (struct rspamd_kvstorage_connection *conn); - -/** - * Convert error code to string - * @param err error code to be converted - */ -const gchar* rspamd_kvstorage_strerror (enum rspamd_kvstorage_error err); - -#endif /* LIBKVSTORAGECLIENT_H_ */ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 000000000..4e24448c3 --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,146 @@ +# Librspamd-util +SET(LIBRSPAMDUTILSRC aio_event.c + bloom.c + diff.c + fstring.c + fuzzy.c + hash.c + http.c + logger.c + map.c + memcached.c + mem_pool.c + printf.c + radix.c + rrd.c + trie.c + upstream.c + util.c) + +# Librspamdserver +SET(LIBRSPAMDSERVERSRC + binlog.c + buffer.c + cfg_utils.c + cfg_rcl.c + cfg_xml.c + dkim.c + dns.c + dynamic_cfg.c + events.c + html.c + proxy.c + roll_history.c + settings.c + spf.c + statfile.c + statfile_sync.c + symbols_cache.c + url.c + view.c) + +# Librspamd mime +SET(LIBRSPAMDMIMESRC + expressions.c + filter.c + images.c + message.c + protocol.c + smtp_utils.c + smtp_proto.c + worker_util.c) + +SET(TOKENIZERSSRC tokenizers/tokenizers.c + tokenizers/osb.c) + +SET(CLASSIFIERSSRC classifiers/classifiers.c + classifiers/bayes.c + classifiers/winnow.c) +# Add targets + +# Rspamdutil +ADD_LIBRARY(rspamd-util ${LINK_TYPE} ${LIBRSPAMDUTILSRC}) +IF(CMAKE_COMPILER_IS_GNUCC) +SET_TARGET_PROPERTIES(rspamd-util PROPERTIES COMPILE_FLAGS "-fno-strict-aliasing") +ENDIF(CMAKE_COMPILER_IS_GNUCC) + +TARGET_LINK_LIBRARIES(rspamd-util ${RSPAMD_REQUIRED_LIBRARIES}) +TARGET_LINK_LIBRARIES(rspamd-util pcre) +TARGET_LINK_LIBRARIES(rspamd-util rspamd-ucl) +TARGET_LINK_LIBRARIES(rspamd-util rspamd-http-parser) +TARGET_LINK_LIBRARIES(rspamd-util event) + +IF(NOT DEBIAN_BUILD) +SET_TARGET_PROPERTIES(rspamd-util PROPERTIES VERSION ${RSPAMD_VERSION}) +ENDIF(NOT DEBIAN_BUILD) + +IF(GLIB_COMPAT) + INCLUDE_DIRECTORIES("${CMAKE_CURRENT_SOURCE_DIR}/contrib/lgpl") + TARGET_LINK_LIBRARIES(rspamd-util glibadditions) +ENDIF(GLIB_COMPAT) + +IF(NO_SHARED MATCHES "OFF") + INSTALL(TARGETS rspamd-util + LIBRARY DESTINATION ${LIBDIR} + PUBLIC_HEADER DESTINATION include) +ENDIF(NO_SHARED MATCHES "OFF") + +# Librspamd-server + +#IF(WITH_DB) +# LIST(APPEND LIBRSPAMDSERVERSRC kvstorage_bdb.c) +#ENDIF(WITH_DB) +#IF(WITH_SQLITE) +# LIST(APPEND LIBRSPAMDSERVERSRC kvstorage_sqlite.c) +#ENDIF(WITH_SQLITE) + +ADD_LIBRARY(rspamd-server ${LINK_TYPE} ${LIBRSPAMDSERVERSRC} ${TOKENIZERSSRC} ${CLASSIFIERSSRC}) +IF(NOT DEBIAN_BUILD) +SET_TARGET_PROPERTIES(rspamd-server PROPERTIES VERSION ${RSPAMD_VERSION}) +ENDIF(NOT DEBIAN_BUILD) +SET_TARGET_PROPERTIES(rspamd-server PROPERTIES LINKER_LANGUAGE C COMPILE_FLAGS "-DRSPAMD_LIB") +TARGET_LINK_LIBRARIES(rspamd-server rspamd-lua) +TARGET_LINK_LIBRARIES(rspamd-server rspamd-json) +TARGET_LINK_LIBRARIES(rspamd-server rspamd-cdb) +TARGET_LINK_LIBRARIES(rspamd-server rspamd-util) +IF(LIBJUDY_LIBRARY) + TARGET_LINK_LIBRARIES(rspamd-server Judy) +ENDIF(LIBJUDY_LIBRARY) +IF(CMAKE_COMPILER_IS_GNUCC) +SET_TARGET_PROPERTIES(rspamd-server PROPERTIES COMPILE_FLAGS "-DRSPAMD_LIB -fno-strict-aliasing") +ENDIF(CMAKE_COMPILER_IS_GNUCC) + +IF(WITH_DB) + TARGET_LINK_LIBRARIES(rspamd-server db) +ENDIF(WITH_DB) + +IF(OPENSSL_FOUND) + TARGET_LINK_LIBRARIES(rspamd-server ${OPENSSL_LIBRARIES}) +ENDIF(OPENSSL_FOUND) + +IF(NO_SHARED MATCHES "OFF") + INSTALL(TARGETS rspamd-server + LIBRARY DESTINATION ${LIBDIR} + PUBLIC_HEADER DESTINATION ${INCLUDEDIR}) +ENDIF(NO_SHARED MATCHES "OFF") + +# Librspamdmime +ADD_LIBRARY(rspamd-mime ${LINK_TYPE} ${LIBRSPAMDMIMESRC}) +IF(NOT DEBIAN_BUILD) +SET_TARGET_PROPERTIES(rspamd-mime PROPERTIES VERSION ${RSPAMD_VERSION}) +ENDIF(NOT DEBIAN_BUILD) +SET_TARGET_PROPERTIES(rspamd-mime PROPERTIES LINKER_LANGUAGE C) +SET_TARGET_PROPERTIES(rspamd-mime PROPERTIES COMPILE_FLAGS "-DRSPAMD_LIB") +TARGET_LINK_LIBRARIES(rspamd-mime rspamd-server) +TARGET_LINK_LIBRARIES(rspamd-mime rspamd-util) +IF(CMAKE_COMPILER_IS_GNUCC) +SET_TARGET_PROPERTIES(rspamd-mime PROPERTIES COMPILE_FLAGS "-DRSPAMD_LIB -fno-strict-aliasing") +ENDIF(CMAKE_COMPILER_IS_GNUCC) + +IF(NO_SHARED MATCHES "OFF") + INSTALL(TARGETS rspamd-mime + LIBRARY DESTINATION ${LIBDIR} + PUBLIC_HEADER DESTINATION ${INCLUDEDIR}) +ENDIF(NO_SHARED MATCHES "OFF") + +INCLUDE_DIRECTORIES("${CMAKE_CURRENT_SOURCE_DIR}/src") \ No newline at end of file diff --git a/src/client/CMakeLists.txt b/src/client/CMakeLists.txt index 1d48a202f..90936f037 100644 --- a/src/client/CMakeLists.txt +++ b/src/client/CMakeLists.txt @@ -1,3 +1,26 @@ +# Librspamdclient +SET(LIBRSPAMDCLIENTSRC rspamdclient.c) + +ADD_LIBRARY(rspamdclient SHARED ${LIBRSPAMDCLIENTSRC}) +IF(CMAKE_COMPILER_IS_GNUCC) + SET_TARGET_PROPERTIES(rspamdclient PROPERTIES COMPILE_FLAGS "-fno-strict-aliasing") +ENDIF(CMAKE_COMPILER_IS_GNUCC) + +TARGET_LINK_LIBRARIES(rspamdclient rspamd-util) +TARGET_LINK_LIBRARIES(rspamdclient ${RSPAMD_REQUIRED_LIBRARIES}) + +IF(GLIB_COMPAT) + INCLUDE_DIRECTORIES("${CMAKE_CURRENT_SOURCE_DIR}/contrib/lgpl") + TARGET_LINK_LIBRARIES(rspamdclient glibadditions) +ENDIF(GLIB_COMPAT) + +IF(NO_SHARED MATCHES "OFF") + INSTALL(TARGETS rspamdclient LIBRARY PUBLIC_HEADER + LIBRARY DESTINATION ${LIBDIR} + PUBLIC_HEADER DESTINATION ${INCLUDEDIR} + ARCHIVE DESTINATION ${LIBDIR}) +ENDIF(NO_SHARED MATCHES "OFF") + # rspamc SET(RSPAMCSRC rspamc.c) diff --git a/src/client/rspamdclient.c b/src/client/rspamdclient.c new file mode 100644 index 000000000..126ddcd1b --- /dev/null +++ b/src/client/rspamdclient.c @@ -0,0 +1,23 @@ +/* Copyright (c) 2014, Vsevolod Stakhov + * 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 ''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 AUTHOR 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. + */ + diff --git a/src/client/rspamdclient.h b/src/client/rspamdclient.h new file mode 100644 index 000000000..90a4c1c27 --- /dev/null +++ b/src/client/rspamdclient.h @@ -0,0 +1,32 @@ +/* Copyright (c) 2014, Vsevolod Stakhov + * 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 ''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 AUTHOR 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. + */ + +#ifndef RSPAMDCLIENT_H_ +#define RSPAMDCLIENT_H_ + +#include "config.h" +#include "ucl.h" + + + +#endif /* RSPAMDCLIENT_H_ */ -- 2.39.5