2 ** \file stressclient.cpp
4 ** \author grymse@alhem.net
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.
24 #pragma warning(disable:4786)
26 #include <StdoutLog.h>
27 #include <ListenSocket.h>
28 #include <SocketHandler.h>
29 #include <TcpSocket.h>
35 typedef __int64
int64_t;
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;
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;
62 static bool g_b_ssl
= false;
64 static bool g_b_instant
= false;
65 static struct timeval g_t_start
;
69 * Return time difference between two struct timeval's, in seconds
70 * \param t0 start time
73 double Diff(struct timeval t0
,struct timeval t
)
75 t
.tv_sec
-= t0
.tv_sec
;
76 t
.tv_usec
-= t0
.tv_usec
;
82 return t
.tv_sec
+ (double)t
.tv_usec
/ 1000000;
86 void gettime(struct timeval
*p
, struct timezone
*)
89 FILETIME ft
; // Contains a 64-bit value representing the number of 100-nanosecond intervals since January 1, 1601 (UTC).
90 GetSystemTimeAsFileTime(&ft
);
92 memcpy(&tt
, &ft
, sizeof(tt
));
94 p
->tv_sec
= tt
/ 1000000;
95 p
->tv_usec
= tt
% 1000000;
97 gettimeofday(p
, NULL
);
106 double rt
= Diff(g_t_start
, tv
);
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
);
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;
117 double mbo
= (double)gBytesOut
/ 1024;
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()
140 gBytesIn
= gBytesOut
= 0;
144 class MySocket
: public TcpSocket
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
);
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
);
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());
172 g_b_flood
= g_b_repeat
;
179 gettime(&m_connect
, NULL
);
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
;
194 gettime(&m_send
, NULL
);
198 void OnLine(const std::string
& line
) {
199 gettime(&m_reply
, NULL
);
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
;
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");
217 gBytesIn
+= GetBytesReceived(true);
218 gBytesOut
+= GetBytesSent(true);
224 if (g_b_repeat
&& g_b_limit
)
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
);
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
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
));
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
;
276 gettime(&m_send
, NULL
);
278 // send request header
279 HttpGetSocket::OnConnect();
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
;
300 MyHttpSocket
*p
= new MyHttpSocket(Handler(), m_url
);
301 p
-> SetDeleteByHandler();
308 struct timeval m_create
;
309 struct timeval m_connect
;
310 struct timeval m_send
;
311 struct timeval m_reply
;
336 class MyHandler
: public SocketHandler
339 MyHandler() : SocketHandler() {
341 MyHandler(StdoutLog
*p
) : SocketHandler(p
) {
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
);
359 for (socket_m::iterator it
= m_sockets
.begin(); it
!= m_sockets
.end(); it
++)
361 MySocket
*p
= dynamic_cast<MySocket
*>(it
-> second
);
371 printf("Number of //stress// sockets: %d Active: %d\n", ant
, act
);
376 int main(int argc
,char *argv
[])
380 bool enableLog
= false;
383 time_t report_period
= 10;
384 for (int i
= 1; i
< argc
; i
++)
386 if (!strcmp(argv
[i
], "-many"))
388 if (!strcmp(argv
[i
], "-one"))
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)
394 if (!strcmp(argv
[i
], "-port") && i
< argc
- 1)
395 gPort
= atoi(argv
[++i
]);
396 if (!strcmp(argv
[i
], "-off"))
398 if (!strcmp(argv
[i
], "-repeat"))
400 if (!strcmp(argv
[i
], "-size") && i
< argc
- 1)
401 g_data_size
= atoi(argv
[++i
]);
402 if (!strcmp(argv
[i
], "-log"))
404 if (!strcmp(argv
[i
], "-time") && i
< argc
- 1)
405 report_period
= atoi(argv
[++i
]);
406 if (!strcmp(argv
[i
], "-stop"))
409 if (!strcmp(argv
[i
], "-ssl"))
412 if (!strcmp(argv
[i
], "-instant"))
414 if (!strcmp(argv
[i
], "-http"))
416 if (!strcmp(argv
[i
], "-url") && i
< argc
- 1)
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");
438 printf(" -ssl use ssl\n");
440 printf(" -url xx url to use in http mode (default http://<host>:<port>/)\n");
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()];
450 signal(SIGINT
, sigint
);
451 signal(SIGUSR1
, sigusr1
);
452 signal(SIGUSR2
, sigusr2
);
453 signal(SIGPIPE
, SIG_IGN
);
455 StdoutLog
*log
= enableLog
? new StdoutLog() : NULL
;
461 url
= "http://" + gHost
+ ":" + Utility::l2string(gPort
) + "/";
463 MyHttpSocket
*s
= new MyHttpSocket(h
, url
);
464 s
-> SetDeleteByHandler();
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
);
481 MySocket
*s
= new MySocket(h
, one
);
482 s
-> SetDeleteByHandler();
483 s
-> Open(gHost
, gPort
);
486 time_t t
= time(NULL
);
487 gettime(&g_t_start
, NULL
);
493 fprintf(stderr
, "\nFlooding\n");
497 if (time(NULL
) - t
>= report_period
) // report
508 fprintf(stderr
, "\nExiting...\n");