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)
+++ /dev/null
-# 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
+++ /dev/null
-/*
- * 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: <name>; <True|False|Skip>; <score> / <required_score>[ / <reject_score>]
- */
-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: <name>[(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: <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: <value>
- */
-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);
-}
+++ /dev/null
-#ifndef LIBRSPAMD_CLIENT_H
-#define LIBRSPAMD_CLIENT_H
-
-#include <glib.h>
-
-/**
- * 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
+++ /dev/null
-/* 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";
-}
+++ /dev/null
-/* 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 <glib.h>
-#include <sys/time.h>
-
-/* 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_ */
--- /dev/null
+# 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
+# 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)
--- /dev/null
+/* 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.
+ */
+
--- /dev/null
+/* 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_ */