summaryrefslogtreecommitdiffstats
path: root/utils
diff options
context:
space:
mode:
authorVsevolod Stakhov <vsevolod@highsecure.ru>2015-10-20 10:10:35 +0100
committerVsevolod Stakhov <vsevolod@highsecure.ru>2015-10-20 10:10:35 +0100
commitc0864168aa88ca21c09a45b5ea13352262f99bc4 (patch)
treed2290b20037645984848578d881833b47d783e36 /utils
parenta9c480ca19d2e050a0d7edd6d8e3a4f6817d23b5 (diff)
downloadrspamd-c0864168aa88ca21c09a45b5ea13352262f99bc4.tar.gz
rspamd-c0864168aa88ca21c09a45b5ea13352262f99bc4.zip
Add a simple http server for benchmarks
Diffstat (limited to 'utils')
-rw-r--r--utils/CMakeLists.txt22
-rw-r--r--utils/rspamd_http_bench.c42
-rw-r--r--utils/rspamd_http_server.c289
3 files changed, 353 insertions, 0 deletions
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 <math.h>
+
+#ifdef HAVE_SYS_WAIT_H
+#include <sys/wait.h>
+#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 <math.h>
+
+#ifdef HAVE_SYS_WAIT_H
+#include <sys/wait.h>
+#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;
+}