diff --git a/src/libcharon/plugins/load_tester/Makefile.am b/src/libcharon/plugins/load_tester/Makefile.am index cdd0445a9..0069fb5ab 100644 --- a/src/libcharon/plugins/load_tester/Makefile.am +++ b/src/libcharon/plugins/load_tester/Makefile.am @@ -2,7 +2,8 @@ INCLUDES = -I$(top_srcdir)/src/libstrongswan -I$(top_srcdir)/src/libhydra \ -I$(top_srcdir)/src/libcharon -AM_CFLAGS = -rdynamic +AM_CFLAGS = -rdynamic \ + -DIPSEC_PIDDIR=\"${piddir}\" if MONOLITHIC noinst_LTLIBRARIES = libstrongswan-load-tester.la @@ -16,6 +17,7 @@ libstrongswan_load_tester_la_SOURCES = \ load_tester_creds.c load_tester_creds.h \ load_tester_ipsec.c load_tester_ipsec.h \ load_tester_listener.c load_tester_listener.h \ + load_tester_control.c load_tester_control.h \ load_tester_diffie_hellman.c load_tester_diffie_hellman.h libstrongswan_load_tester_la_LDFLAGS = -module -avoid-version diff --git a/src/libcharon/plugins/load_tester/load_tester_control.c b/src/libcharon/plugins/load_tester/load_tester_control.c new file mode 100644 index 000000000..114233d57 --- /dev/null +++ b/src/libcharon/plugins/load_tester/load_tester_control.c @@ -0,0 +1,213 @@ +/* + * Copyright (C) 2012 Martin Willi + * Copyright (C) 2012 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "load_tester_control.h" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +typedef struct private_load_tester_control_t private_load_tester_control_t; + +/** + * Private data of an load_tester_control_t object. + */ +struct private_load_tester_control_t { + + /** + * Public load_tester_control_t interface. + */ + load_tester_control_t public; + + /** + * Load tester unix socket file descriptor + */ + int socket; +}; + +/** + * Open load-tester listening socket + */ +static bool open_socket(private_load_tester_control_t *this) +{ + struct sockaddr_un addr; + mode_t old; + + addr.sun_family = AF_UNIX; + strcpy(addr.sun_path, LOAD_TESTER_SOCKET); + + this->socket = socket(AF_UNIX, SOCK_SEQPACKET, 0); + if (this->socket == -1) + { + DBG1(DBG_CFG, "creating load-tester socket failed"); + return FALSE; + } + unlink(addr.sun_path); + old = umask(~(S_IRWXU | S_IRWXG)); + if (bind(this->socket, (struct sockaddr*)&addr, sizeof(addr)) < 0) + { + DBG1(DBG_CFG, "binding load-tester socket failed: %s", strerror(errno)); + close(this->socket); + return FALSE; + } + umask(old); + if (chown(addr.sun_path, charon->caps->get_uid(charon->caps), + charon->caps->get_gid(charon->caps)) != 0) + { + DBG1(DBG_CFG, "changing load-tester socket permissions failed: %s", + strerror(errno)); + } + if (listen(this->socket, 10) < 0) + { + DBG1(DBG_CFG, "listening on load-tester socket failed: %s", strerror(errno)); + close(this->socket); + unlink(addr.sun_path); + return FALSE; + } + return TRUE; +} + +/** + * Initiate load-test, write progress to stream + */ +static job_requeue_t initiate(FILE *stream) +{ + enumerator_t *enumerator; + peer_cfg_t *peer_cfg; + child_cfg_t *child_cfg; + u_int i, count; + char buf[16] = ""; + + fflush(stream); + if (fgets(buf, sizeof(buf), stream) == NULL) + { + return JOB_REQUEUE_NONE; + } + if (sscanf(buf, "%u", &count) != 1) + { + return JOB_REQUEUE_NONE; + } + + peer_cfg = charon->backends->get_peer_cfg_by_name(charon->backends, + "load-test"); + if (!peer_cfg) + { + return JOB_REQUEUE_NONE; + } + enumerator = peer_cfg->create_child_cfg_enumerator(peer_cfg); + if (!enumerator->enumerate(enumerator, &child_cfg)) + { + enumerator->destroy(enumerator); + return JOB_REQUEUE_NONE; + } + enumerator->destroy(enumerator); + + for (i = 0; i < count; i++) + { + if (charon->controller->initiate(charon->controller, + peer_cfg->get_ref(peer_cfg), + child_cfg->get_ref(child_cfg), + controller_cb_empty, NULL, 0) == SUCCESS) + { + fprintf(stream, "."); + } + else + { + fprintf(stream, "!"); + } + fflush(stream); + } + peer_cfg->destroy(peer_cfg); + fprintf(stream, "\n"); + + return JOB_REQUEUE_NONE; +} + +/** + * Accept load-tester control connections, dispatch + */ +static job_requeue_t receive(private_load_tester_control_t *this) +{ + struct sockaddr_un addr; + int fd, len = sizeof(addr); + bool oldstate; + FILE *stream; + + oldstate = thread_cancelability(TRUE); + fd = accept(this->socket, (struct sockaddr*)&addr, &len); + thread_cancelability(oldstate); + + if (fd != -1) + { + stream = fdopen(fd, "r+"); + if (stream) + { + DBG1(DBG_CFG, "client connected"); + lib->processor->queue_job(lib->processor, + (job_t*)callback_job_create_with_prio( + (callback_job_cb_t)initiate, stream, (void*)fclose, + (callback_job_cancel_t)return_false, JOB_PRIO_CRITICAL)); + } + else + { + close(fd); + } + } + return JOB_REQUEUE_FAIR; +} + +METHOD(load_tester_control_t, destroy, void, + private_load_tester_control_t *this) +{ + if (this->socket != -1) + { + close(this->socket); + } + free(this); +} + +/** + * See header + */ +load_tester_control_t *load_tester_control_create() +{ + private_load_tester_control_t *this; + + INIT(this, + .public = { + .destroy = _destroy, + }, + ); + + if (open_socket(this)) + { + lib->processor->queue_job(lib->processor, (job_t*) + callback_job_create_with_prio((callback_job_cb_t)receive, this, NULL, + (callback_job_cancel_t)return_false, JOB_PRIO_CRITICAL)); + } + else + { + this->socket = -1; + } + + return &this->public; +} diff --git a/src/libcharon/plugins/load_tester/load_tester_control.h b/src/libcharon/plugins/load_tester/load_tester_control.h new file mode 100644 index 000000000..5d280f0a0 --- /dev/null +++ b/src/libcharon/plugins/load_tester/load_tester_control.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2012 Martin Willi + * Copyright (C) 2012 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup load_tester_control load_tester_control + * @{ @ingroup load_tester + */ + +#ifndef LOAD_TESTER_CONTROL_H_ +#define LOAD_TESTER_CONTROL_H_ + +/** + * Socket to accept connections. + */ +#define LOAD_TESTER_SOCKET IPSEC_PIDDIR "/charon.ldt" + +typedef struct load_tester_control_t load_tester_control_t; + +/** + * Unix control socket to initiate batches of load-tests. + */ +struct load_tester_control_t { + + /** + * Destroy a load_tester_control_t. + */ + void (*destroy)(load_tester_control_t *this); +}; + +/** + * Create a load_tester_control instance. + */ +load_tester_control_t *load_tester_control_create(); + +#endif /** LOAD_TESTER_CONTROL_H_ @}*/ diff --git a/src/libcharon/plugins/load_tester/load_tester_plugin.c b/src/libcharon/plugins/load_tester/load_tester_plugin.c index 4a982d4b7..4f2bf05dc 100644 --- a/src/libcharon/plugins/load_tester/load_tester_plugin.c +++ b/src/libcharon/plugins/load_tester/load_tester_plugin.c @@ -18,6 +18,7 @@ #include "load_tester_creds.h" #include "load_tester_ipsec.h" #include "load_tester_listener.h" +#include "load_tester_control.h" #include "load_tester_diffie_hellman.h" #include @@ -50,6 +51,11 @@ struct private_load_tester_plugin_t { */ load_tester_creds_t *creds; + /** + * Unix control socket to initiate load-tests + */ + load_tester_control_t *control; + /** * event handler, listens on bus */ @@ -181,6 +187,7 @@ static bool register_load_tester(private_load_tester_plugin_t *this, this->config = load_tester_config_create(); this->creds = load_tester_creds_create(); + this->control = load_tester_control_create(); charon->backends->add_backend(charon->backends, &this->config->backend); lib->credmgr->add_set(lib->credmgr, &this->creds->credential_set); @@ -215,6 +222,7 @@ static bool register_load_tester(private_load_tester_plugin_t *this, this->config->destroy(this->config); this->creds->destroy(this->creds); this->listener->destroy(this->listener); + this->control->destroy(this->control); } return TRUE; }