From c0864168aa88ca21c09a45b5ea13352262f99bc4 Mon Sep 17 00:00:00 2001 From: Vsevolod Stakhov Date: Tue, 20 Oct 2015 10:10:35 +0100 Subject: [PATCH] Add a simple http server for benchmarks --- CMakeLists.txt | 9 +- utils/CMakeLists.txt | 22 +++ utils/rspamd_http_bench.c | 42 ++++++ utils/rspamd_http_server.c | 289 +++++++++++++++++++++++++++++++++++++ 4 files changed, 354 insertions(+), 8 deletions(-) create mode 100644 utils/CMakeLists.txt create mode 100644 utils/rspamd_http_bench.c create mode 100644 utils/rspamd_http_server.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 5eeb707dd..9d9dbf7e9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1012,8 +1012,8 @@ ADD_SUBDIRECTORY(contrib/libucl) ADD_SUBDIRECTORY(contrib/librdns) ADD_SUBDIRECTORY(contrib/aho-corasick) ADD_SUBDIRECTORY(src) - ADD_SUBDIRECTORY(test) +ADD_SUBDIRECTORY(utils) ############################ TARGETS SECTION ############################### @@ -1079,13 +1079,6 @@ INSTALL(FILES "contrib/lua-fun/fun.lua" DESTINATION ${PLUGINSDIR}/lua) INSTALL(FILES "contrib/publicsuffix/effective_tld_names.dat" DESTINATION "${PLUGINSDIR}") -# Redirector -IF(ENABLE_REDIRECTOR MATCHES "ON") - CONFIGURE_FILE(utils/redirector.pl.in utils/redirector.pl @ONLY) - INSTALL(PROGRAMS "${CMAKE_CURRENT_BINARY_DIR}/utils/redirector.pl" - DESTINATION bin RENAME rspamd-redirector) -ENDIF(ENABLE_REDIRECTOR MATCHES "ON") - # Lua config FILE(GLOB_RECURSE LUA_CONFIGS RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}/rules" "${CMAKE_CURRENT_SOURCE_DIR}/rules/*.lua") diff --git a/utils/CMakeLists.txt b/utils/CMakeLists.txt new file mode 100644 index 000000000..9da564a32 --- /dev/null +++ b/utils/CMakeLists.txt @@ -0,0 +1,22 @@ +SET(UTILSERVERSRC rspamd_http_server.c) +SET(UTILBENCHSRC rspamd_http_bench.c) + +ADD_EXECUTABLE(rspamd-http-server ${UTILSERVERSRC}) +SET_TARGET_PROPERTIES(rspamd-http-server PROPERTIES LINKER_LANGUAGE C) +TARGET_LINK_LIBRARIES(rspamd-http-server rspamd-server) + +TARGET_LINK_LIBRARIES(rspamd-http-server rspamd-http-parser) +TARGET_LINK_LIBRARIES(rspamd-http-server ${RSPAMD_REQUIRED_LIBRARIES}) + +ADD_EXECUTABLE(rspamd-http-bench ${UTILBENCHSRC}) +SET_TARGET_PROPERTIES(rspamd-http-server PROPERTIES LINKER_LANGUAGE C) +TARGET_LINK_LIBRARIES(rspamd-http-server rspamd-server) +TARGET_LINK_LIBRARIES(rspamd-http-server rspamd-http-parser) +TARGET_LINK_LIBRARIES(rspamd-http-server ${RSPAMD_REQUIRED_LIBRARIES}) + +# Redirector +IF (ENABLE_REDIRECTOR MATCHES "ON") + CONFIGURE_FILE(redirector.pl.in redirector.pl @ONLY) + INSTALL(PROGRAMS "${CMAKE_CURRENT_BINARY_DIR}/redirector.pl" + DESTINATION bin RENAME rspamd-redirector) +ENDIF (ENABLE_REDIRECTOR MATCHES "ON") \ No newline at end of file diff --git a/utils/rspamd_http_bench.c b/utils/rspamd_http_bench.c new file mode 100644 index 000000000..1e5c3873a --- /dev/null +++ b/utils/rspamd_http_bench.c @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2015, 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 BY AUTHOR ''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 "rspamd.h" +#include "util.h" +#include "http.h" +#include "ottery.h" +#include "cryptobox.h" +#include "unix-std.h" +#include + +#ifdef HAVE_SYS_WAIT_H +#include +#endif + +int +main (int argc, char **argv) +{ + return 1; +} diff --git a/utils/rspamd_http_server.c b/utils/rspamd_http_server.c new file mode 100644 index 000000000..eb6b8fcba --- /dev/null +++ b/utils/rspamd_http_server.c @@ -0,0 +1,289 @@ +/* + * Copyright (c) 2015, 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 BY AUTHOR ''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 "rspamd.h" +#include "util.h" +#include "http.h" +#include "ottery.h" +#include "cryptobox.h" +#include "unix-std.h" +#include + +#ifdef HAVE_SYS_WAIT_H +#include +#endif + +static guint port = 43000; +static guint cache_size = 10; +static guint nworkers = 1; +static gboolean openssl_mode = FALSE; +static GHashTable *maps = NULL; +static struct rspamd_keypair_cache *c; +static gpointer server_key; +static struct timeval io_tv = { + .tv_sec = 5, + .tv_usec = 0 +}; + +static GOptionEntry entries[] = { + {"port", 'p', 0, G_OPTION_ARG_INT, &port, + "Port number (default: 43000)", NULL}, + {"cache", 'c', 0, G_OPTION_ARG_INT, &cache_size, + "Keys cache size (default: 10)", NULL}, + {"workers", 'n', 0, G_OPTION_ARG_INT, &nworkers, + "Number of workers to start (default: 1)", NULL}, + {"openssl", 'o', 0, G_OPTION_ARG_NONE, &openssl_mode, + "Use openssl crypto", NULL}, + {NULL, 0, 0, G_OPTION_ARG_NONE, NULL, NULL, NULL} +}; + +struct rspamd_http_server_session { + struct rspamd_http_connection *conn; + struct event_base *ev_base; + guint req_size; + gboolean reply; + gint fd; +}; + +static void +rspamd_server_error (struct rspamd_http_connection *conn, + GError *err) +{ + msg_err ("http error occurred: %s", err->message); + g_assert (0); +} + +static int +rspamd_server_finish (struct rspamd_http_connection *conn, + struct rspamd_http_message *msg) +{ + struct rspamd_http_server_session *session = conn->ud; + struct rspamd_http_message *reply; + gulong size; + const gchar *url_str; + guint url_len; + + if (!session->reply) { + session->reply = TRUE; + reply = rspamd_http_new_message (HTTP_RESPONSE); + url_str = msg->url->str; + url_len = msg->url->len; + + if (url_str[0] == '/') { + url_str ++; + url_len --; + } + + if (rspamd_strtoul (url_str, url_len, &size)) { + session->req_size = size; + + reply->code = 200; + reply->status = rspamd_fstring_new_init ("OK", 2); + reply->body = rspamd_fstring_sized_new (size); + memset (reply->body->str, 0, size); + } + else { + reply->code = 404; + reply->status = rspamd_fstring_new_init ("Not found", 9); + } + + rspamd_http_connection_reset (conn); + rspamd_http_connection_write_message (conn, reply, NULL, + "application/octet-stream", session, session->fd, + &io_tv, session->ev_base); + } + else { + /* Destroy session */ + rspamd_http_connection_unref (conn); + close (session->fd); + g_slice_free1 (sizeof (*session), session); + } + + return 0; +} + +static void +rspamd_server_accept (gint fd, short what, void *arg) +{ + struct event_base *ev_base = arg; + struct rspamd_http_server_session *session; + rspamd_inet_addr_t *addr; + gint nfd; + + if ((nfd = + rspamd_accept_from_socket (fd, &addr)) == -1) { + msg_warn ("accept failed: %s", strerror (errno)); + return; + } + /* Check for EAGAIN */ + if (nfd == 0) { + return; + } + + rspamd_inet_address_destroy (addr); + session = g_slice_alloc (sizeof (*session)); + session->conn = rspamd_http_connection_new (NULL, rspamd_server_error, + rspamd_server_finish, 0, RSPAMD_HTTP_SERVER, c); + rspamd_http_connection_set_key (session->conn, server_key); + rspamd_http_connection_read_message (session->conn, session, nfd, &io_tv, + ev_base); + session->reply = FALSE; + session->fd = nfd; + session->ev_base = ev_base; +} + +static void +rspamd_http_term_handler (gint fd, short what, void *arg) +{ + struct event_base *ev_base = arg; + struct timeval tv = {0, 0}; + + event_base_loopexit (ev_base, &tv); +} + +static void +rspamd_http_server_func (gint fd, rspamd_inet_addr_t *addr) +{ + struct event_base *ev_base = event_init (); + struct event accept_ev, term_ev; + + event_set (&accept_ev, fd, EV_READ | EV_PERSIST, rspamd_server_accept, ev_base); + event_base_set (ev_base, &accept_ev); + event_add (&accept_ev, NULL); + + evsignal_set (&term_ev, SIGTERM, rspamd_http_term_handler, ev_base); + event_base_set (ev_base, &term_ev); + event_add (&term_ev, NULL); + + event_base_loop (ev_base, 0); +} + +static void +rspamd_http_start_servers (pid_t *sfd, rspamd_inet_addr_t *addr) +{ + guint i; + gint fd; + + g_assert ( + (fd = rspamd_inet_address_listen (addr, SOCK_STREAM, TRUE)) != -1); + + for (i = 0; i < nworkers; i++) { + sfd[i] = fork (); + g_assert (sfd[i] != -1); + + if (sfd[i] == 0) { + gperf_profiler_init (NULL, "http-server"); + rspamd_http_server_func (fd, addr); + gperf_profiler_stop (); + exit (EXIT_SUCCESS); + } + } + + close (fd); +} + +static void +rspamd_http_stop_servers (pid_t *sfd) +{ + guint i; + gint res; + + for (i = 0; i < nworkers; i++) { + kill (sfd[i], SIGTERM); + wait (&res); + } +} + +static void +rspamd_http_server_term (int fd, short what, void *arg) +{ + pid_t *sfd = arg; + + rspamd_http_stop_servers (sfd); +} + +int +main (int argc, gchar **argv) +{ + GOptionContext *context; + GError *error = NULL; + struct event_base *ev_base; + GString *b32_key; + pid_t *sfd; + rspamd_inet_addr_t *addr; + struct event term_ev, int_ev; + struct in_addr ina = {INADDR_ANY}; + + rspamd_init_libs (); + + context = g_option_context_new ( + "rspamd_http_server - test server for benchmarks"); + g_option_context_set_summary (context, + "Summary:\n Rspamd test HTTP server " + RVERSION + "\n Release id: " + RID); + g_option_context_add_main_entries (context, entries, NULL); + + if (!g_option_context_parse (context, &argc, &argv, &error)) { + rspamd_fprintf (stderr, "option parsing failed: %s\n", error->message); + g_error_free (error); + exit (1); + } + + maps = g_hash_table_new (g_int_hash, g_int_equal); + + if (openssl_mode) { + g_assert (rspamd_cryptobox_openssl_mode (TRUE)); + } + + server_key = rspamd_http_connection_gen_key (); + b32_key = rspamd_http_connection_print_key (server_key, + RSPAMD_KEYPAIR_PUBKEY | RSPAMD_KEYPAIR_BASE32); + rspamd_printf ("key: %v\n", b32_key); + + if (cache_size > 0) { + c = rspamd_keypair_cache_new (cache_size); + } + + sfd = g_alloca (sizeof (*sfd) * nworkers); + addr = rspamd_inet_address_new (AF_INET, &ina); + rspamd_inet_address_set_port (addr, port); + rspamd_http_start_servers (sfd, addr); + + /* Just wait for workers */ + ev_base = event_init (); + + event_set (&term_ev, SIGTERM, EV_SIGNAL, rspamd_http_server_term, sfd); + event_base_set (ev_base, &term_ev); + event_add (&term_ev, NULL); + event_set (&int_ev, SIGINT, EV_SIGNAL, rspamd_http_server_term, sfd); + event_base_set (ev_base, &int_ev); + event_add (&int_ev, NULL); + + event_base_loop (ev_base, 0); + + return 0; +} -- 2.39.5