diff options
author | Othmar Gsenger <otti@anytun.org> | 2007-12-03 10:51:16 +0000 |
---|---|---|
committer | Othmar Gsenger <otti@anytun.org> | 2007-12-03 10:51:16 +0000 |
commit | fa4f4a8a50c4bab3a3e247fb7186a7f9a00dfc11 (patch) | |
tree | 5ff84c3c71e6d3dadbaf9e13d3fdd84ab2691ca6 /Sockets/tests/stressclient.cpp | |
parent | added ssl tools (diff) |
Added syncsocket
Diffstat (limited to 'Sockets/tests/stressclient.cpp')
-rw-r--r-- | Sockets/tests/stressclient.cpp | 516 |
1 files changed, 516 insertions, 0 deletions
diff --git a/Sockets/tests/stressclient.cpp b/Sockets/tests/stressclient.cpp new file mode 100644 index 0000000..4187868 --- /dev/null +++ b/Sockets/tests/stressclient.cpp @@ -0,0 +1,516 @@ +/** + ** \file stressclient.cpp + ** \date 2006-10-02 + ** \author grymse@alhem.net +**/ +/* +Copyright (C) 2006 Anders Hedstrom + +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. + +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. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ +#ifdef _WIN32 +#pragma warning(disable:4786) +#endif +#include <StdoutLog.h> +#include <ListenSocket.h> +#include <SocketHandler.h> +#include <TcpSocket.h> +#include <Utility.h> +#ifndef _WIN32 +#include <signal.h> +#include <stdint.h> +#else +typedef __int64 int64_t; +#endif +#include <HttpGetSocket.h> + + +static double g_min_time = 10000; +static double g_max_time = 0; +static double g_tot_time = 0; +static int g_ant = 0; +static double g_min_time2 = 10000; +static double g_max_time2 = 0; +static double g_tot_time2 = 0; +static int g_ant2 = 0; +static bool gQuit = false; +static size_t g_max_connections = 0; +static std::string gHost = "localhost"; +static port_t gPort = 2222; +static bool g_b_flood = false; +static bool g_b_off = false; +static bool g_b_limit = false; +static int64_t gBytesIn = 0; +static int64_t gBytesOut = 0; +static bool g_b_repeat = false; +static std::string g_data; +static size_t g_data_size = 1024; +static bool g_b_stop = false; +#ifdef HAVE_OPENSSL +static bool g_b_ssl = false; +#endif +static bool g_b_instant = false; +static struct timeval g_t_start; + + +/** + * Return time difference between two struct timeval's, in seconds + * \param t0 start time + * \param t end time + */ +double Diff(struct timeval t0,struct timeval t) +{ + t.tv_sec -= t0.tv_sec; + t.tv_usec -= t0.tv_usec; + if (t.tv_usec < 0) + { + t.tv_usec += 1000000; + t.tv_sec -= 1; + } + return t.tv_sec + (double)t.tv_usec / 1000000; +} + + +void gettime(struct timeval *p, struct timezone *) +{ +#ifdef _WIN32 + FILETIME ft; // Contains a 64-bit value representing the number of 100-nanosecond intervals since January 1, 1601 (UTC). + GetSystemTimeAsFileTime(&ft); + uint64_t tt; + memcpy(&tt, &ft, sizeof(tt)); + tt /= 10; + p->tv_sec = tt / 1000000; + p->tv_usec = tt % 1000000; +#else + gettimeofday(p, NULL); +#endif +} + + +void printreport() +{ + struct timeval tv; + gettime(&tv, NULL); + double rt = Diff(g_t_start, tv); + g_t_start = tv; + // + printf("\n"); + if (g_ant) + printf("connect; ant: %5d min: %.4f max: %.4f med: %.4f\n", g_ant, g_min_time, g_max_time, g_tot_time / g_ant); + if (g_ant2) + printf("reply; ant: %5d min: %.4f max: %.4f med: %.4f\n", g_ant2, g_min_time2, g_max_time2, g_tot_time2 / g_ant2); + double mbi = (double)gBytesIn / 1024; + mbi /= 1024; + mbi /= rt; + double mbo = (double)gBytesOut / 1024; + mbo /= 1024; + mbo /= rt; + printf("bytes in: %lld", gBytesIn); + printf(" (%.2f MB/sec)", mbi); + printf(" bytes out: %lld", gBytesOut); + printf(" (%.2f MB/sec)", mbo); + printf(" time: %.2f sec\n", rt); +} + + +void printreport_reset() +{ + printreport(); + // + g_min_time = 10000; + g_max_time = 0; + g_tot_time = 0; + g_ant = 0; + g_min_time2 = 10000; + g_max_time2 = 0; + g_tot_time2 = 0; + g_ant2 = 0; + gBytesIn = gBytesOut = 0; +} + + +class MySocket : public TcpSocket +{ +public: + MySocket(ISocketHandler& h,bool one) : TcpSocket(h), m_b_client(false), m_b_one(one), m_b_created(false), m_b_active(false) { + gettime(&m_create, NULL); + SetLineProtocol(); +#ifdef HAVE_OPENSSL + if (g_b_ssl) + EnableSSL(); +#endif + if (g_max_connections && !m_b_one && Handler().GetCount() >= g_max_connections) + { + fprintf(stderr, "\nConnection limit reached: %d, continuing in single connection stress mode\n", (int)g_max_connections); + if (g_b_off) + printreport_reset(); + g_b_limit = true; + m_b_one = true; + // + g_b_flood = g_b_repeat; + } + if (!m_b_one && Handler().GetCount() >= FD_SETSIZE - 17) + { + fprintf(stderr, "\nFD_SETSIZE connection limit reached: %d, continuing in single connection stress mode\n", (int)Handler().GetCount()); + if (g_b_off) + printreport_reset(); + g_b_limit = true; + m_b_one = true; + // + g_b_flood = g_b_repeat; + } + } + ~MySocket() { + } + + void OnConnect() { + gettime(&m_connect, NULL); + m_b_active = true; + { + double tconnect = Diff(m_create, m_connect); + // + g_min_time = tconnect < g_min_time ? tconnect : g_min_time; + g_max_time = tconnect > g_max_time ? tconnect : g_max_time; + g_tot_time += tconnect; + g_ant += 1; + } + SendBlock(); + m_b_client = true; + } + + void SendBlock() { + gettime(&m_send, NULL); + Send(g_data + "\n"); + } + + void OnLine(const std::string& line) { + gettime(&m_reply, NULL); + m_b_active = true; + { + double treply = Diff(m_send, m_reply); + // + g_min_time2 = treply < g_min_time2 ? treply : g_min_time2; + g_max_time2 = treply > g_max_time2 ? treply : g_max_time2; + g_tot_time2 += treply; + g_ant2 += 1; + } + // + if (line != g_data) + { + fprintf(stderr, "\n%s\n%s\n", line.c_str(), g_data.c_str()); + fprintf(stderr, "(reply did not match data - exiting)\n"); + exit(-1); + } + // + gBytesIn += GetBytesReceived(true); + gBytesOut += GetBytesSent(true); + if (m_b_one) + { + SetCloseAndDelete(); + } + else + if (g_b_repeat && g_b_limit) + { + SendBlock(); + } + // add another + if (!m_b_created && (!g_b_limit || !g_b_off) && !g_b_instant) + { + MySocket *p = new MySocket(Handler(), m_b_one); + p -> SetDeleteByHandler(); + p -> Open(gHost, gPort); + Handler().Add(p); + m_b_created = true; + } + } + + bool IsActive() { + bool b = m_b_active; + m_b_active = false; + return b; + } + +private: + bool m_b_client; + bool m_b_one; + bool m_b_created; + bool m_b_active; + struct timeval m_create; + struct timeval m_connect; + struct timeval m_send; + struct timeval m_reply; +}; + + +class MyHttpSocket : public HttpGetSocket +{ +public: + MyHttpSocket(ISocketHandler& h,const std::string& url) : HttpGetSocket(h,url), m_url(url) { + gettime(&m_create, NULL); + AddResponseHeader("content-length", Utility::l2string(g_data_size)); + } + ~MyHttpSocket() {} + + void OnConnect() { + gettime(&m_connect, NULL); + { + double tconnect = Diff(m_create, m_connect); + // + g_min_time = tconnect < g_min_time ? tconnect : g_min_time; + g_max_time = tconnect > g_max_time ? tconnect : g_max_time; + g_tot_time += tconnect; + g_ant += 1; + } + gettime(&m_send, NULL); + + // send request header + HttpGetSocket::OnConnect(); + + // send body + Send(g_data); + } + + void OnContent() { + gettime(&m_reply, NULL); + { + double treply = Diff(m_send, m_reply); + // + g_min_time2 = treply < g_min_time2 ? treply : g_min_time2; + g_max_time2 = treply > g_max_time2 ? treply : g_max_time2; + g_tot_time2 += treply; + g_ant2 += 1; + } + CreateNew(); + } + void CreateNew() { + if (g_b_off) + return; + MyHttpSocket *p = new MyHttpSocket(Handler(), m_url); + p -> SetDeleteByHandler(); + Handler().Add(p); + SetCloseAndDelete(); + } + +private: + std::string m_url; + struct timeval m_create; + struct timeval m_connect; + struct timeval m_send; + struct timeval m_reply; +}; + + +#ifndef _WIN32 +void sigint(int) +{ + printreport(); + gQuit = true; +} + + +void sigusr1(int) +{ + g_b_flood = true; +} + + +void sigusr2(int) +{ + printreport_reset(); +} +#endif + + +class MyHandler : public SocketHandler +{ +public: + MyHandler() : SocketHandler() { + } + MyHandler(StdoutLog *p) : SocketHandler(p) { + } + ~MyHandler() { + } + void Flood() { + for (socket_m::iterator it = m_sockets.begin(); it != m_sockets.end(); it++) + { + Socket *p0 = it -> second; + MySocket *p = dynamic_cast<MySocket *>(p0); + if (p) + { + p -> SendBlock(); + } + } + } + void Report() { + int ant = 0; + int act = 0; + for (socket_m::iterator it = m_sockets.begin(); it != m_sockets.end(); it++) + { + MySocket *p = dynamic_cast<MySocket *>(it -> second); + if (p) + { + ant++; + if (p -> IsActive()) + { + act++; + } + } + } + printf("Number of //stress// sockets: %d Active: %d\n", ant, act); + } +}; + + +int main(int argc,char *argv[]) +{ + bool many = false; + bool one = false; + bool enableLog = false; + bool http = false; + std::string url; + time_t report_period = 10; + for (int i = 1; i < argc; i++) + { + if (!strcmp(argv[i], "-many")) + many = true; + if (!strcmp(argv[i], "-one")) + one = true; + if (*argv[i] == '-' && strlen(argv[i]) > 1 && isdigit(argv[i][1]) ) + g_max_connections = atoi(argv[i] + 1); + if (!strcmp(argv[i], "-host") && i < argc - 1) + gHost = argv[++i]; + if (!strcmp(argv[i], "-port") && i < argc - 1) + gPort = atoi(argv[++i]); + if (!strcmp(argv[i], "-off")) + g_b_off = true; + if (!strcmp(argv[i], "-repeat")) + g_b_repeat = true; + if (!strcmp(argv[i], "-size") && i < argc - 1) + g_data_size = atoi(argv[++i]); + if (!strcmp(argv[i], "-log")) + enableLog = true; + if (!strcmp(argv[i], "-time") && i < argc - 1) + report_period = atoi(argv[++i]); + if (!strcmp(argv[i], "-stop")) + g_b_stop = true; +#ifdef HAVE_OPENSSL + if (!strcmp(argv[i], "-ssl")) + g_b_ssl = true; +#endif + if (!strcmp(argv[i], "-instant")) + g_b_instant = true; + if (!strcmp(argv[i], "-http")) + http = true; + if (!strcmp(argv[i], "-url") && i < argc - 1) + url = argv[++i]; + } + if (argc < 2 || (!many && !one && !g_max_connections && !http) ) + { + printf("Usage: %s [mode] [options]\n", *argv); + printf(" Modes (only use one of these):\n"); + printf(" -many start max number of connections\n"); + printf(" -one open - close - repeat\n"); + printf(" -nn open nn connections, then start -one mode\n"); + printf(" -http send/receive http request/response\n"); + printf(" Options:\n"); + printf(" -host xx host to connect to\n"); + printf(" -port nn port number to connection to\n"); + printf(" -off turn off new connections when connection limit reached\n"); + printf(" -repeat send new block when reply is received\n"); + printf(" -size nn size of block to send, default is 1024 bytes\n"); + printf(" -log enable debug log\n"); + printf(" -time nn time between reports, default 10s\n"); + printf(" -stop stop after time elapsed\n"); + printf(" -instant create all sockets at once\n"); +#ifdef HAVE_OPENSSL + printf(" -ssl use ssl\n"); +#endif + printf(" -url xx url to use in http mode (default http://<host>:<port>/)\n"); + exit(-1); + } + fprintf(stderr, "Using data size: %d bytes\n", (int)g_data_size); + std::string chars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; + while (g_data.size() < g_data_size) + { + g_data += chars[rand() % chars.size()]; + } +#ifndef _WIN32 + signal(SIGINT, sigint); + signal(SIGUSR1, sigusr1); + signal(SIGUSR2, sigusr2); + signal(SIGPIPE, SIG_IGN); +#endif + StdoutLog *log = enableLog ? new StdoutLog() : NULL; + MyHandler h(log); + if (http) + { + if (!url.size()) + { + url = "http://" + gHost + ":" + Utility::l2string(gPort) + "/"; + } + MyHttpSocket *s = new MyHttpSocket(h, url); + s -> SetDeleteByHandler(); + h.Add(s); + } + else + if (g_b_instant) + { + for (size_t i = 0; i < g_max_connections; i++) + { + MySocket *s = new MySocket(h, one); + s -> SetDeleteByHandler(); + s -> Open(gHost, gPort); + h.Add(s); + } + g_b_limit = true; + } + else + { + MySocket *s = new MySocket(h, one); + s -> SetDeleteByHandler(); + s -> Open(gHost, gPort); + h.Add(s); + } + time_t t = time(NULL); + gettime(&g_t_start, NULL); + while (!gQuit) + { + h.Select(1, 0); + if (g_b_flood) + { + fprintf(stderr, "\nFlooding\n"); + h.Flood(); + g_b_flood = false; + } + if (time(NULL) - t >= report_period) // report + { + t = time(NULL); + printreport_reset(); + h.Report(); + if (g_b_stop) + { + gQuit = true; + } + } + } + fprintf(stderr, "\nExiting...\n"); + if (log) + { +// delete log; + } + return 0; +} + + |