big svn cleanup
[anytun.git] / src / Sockets / tests / stressclient.cpp
blob41878686327a031a614a794758c86c91b4e586b9
1 /**
2 ** \file stressclient.cpp
3 ** \date 2006-10-02
4 ** \author grymse@alhem.net
5 **/
6 /*
7 Copyright (C) 2006 Anders Hedstrom
9 This program is free software; you can redistribute it and/or
10 modify it under the terms of the GNU General Public License
11 as published by the Free Software Foundation; either version 2
12 of the License, or (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23 #ifdef _WIN32
24 #pragma warning(disable:4786)
25 #endif
26 #include <StdoutLog.h>
27 #include <ListenSocket.h>
28 #include <SocketHandler.h>
29 #include <TcpSocket.h>
30 #include <Utility.h>
31 #ifndef _WIN32
32 #include <signal.h>
33 #include <stdint.h>
34 #else
35 typedef __int64 int64_t;
36 #endif
37 #include <HttpGetSocket.h>
40 static double g_min_time = 10000;
41 static double g_max_time = 0;
42 static double g_tot_time = 0;
43 static int g_ant = 0;
44 static double g_min_time2 = 10000;
45 static double g_max_time2 = 0;
46 static double g_tot_time2 = 0;
47 static int g_ant2 = 0;
48 static bool gQuit = false;
49 static size_t g_max_connections = 0;
50 static std::string gHost = "localhost";
51 static port_t gPort = 2222;
52 static bool g_b_flood = false;
53 static bool g_b_off = false;
54 static bool g_b_limit = false;
55 static int64_t gBytesIn = 0;
56 static int64_t gBytesOut = 0;
57 static bool g_b_repeat = false;
58 static std::string g_data;
59 static size_t g_data_size = 1024;
60 static bool g_b_stop = false;
61 #ifdef HAVE_OPENSSL
62 static bool g_b_ssl = false;
63 #endif
64 static bool g_b_instant = false;
65 static struct timeval g_t_start;
68 /**
69 * Return time difference between two struct timeval's, in seconds
70 * \param t0 start time
71 * \param t end time
73 double Diff(struct timeval t0,struct timeval t)
75 t.tv_sec -= t0.tv_sec;
76 t.tv_usec -= t0.tv_usec;
77 if (t.tv_usec < 0)
79 t.tv_usec += 1000000;
80 t.tv_sec -= 1;
82 return t.tv_sec + (double)t.tv_usec / 1000000;
86 void gettime(struct timeval *p, struct timezone *)
88 #ifdef _WIN32
89 FILETIME ft; // Contains a 64-bit value representing the number of 100-nanosecond intervals since January 1, 1601 (UTC).
90 GetSystemTimeAsFileTime(&ft);
91 uint64_t tt;
92 memcpy(&tt, &ft, sizeof(tt));
93 tt /= 10;
94 p->tv_sec = tt / 1000000;
95 p->tv_usec = tt % 1000000;
96 #else
97 gettimeofday(p, NULL);
98 #endif
102 void printreport()
104 struct timeval tv;
105 gettime(&tv, NULL);
106 double rt = Diff(g_t_start, tv);
107 g_t_start = tv;
109 printf("\n");
110 if (g_ant)
111 printf("connect; ant: %5d min: %.4f max: %.4f med: %.4f\n", g_ant, g_min_time, g_max_time, g_tot_time / g_ant);
112 if (g_ant2)
113 printf("reply; ant: %5d min: %.4f max: %.4f med: %.4f\n", g_ant2, g_min_time2, g_max_time2, g_tot_time2 / g_ant2);
114 double mbi = (double)gBytesIn / 1024;
115 mbi /= 1024;
116 mbi /= rt;
117 double mbo = (double)gBytesOut / 1024;
118 mbo /= 1024;
119 mbo /= rt;
120 printf("bytes in: %lld", gBytesIn);
121 printf(" (%.2f MB/sec)", mbi);
122 printf(" bytes out: %lld", gBytesOut);
123 printf(" (%.2f MB/sec)", mbo);
124 printf(" time: %.2f sec\n", rt);
128 void printreport_reset()
130 printreport();
132 g_min_time = 10000;
133 g_max_time = 0;
134 g_tot_time = 0;
135 g_ant = 0;
136 g_min_time2 = 10000;
137 g_max_time2 = 0;
138 g_tot_time2 = 0;
139 g_ant2 = 0;
140 gBytesIn = gBytesOut = 0;
144 class MySocket : public TcpSocket
146 public:
147 MySocket(ISocketHandler& h,bool one) : TcpSocket(h), m_b_client(false), m_b_one(one), m_b_created(false), m_b_active(false) {
148 gettime(&m_create, NULL);
149 SetLineProtocol();
150 #ifdef HAVE_OPENSSL
151 if (g_b_ssl)
152 EnableSSL();
153 #endif
154 if (g_max_connections && !m_b_one && Handler().GetCount() >= g_max_connections)
156 fprintf(stderr, "\nConnection limit reached: %d, continuing in single connection stress mode\n", (int)g_max_connections);
157 if (g_b_off)
158 printreport_reset();
159 g_b_limit = true;
160 m_b_one = true;
162 g_b_flood = g_b_repeat;
164 if (!m_b_one && Handler().GetCount() >= FD_SETSIZE - 17)
166 fprintf(stderr, "\nFD_SETSIZE connection limit reached: %d, continuing in single connection stress mode\n", (int)Handler().GetCount());
167 if (g_b_off)
168 printreport_reset();
169 g_b_limit = true;
170 m_b_one = true;
172 g_b_flood = g_b_repeat;
175 ~MySocket() {
178 void OnConnect() {
179 gettime(&m_connect, NULL);
180 m_b_active = true;
182 double tconnect = Diff(m_create, m_connect);
184 g_min_time = tconnect < g_min_time ? tconnect : g_min_time;
185 g_max_time = tconnect > g_max_time ? tconnect : g_max_time;
186 g_tot_time += tconnect;
187 g_ant += 1;
189 SendBlock();
190 m_b_client = true;
193 void SendBlock() {
194 gettime(&m_send, NULL);
195 Send(g_data + "\n");
198 void OnLine(const std::string& line) {
199 gettime(&m_reply, NULL);
200 m_b_active = true;
202 double treply = Diff(m_send, m_reply);
204 g_min_time2 = treply < g_min_time2 ? treply : g_min_time2;
205 g_max_time2 = treply > g_max_time2 ? treply : g_max_time2;
206 g_tot_time2 += treply;
207 g_ant2 += 1;
210 if (line != g_data)
212 fprintf(stderr, "\n%s\n%s\n", line.c_str(), g_data.c_str());
213 fprintf(stderr, "(reply did not match data - exiting)\n");
214 exit(-1);
217 gBytesIn += GetBytesReceived(true);
218 gBytesOut += GetBytesSent(true);
219 if (m_b_one)
221 SetCloseAndDelete();
223 else
224 if (g_b_repeat && g_b_limit)
226 SendBlock();
228 // add another
229 if (!m_b_created && (!g_b_limit || !g_b_off) && !g_b_instant)
231 MySocket *p = new MySocket(Handler(), m_b_one);
232 p -> SetDeleteByHandler();
233 p -> Open(gHost, gPort);
234 Handler().Add(p);
235 m_b_created = true;
239 bool IsActive() {
240 bool b = m_b_active;
241 m_b_active = false;
242 return b;
245 private:
246 bool m_b_client;
247 bool m_b_one;
248 bool m_b_created;
249 bool m_b_active;
250 struct timeval m_create;
251 struct timeval m_connect;
252 struct timeval m_send;
253 struct timeval m_reply;
257 class MyHttpSocket : public HttpGetSocket
259 public:
260 MyHttpSocket(ISocketHandler& h,const std::string& url) : HttpGetSocket(h,url), m_url(url) {
261 gettime(&m_create, NULL);
262 AddResponseHeader("content-length", Utility::l2string(g_data_size));
264 ~MyHttpSocket() {}
266 void OnConnect() {
267 gettime(&m_connect, NULL);
269 double tconnect = Diff(m_create, m_connect);
271 g_min_time = tconnect < g_min_time ? tconnect : g_min_time;
272 g_max_time = tconnect > g_max_time ? tconnect : g_max_time;
273 g_tot_time += tconnect;
274 g_ant += 1;
276 gettime(&m_send, NULL);
278 // send request header
279 HttpGetSocket::OnConnect();
281 // send body
282 Send(g_data);
285 void OnContent() {
286 gettime(&m_reply, NULL);
288 double treply = Diff(m_send, m_reply);
290 g_min_time2 = treply < g_min_time2 ? treply : g_min_time2;
291 g_max_time2 = treply > g_max_time2 ? treply : g_max_time2;
292 g_tot_time2 += treply;
293 g_ant2 += 1;
295 CreateNew();
297 void CreateNew() {
298 if (g_b_off)
299 return;
300 MyHttpSocket *p = new MyHttpSocket(Handler(), m_url);
301 p -> SetDeleteByHandler();
302 Handler().Add(p);
303 SetCloseAndDelete();
306 private:
307 std::string m_url;
308 struct timeval m_create;
309 struct timeval m_connect;
310 struct timeval m_send;
311 struct timeval m_reply;
315 #ifndef _WIN32
316 void sigint(int)
318 printreport();
319 gQuit = true;
323 void sigusr1(int)
325 g_b_flood = true;
329 void sigusr2(int)
331 printreport_reset();
333 #endif
336 class MyHandler : public SocketHandler
338 public:
339 MyHandler() : SocketHandler() {
341 MyHandler(StdoutLog *p) : SocketHandler(p) {
343 ~MyHandler() {
345 void Flood() {
346 for (socket_m::iterator it = m_sockets.begin(); it != m_sockets.end(); it++)
348 Socket *p0 = it -> second;
349 MySocket *p = dynamic_cast<MySocket *>(p0);
350 if (p)
352 p -> SendBlock();
356 void Report() {
357 int ant = 0;
358 int act = 0;
359 for (socket_m::iterator it = m_sockets.begin(); it != m_sockets.end(); it++)
361 MySocket *p = dynamic_cast<MySocket *>(it -> second);
362 if (p)
364 ant++;
365 if (p -> IsActive())
367 act++;
371 printf("Number of //stress// sockets: %d Active: %d\n", ant, act);
376 int main(int argc,char *argv[])
378 bool many = false;
379 bool one = false;
380 bool enableLog = false;
381 bool http = false;
382 std::string url;
383 time_t report_period = 10;
384 for (int i = 1; i < argc; i++)
386 if (!strcmp(argv[i], "-many"))
387 many = true;
388 if (!strcmp(argv[i], "-one"))
389 one = true;
390 if (*argv[i] == '-' && strlen(argv[i]) > 1 && isdigit(argv[i][1]) )
391 g_max_connections = atoi(argv[i] + 1);
392 if (!strcmp(argv[i], "-host") && i < argc - 1)
393 gHost = argv[++i];
394 if (!strcmp(argv[i], "-port") && i < argc - 1)
395 gPort = atoi(argv[++i]);
396 if (!strcmp(argv[i], "-off"))
397 g_b_off = true;
398 if (!strcmp(argv[i], "-repeat"))
399 g_b_repeat = true;
400 if (!strcmp(argv[i], "-size") && i < argc - 1)
401 g_data_size = atoi(argv[++i]);
402 if (!strcmp(argv[i], "-log"))
403 enableLog = true;
404 if (!strcmp(argv[i], "-time") && i < argc - 1)
405 report_period = atoi(argv[++i]);
406 if (!strcmp(argv[i], "-stop"))
407 g_b_stop = true;
408 #ifdef HAVE_OPENSSL
409 if (!strcmp(argv[i], "-ssl"))
410 g_b_ssl = true;
411 #endif
412 if (!strcmp(argv[i], "-instant"))
413 g_b_instant = true;
414 if (!strcmp(argv[i], "-http"))
415 http = true;
416 if (!strcmp(argv[i], "-url") && i < argc - 1)
417 url = argv[++i];
419 if (argc < 2 || (!many && !one && !g_max_connections && !http) )
421 printf("Usage: %s [mode] [options]\n", *argv);
422 printf(" Modes (only use one of these):\n");
423 printf(" -many start max number of connections\n");
424 printf(" -one open - close - repeat\n");
425 printf(" -nn open nn connections, then start -one mode\n");
426 printf(" -http send/receive http request/response\n");
427 printf(" Options:\n");
428 printf(" -host xx host to connect to\n");
429 printf(" -port nn port number to connection to\n");
430 printf(" -off turn off new connections when connection limit reached\n");
431 printf(" -repeat send new block when reply is received\n");
432 printf(" -size nn size of block to send, default is 1024 bytes\n");
433 printf(" -log enable debug log\n");
434 printf(" -time nn time between reports, default 10s\n");
435 printf(" -stop stop after time elapsed\n");
436 printf(" -instant create all sockets at once\n");
437 #ifdef HAVE_OPENSSL
438 printf(" -ssl use ssl\n");
439 #endif
440 printf(" -url xx url to use in http mode (default http://<host>:<port>/)\n");
441 exit(-1);
443 fprintf(stderr, "Using data size: %d bytes\n", (int)g_data_size);
444 std::string chars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
445 while (g_data.size() < g_data_size)
447 g_data += chars[rand() % chars.size()];
449 #ifndef _WIN32
450 signal(SIGINT, sigint);
451 signal(SIGUSR1, sigusr1);
452 signal(SIGUSR2, sigusr2);
453 signal(SIGPIPE, SIG_IGN);
454 #endif
455 StdoutLog *log = enableLog ? new StdoutLog() : NULL;
456 MyHandler h(log);
457 if (http)
459 if (!url.size())
461 url = "http://" + gHost + ":" + Utility::l2string(gPort) + "/";
463 MyHttpSocket *s = new MyHttpSocket(h, url);
464 s -> SetDeleteByHandler();
465 h.Add(s);
467 else
468 if (g_b_instant)
470 for (size_t i = 0; i < g_max_connections; i++)
472 MySocket *s = new MySocket(h, one);
473 s -> SetDeleteByHandler();
474 s -> Open(gHost, gPort);
475 h.Add(s);
477 g_b_limit = true;
479 else
481 MySocket *s = new MySocket(h, one);
482 s -> SetDeleteByHandler();
483 s -> Open(gHost, gPort);
484 h.Add(s);
486 time_t t = time(NULL);
487 gettime(&g_t_start, NULL);
488 while (!gQuit)
490 h.Select(1, 0);
491 if (g_b_flood)
493 fprintf(stderr, "\nFlooding\n");
494 h.Flood();
495 g_b_flood = false;
497 if (time(NULL) - t >= report_period) // report
499 t = time(NULL);
500 printreport_reset();
501 h.Report();
502 if (g_b_stop)
504 gQuit = true;
508 fprintf(stderr, "\nExiting...\n");
509 if (log)
511 // delete log;
513 return 0;