1 /* Copyright 1999-2004 The Apache Software Foundation
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
7 * http://www.apache.org/licenses/LICENSE-2.0
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
17 ** This program is based on ZeusBench V1.0 written by Adam Twiss
18 ** which is Copyright (c) 1996 by Zeus Technology Ltd. http://www.zeustech.net/
20 ** This software is provided "as is" and any express or implied waranties,
21 ** including but not limited to, the implied warranties of merchantability and
22 ** fitness for a particular purpose are disclaimed. In no event shall
23 ** Zeus Technology Ltd. be liable for any direct, indirect, incidental, special,
24 ** exemplary, or consequential damaged (including, but not limited to,
25 ** procurement of substitute good or services; loss of use, data, or profits;
26 ** or business interruption) however caused and on theory of liability. Whether
27 ** in contract, strict liability or tort (including negligence or otherwise)
28 ** arising in any way out of the use of this software, even if advised of the
29 ** possibility of such damage.
35 ** - Originally written by Adam Twiss <adam@zeus.co.uk>, March 1996
36 ** with input from Mike Belshe <mbelshe@netscape.com> and
37 ** Michael Campanella <campanella@stevms.enet.dec.com>
38 ** - Enhanced by Dean Gaudet <dgaudet@apache.org>, November 1997
39 ** - Cleaned up by Ralf S. Engelschall <rse@apache.org>, March 1998
40 ** - POST and verbosity by Kurt Sussman <kls@merlot.com>, August 1998
41 ** - HTML table output added by David N. Welton <davidw@prosa.it>, January 1999
42 ** - Added Cookie, Arbitrary header and auth support. <dirkx@webweaving.org>, April 1999
44 ** - Increased version number - as some of the socket/error handling has
45 ** fundamentally changed - and will give fundamentally different results
46 ** in situations where a server is dropping requests. Therefore you can
47 ** no longer compare results of AB as easily. Hence the inc of the version.
48 ** They should be closer to the truth though. Sander & <dirkx@covalent.net>, End 2000.
49 ** - Fixed proxy functionality, added median/mean statistics, added gnuplot
50 ** output option, added _experimental/rudimentary_ SSL support. Added
51 ** confidence guestimators and warnings. Sander & <dirkx@covalent.net>, End 2000
52 ** - Fixed serious int overflow issues which would cause realistic (longer
53 ** than a few minutes) run's to have wrong (but believable) results. Added
54 ** trapping of connection errors which influenced measurements.
55 ** Contributed by Sander Temme, Early 2001
57 ** - Changed timeout behavour during write to work whilst the sockets
58 ** are filling up and apr_write() does writes a few - but not all.
59 ** This will potentially change results. <dirkx@webweaving.org>, April 2001
61 ** Improvements to concurrent processing:
62 ** - Enabled non-blocking connect()s.
63 ** - Prevent blocking calls to apr_socket_recv() (thereby allowing AB to
64 ** manage its entire set of socket descriptors).
65 ** - Any error returned from apr_socket_recv() that is not EAGAIN or EOF
66 ** is now treated as fatal.
67 ** Contributed by Aaron Bannert, April 24, 2002
70 ** Internalized the version string - this string is part
71 ** of the Agent: header and the result output.
74 ** Adopted SSL code by Madhu Mathihalli <madhusudan_mathihalli@hp.com>
75 ** [PATCH] ab with SSL support Posted Wed, 15 Aug 2001 20:55:06 GMT
76 ** Introduces four 'if (int == value)' tests per non-ssl request.
79 ** Switched to the new abstract pollset API, allowing ab to
80 ** take advantage of future apr_pollset_t scalability improvements.
81 ** Contributed by Brian Pane, August 31, 2002
84 /* Note: this version string should start with \d+[\d\.]* and be a valid
85 * string for an HTTP Agent: header when prefixed with 'ApacheBench/'.
86 * It should reflect the version of AB - and not that of the apache server
87 * it happens to accompany. And it should be updated or changed whenever
88 * the results are no longer fundamentally comparable to the results of
89 * a previous version of ab. Either due to a change in the logic of
90 * ab - or to due to a change in the distribution it is compiled with
91 * (such as an APR change in for example blocking).
93 #define AP_AB_BASEREVISION "2.0.40-dev"
99 * - has various other poor buffer attacks related to the lazy parsing of
100 * response headers from the server
101 * - doesn't implement much of HTTP/1.x, only accepts certain forms of
103 * - (performance problem) heavy use of strstr shows up top in profile
104 * only an issue for loopback usage
107 /* -------------------------------------------------------------------- */
110 /* Hmmm... This source code isn't being compiled in ASCII.
111 * In order for data that flows over the network to make
112 * sense, we need to translate to/from ASCII.
117 /* affects include files on Solaris */
121 #include "apr_signal.h"
122 #include "apr_strings.h"
123 #include "apr_network_io.h"
124 #include "apr_file_io.h"
125 #include "apr_time.h"
126 #include "apr_getopt.h"
127 #include "apr_general.h"
129 #include "apr_portable.h"
130 #include "ap_release.h"
131 #include "apr_poll.h"
133 #define APR_WANT_STRFUNC
134 #include "apr_want.h"
136 #include "apr_base64.h"
138 #include "apr_xlate.h"
143 #if APR_HAVE_STDLIB_H
146 #if APR_HAVE_UNISTD_H
147 #include <unistd.h> /* for getpid() */
150 #if !defined(WIN32) && !defined(NETWARE)
151 #include "ap_config_auto.h"
154 #if defined(HAVE_SSLC)
156 /* Libraries for RSA SSL-C */
167 #elif defined(HAVE_OPENSSL)
169 /* Libraries on most systems.. */
170 #include <openssl/rsa.h>
171 #include <openssl/crypto.h>
172 #include <openssl/x509.h>
173 #include <openssl/pem.h>
174 #include <openssl/err.h>
175 #include <openssl/ssl.h>
176 #include <openssl/rand.h>
186 /* ------------------- DEFINITIONS -------------------------- */
189 #define AB_MAX APR_INT64_C(0x7fffffffffffffff)
191 #define AB_MAX LLONG_MAX
194 /* maximum number of requests on a time limited test */
195 #define MAX_REQUESTS 50000
197 /* good old state hostname */
198 #define STATE_UNCONNECTED 0
199 #define STATE_CONNECTING 1 /* TCP connect initiated, but we don't
200 * know if it worked yet
202 #define STATE_CONNECTED 2 /* we know TCP connect completed */
205 #define CBUFFSIZE (2048)
209 apr_socket_t *aprsock;
211 apr_size_t read; /* amount of bytes read */
212 apr_size_t bread; /* amount of body read */
213 apr_size_t rwrite, rwrote; /* keep pointers in what we write - across
215 apr_size_t length; /* Content-Length value used for keep-alive */
216 char cbuff[CBUFFSIZE]; /* a buffer to store server response header */
217 int cbx; /* offset in cbuffer */
218 int keepalive; /* non-zero if a keep-alive request */
219 int gotheader; /* non-zero if we have the entire header in
221 apr_time_t start, /* Start of connection */
222 connect, /* Connected, start writing */
223 endwrite, /* Request written */
224 beginread, /* First byte of input */
225 done; /* Connection closed */
235 /* XXXX insert SSL timings */
237 int read; /* number of bytes read */
238 apr_time_t starttime; /* start time of connection in seconds since
240 apr_interval_time_t waittime; /* Between writing request and reading
242 apr_interval_time_t ctime; /* time in ms to connect */
243 apr_interval_time_t time; /* time in ms for connection */
246 #define ap_min(a,b) ((a)<(b))?(a):(b)
247 #define ap_max(a,b) ((a)>(b))?(a):(b)
249 /* --------------------- GLOBALS ---------------------------- */
251 int verbosity = 0; /* no verbosity by default */
252 int posting = 0; /* GET by default */
253 int requests = 1; /* Number of requests to make */
254 int heartbeatres = 100; /* How often do we say we're alive */
255 int concurrency = 1; /* Number of multiple requests to make */
256 int percentile = 1; /* Show percentile served */
257 int confidence = 1; /* Show confidence estimator and warnings */
258 int tlimit = 0; /* time limit in secs */
259 int keepalive = 0; /* try and do keepalive connections */
260 char servername[1024]; /* name that server reports */
261 char *hostname; /* host name from URL */
262 char *host_field; /* value of "Host:" header field */
263 char *path; /* path name */
264 char postfile[1024]; /* name of file containing post data */
265 char *postdata; /* *buffer containing data from postfile */
266 apr_size_t postlen = 0; /* length of data to be POSTed */
267 char content_type[1024]; /* content type to put in POST header */
268 char *cookie, /* optional cookie line */
269 *auth, /* optional (basic/uuencoded) auhentication */
270 *hdrs; /* optional arbitrary headers */
271 apr_port_t port; /* port number */
272 char proxyhost[1024]; /* proxy host name */
273 int proxyport = 0; /* proxy port */
275 apr_port_t connectport;
276 char *gnuplot; /* GNUplot file */
277 char *csvperc; /* CSV Percentile file */
279 char * fullurl, * colonhost;
281 apr_interval_time_t aprtimeout = apr_time_from_sec(30); /* timeout value */
283 * XXX - this is now a per read/write transact type of value
286 int use_html = 0; /* use html in the report */
287 const char *tablestring;
288 const char *trstring;
289 const char *tdstring;
291 apr_size_t doclen = 0; /* the length the document should be */
292 long started = 0; /* number of requests started, so no excess */
293 long totalread = 0; /* total number of bytes read */
294 long totalbread = 0; /* totoal amount of entity body read */
295 long totalposted = 0; /* total number of bytes posted, inc. headers */
296 long done = 0; /* number of requests we have done */
297 long doneka = 0; /* number of keep alive connections done */
298 long good = 0, bad = 0; /* number of good and bad requests */
299 long epipe = 0; /* number of broken pipe writes */
304 BIO *bio_out,*bio_err;
305 static void write_request(struct connection * c);
308 /* store error cases */
309 int err_length = 0, err_conn = 0, err_except = 0;
310 int err_response = 0;
312 apr_time_t start, endtime;
314 /* global request (and its length) */
316 char *request = _request;
319 /* one global throw-away buffer to read stuff into */
322 /* interesting percentiles */
323 int percs[] = {50, 66, 75, 80, 90, 95, 98, 99, 100};
325 struct connection *con; /* connection array */
326 struct data *stats; /* date for each request */
329 apr_pollset_t *readbits;
331 apr_sockaddr_t *destsa;
334 apr_xlate_t *from_ascii, *to_ascii;
337 static void close_connection(struct connection * c);
338 /* --------------------------------------------------------- */
340 /* simple little function to write an error string and exit */
342 static void err(char *s)
344 fprintf(stderr, "%s\n", s);
346 printf("Total of %ld requests completed\n" , done);
350 /* simple little function to write an APR error string and exit */
352 static void apr_err(char *s, apr_status_t rv)
358 s, apr_strerror(rv, buf, sizeof buf), rv);
360 printf("Total of %ld requests completed\n" , done);
364 #if defined(USE_SSL) && USE_THREADS
366 * To ensure thread-safetyness in OpenSSL - work in progress
369 static apr_thread_mutex_t **lock_cs;
370 static int lock_num_locks;
372 static void ssl_util_thr_lock(int mode, int type,
373 const char *file, int line)
375 if (type < lock_num_locks) {
376 if (mode & CRYPTO_LOCK) {
377 apr_thread_mutex_lock(lock_cs[type]);
380 apr_thread_mutex_unlock(lock_cs[type]);
385 static unsigned long ssl_util_thr_id(void)
387 /* OpenSSL needs this to return an unsigned long. On OS/390, the pthread
388 * id is a structure twice that big. Use the TCB pointer instead as a
389 * unique unsigned long.
394 unsigned long PSATOLD;
397 return psaptr->PSATOLD;
399 return (unsigned long) apr_os_thread_current();
403 static apr_status_t ssl_util_thread_cleanup(void *data)
405 CRYPTO_set_locking_callback(NULL);
407 /* Let the registered mutex cleanups do their own thing
412 void ssl_util_thread_setup(apr_pool_t *p)
416 lock_num_locks = CRYPTO_num_locks();
417 lock_cs = apr_palloc(p, lock_num_locks * sizeof(*lock_cs));
419 for (i = 0; i < lock_num_locks; i++) {
420 apr_thread_mutex_create(&(lock_cs[i]), APR_THREAD_MUTEX_DEFAULT, p);
423 CRYPTO_set_id_callback(ssl_util_thr_id);
425 CRYPTO_set_locking_callback(ssl_util_thr_lock);
427 apr_pool_cleanup_register(p, NULL, ssl_util_thread_cleanup,
428 apr_pool_cleanup_null);
432 /* --------------------------------------------------------- */
433 /* write out request to a connection - assumes we can write
434 * (small) request out in one go into our new socket buffer
438 static long ssl_print_cb(BIO *bio,int cmd,const char *argp,int argi,long argl,long ret)
442 out=(BIO *)BIO_get_callback_arg(bio);
443 if (out == NULL) return(ret);
445 if (cmd == (BIO_CB_READ|BIO_CB_RETURN))
447 BIO_printf(out,"read from %08X [%08lX] (%d bytes => %ld (0x%X))\n",
448 bio,argp,argi,ret,ret);
449 BIO_dump(out,(char *)argp,(int)ret);
452 else if (cmd == (BIO_CB_WRITE|BIO_CB_RETURN))
454 BIO_printf(out,"write to %08X [%08lX] (%d bytes => %ld (0x%X))\n",
455 bio,argp,argi,ret,ret);
456 BIO_dump(out,(char *)argp,(int)ret);
463 #define RAND_MAX INT_MAX
466 static int ssl_rand_choosenum(int l, int h)
471 srand((unsigned int)time(NULL));
472 apr_snprintf(buf, sizeof(buf), "%.0f",
473 (((double)(rand()%RAND_MAX)/RAND_MAX)*(h-l)));
480 static void ssl_rand_seed(void)
486 unsigned char stackdata[256];
489 * seed in the current time (usually just 4 bytes)
493 RAND_seed((unsigned char *)&t, l);
497 * seed in the current process id (usually just 4 bytes)
501 RAND_seed((unsigned char *)&pid, l);
505 * seed in some current state of the run-time stack (128 bytes)
507 n = ssl_rand_choosenum(0, sizeof(stackdata)-128-1);
508 RAND_seed(stackdata+n, 128);
512 static int ssl_print_connection_info(BIO *bio, SSL *ssl)
517 c=SSL_get_current_cipher(ssl);
518 BIO_printf(bio,"Cipher Suite Protocol :%s\n", SSL_CIPHER_get_version(c));
519 BIO_printf(bio,"Cipher Suite Name :%s\n",SSL_CIPHER_get_name(c));
521 bits=SSL_CIPHER_get_bits(c,&alg_bits);
522 BIO_printf(bio,"Cipher Suite Cipher Bits:%d (%d)\n",bits,alg_bits);
527 static int ssl_print_cert_info(BIO *bio, X509 *x509cert)
532 BIO_printf(bio,"Certificate version: %d\n",X509_get_version(x509cert)+1);
534 BIO_printf(bio,"Valid from: ");
535 ASN1_UTCTIME_print(bio, X509_get_notBefore(x509cert));
536 BIO_printf(bio,"\n");
538 BIO_printf(bio,"Valid to : ");
539 ASN1_UTCTIME_print(bio, X509_get_notAfter(x509cert));
540 BIO_printf(bio,"\n");
542 BIO_printf(bio,"Public key is %d bits\n",
543 EVP_PKEY_bits(X509_get_pubkey(x509cert)));
545 dn=X509_get_issuer_name(x509cert);
546 X509_NAME_oneline(dn, buf, BUFSIZ);
547 BIO_printf(bio,"The issuer name is %s\n", buf);
549 dn=X509_get_subject_name(x509cert);
550 X509_NAME_oneline(dn, buf, BUFSIZ);
551 BIO_printf(bio,"The subject name is %s\n", buf);
553 /* dump the extension list too */
554 BIO_printf(bio,"Extension Count: %d\n",X509_get_ext_count(x509cert));
559 static void ssl_start_connect(struct connection * c)
568 int i, count, hdone = 0;
569 char ssl_hostname[80];
571 /* XXX - Verify if it's okay - TBD */
572 if (requests < concurrency)
573 requests = concurrency;
575 if (!(started < requests))
585 apr_pool_destroy(c->ctx);
586 apr_pool_create(&c->ctx, cntxt);
588 if ((c->ssl=SSL_new(ctx)) == NULL)
590 BIO_printf(bio_err,"SSL_new failed\n");
596 c->start = apr_time_now();
597 memset(ssl_hostname, 0, 80);
598 sprintf(ssl_hostname, "%s:%d", hostname, port);
600 if ((bio = BIO_new_connect(ssl_hostname)) == NULL)
602 BIO_printf(bio_err,"BIO_new_connect failed\n");
605 SSL_set_bio(c->ssl,bio,bio);
606 SSL_set_connect_state(c->ssl);
610 BIO_set_callback(bio,ssl_print_cb);
611 BIO_set_callback_arg(bio,(void*)bio_err);
616 i = SSL_do_handshake(c->ssl);
618 switch (SSL_get_error(c->ssl,i))
624 case SSL_ERROR_SYSCALL:
625 BIO_printf(bio_err,"SSL connection failed\n");
627 c->state = STATE_UNCONNECTED;
630 BIO_printf(bio_err,"\nTest aborted after 10 failures\n\n");
634 case SSL_ERROR_WANT_READ:
635 case SSL_ERROR_WANT_WRITE:
636 case SSL_ERROR_WANT_CONNECT:
637 BIO_printf(bio_err, "Waiting .. sleep(1)\n");
638 apr_sleep(apr_time_from_sec(1));
639 c->state = STATE_CONNECTED;
642 case SSL_ERROR_ZERO_RETURN:
643 BIO_printf(bio_err,"socket closed\n");
650 BIO_printf(bio_err, "\n");
651 sk = SSL_get_peer_cert_chain(c->ssl);
653 if ((count = sk_num(sk)) > 0)
655 if ((count = sk_X509_num(sk)) > 0)
658 for (i=1; i<count; i++)
661 x509cert = (X509 *)sk_value(sk,i);
663 x509cert = (X509 *)sk_X509_value(sk,i);
665 ssl_print_cert_info(bio_out,x509cert);
670 x509cert = SSL_get_peer_certificate(c->ssl);
671 if (x509cert == NULL)
672 BIO_printf(bio_out, "Anon DH\n");
675 BIO_printf(bio_out, "Peer certificate\n");
676 ssl_print_cert_info(bio_out,x509cert);
680 ssl_print_connection_info(bio_err,c->ssl);
681 SSL_SESSION_print(bio_err,SSL_get_session(c->ssl));
684 /* connected first time */
690 static void write_request(struct connection * c)
693 apr_time_t tnow = apr_time_now();
694 apr_size_t l = c->rwrite;
695 apr_status_t e = APR_SUCCESS; /* prevent gcc warning */
700 if (c->rwrite == 0) {
704 apr_socket_timeout_set(c->aprsock, 0);
709 c->rwrite += postlen;
711 else if (tnow > c->connect + aprtimeout) {
712 printf("Send request timed out!\n");
720 e_ssl = SSL_write(c->ssl,request + c->rwrote, l);
723 printf("SSL write failed - closing connection\n");
724 close_connection (c);
731 e = apr_socket_send(c->aprsock, request + c->rwrote, &l);
734 * Bail early on the most common case
742 if (e != APR_SUCCESS) {
744 * Let's hope this traps EWOULDBLOCK too !
746 if (!APR_STATUS_IS_EAGAIN(e)) {
748 printf("Send request failed!\n");
757 totalposted += c->rwrite;
758 c->state = STATE_READ;
759 c->endwrite = apr_time_now();
764 apr_pollfd_t new_pollfd;
765 new_pollfd.desc_type = APR_POLL_SOCKET;
766 new_pollfd.reqevents = APR_POLLIN;
767 new_pollfd.desc.s = c->aprsock;
768 new_pollfd.client_data = c;
769 apr_pollset_add(readbits, &new_pollfd);
773 /* --------------------------------------------------------- */
775 /* calculate and output results */
777 static int compradre(struct data * a, struct data * b)
779 if ((a->ctime) < (b->ctime))
781 if ((a->ctime) > (b->ctime))
786 static int comprando(struct data * a, struct data * b)
788 if ((a->time) < (b->time))
790 if ((a->time) > (b->time))
795 static int compri(struct data * a, struct data * b)
797 apr_interval_time_t p = a->time - a->ctime;
798 apr_interval_time_t q = b->time - b->ctime;
806 static int compwait(struct data * a, struct data * b)
808 if ((a->waittime) < (b->waittime))
810 if ((a->waittime) > (b->waittime))
815 static void output_results(void)
817 apr_interval_time_t timetakenusec;
820 endtime = apr_time_now();
821 timetakenusec = endtime - start;
822 timetaken = ((float)apr_time_sec(timetakenusec)) +
823 ((float)apr_time_usec(timetakenusec)) / 1000000.0F;
826 printf("Server Software: %s\n", servername);
827 printf("Server Hostname: %s\n", hostname);
828 printf("Server Port: %hd\n", port);
830 printf("Document Path: %s\n", path);
831 printf("Document Length: %" APR_SIZE_T_FMT " bytes\n", doclen);
833 printf("Concurrency Level: %d\n", concurrency);
834 printf("Time taken for tests: %ld.%03ld seconds\n",
835 (long) apr_time_sec(timetakenusec),
836 (long) apr_time_usec(timetakenusec));
837 printf("Complete requests: %ld\n", done);
838 printf("Failed requests: %ld\n", bad);
840 printf(" (Connect: %d, Length: %d, Exceptions: %d)\n",
841 err_conn, err_length, err_except);
842 printf("Write errors: %ld\n", epipe);
844 printf("Non-2xx responses: %d\n", err_response);
846 printf("Keep-Alive requests: %ld\n", doneka);
847 printf("Total transferred: %ld bytes\n", totalread);
849 printf("Total POSTed: %ld\n", totalposted);
850 printf("HTML transferred: %ld bytes\n", totalbread);
852 /* avoid divide by zero */
854 printf("Requests per second: %.2f [#/sec] (mean)\n",
855 (float) (done / timetaken));
856 printf("Time per request: %.3f [ms] (mean)\n",
857 (float) (1000 * concurrency * timetaken / done));
858 printf("Time per request: %.3f [ms] (mean, across all concurrent requests)\n",
859 (float) (1000 * timetaken / done));
860 printf("Transfer rate: %.2f [Kbytes/sec] received\n",
861 (float) (totalread / 1024 / timetaken));
863 printf(" %.2f kb/s sent\n",
864 (float) (totalposted / timetaken / 1024));
865 printf(" %.2f kb/s total\n",
866 (float) ((totalread + totalposted) / timetaken / 1024));
871 /* work out connection times */
873 apr_time_t totalcon = 0, total = 0, totald = 0, totalwait = 0;
874 apr_interval_time_t mincon = AB_MAX, mintot = AB_MAX, mind = AB_MAX,
876 apr_interval_time_t maxcon = 0, maxtot = 0, maxd = 0, maxwait = 0;
877 apr_interval_time_t meancon = 0, meantot = 0, meand = 0, meanwait = 0;
878 double sdtot = 0, sdcon = 0, sdd = 0, sdwait = 0;
880 for (i = 0; i < requests; i++) {
881 struct data s = stats[i];
882 mincon = ap_min(mincon, s.ctime);
883 mintot = ap_min(mintot, s.time);
884 mind = ap_min(mind, s.time - s.ctime);
885 minwait = ap_min(minwait, s.waittime);
887 maxcon = ap_max(maxcon, s.ctime);
888 maxtot = ap_max(maxtot, s.time);
889 maxd = ap_max(maxd, s.time - s.ctime);
890 maxwait = ap_max(maxwait, s.waittime);
894 totald += s.time - s.ctime;
895 totalwait += s.waittime;
897 totalcon /= requests;
900 totalwait /= requests;
902 for (i = 0; i < requests; i++) {
903 struct data s = stats[i];
905 a = ((double)s.time - total);
907 a = ((double)s.ctime - totalcon);
909 a = ((double)s.time - (double)s.ctime - totald);
911 a = ((double)s.waittime - totalwait);
915 sdtot = (requests > 1) ? sqrt(sdtot / (requests - 1)) : 0;
916 sdcon = (requests > 1) ? sqrt(sdcon / (requests - 1)) : 0;
917 sdd = (requests > 1) ? sqrt(sdd / (requests - 1)) : 0;
918 sdwait = (requests > 1) ? sqrt(sdwait / (requests - 1)) : 0;
921 FILE *out = fopen(gnuplot, "w");
924 char tmstring[1024];/* XXXX */
926 perror("Cannot open gnuplot output file");
929 fprintf(out, "starttime\tseconds\tctime\tdtime\tttime\twait\n");
930 for (i = 0; i < requests; i++) {
931 apr_time_t diff = stats[i].time - stats[i].ctime;
933 sttime = stats[i].starttime;
934 (void) apr_ctime(tmstring, sttime);
935 fprintf(out, "%s\t%" APR_TIME_T_FMT "\t%" APR_TIME_T_FMT "\t%" APR_TIME_T_FMT "\t%" APR_TIME_T_FMT "\t%" APR_TIME_T_FMT "\n",
946 * XXX: what is better; this hideous cast of the compradre function; or
947 * the four warnings during compile ? dirkx just does not know and
950 qsort(stats, requests, sizeof(struct data),
951 (int (*) (const void *, const void *)) compradre);
952 if ((requests > 1) && (requests % 2))
953 meancon = (stats[requests / 2].ctime + stats[requests / 2 + 1].ctime) / 2;
955 meancon = stats[requests / 2].ctime;
957 qsort(stats, requests, sizeof(struct data),
958 (int (*) (const void *, const void *)) compri);
959 if ((requests > 1) && (requests % 2))
960 meand = (stats[requests / 2].time + stats[requests / 2 + 1].time \
961 -stats[requests / 2].ctime - stats[requests / 2 + 1].ctime) / 2;
963 meand = stats[requests / 2].time - stats[requests / 2].ctime;
965 qsort(stats, requests, sizeof(struct data),
966 (int (*) (const void *, const void *)) compwait);
967 if ((requests > 1) && (requests % 2))
968 meanwait = (stats[requests / 2].waittime + stats[requests / 2 + 1].waittime) / 2;
970 meanwait = stats[requests / 2].waittime;
972 qsort(stats, requests, sizeof(struct data),
973 (int (*) (const void *, const void *)) comprando);
974 if ((requests > 1) && (requests % 2))
975 meantot = (stats[requests / 2].time + stats[requests / 2 + 1].time) / 2;
977 meantot = stats[requests / 2].time;
979 printf("\nConnection Times (ms)\n");
982 #define CONF_FMT_STRING "%5" APR_TIME_T_FMT " %4d %5.1f %6" APR_TIME_T_FMT " %7" APR_TIME_T_FMT "\n"
983 printf(" min mean[+/-sd] median max\n");
984 printf("Connect: " CONF_FMT_STRING,
985 mincon, (int) (totalcon + 0.5), sdcon, meancon, maxcon);
986 printf("Processing: " CONF_FMT_STRING,
987 mind, (int) (totald + 0.5), sdd, meand, maxd);
988 printf("Waiting: " CONF_FMT_STRING,
989 minwait, (int) (totalwait + 0.5), sdwait, meanwait, maxwait);
990 printf("Total: " CONF_FMT_STRING,
991 mintot, (int) (total + 0.5), sdtot, meantot, maxtot);
992 #undef CONF_FMT_STRING
994 #define SANE(what,avg,mean,sd) \
996 double d = (double)avg - mean; \
999 printf("ERROR: The median and mean for " what " are more than twice the standard\n" \
1000 " deviation apart. These results are NOT reliable.\n"); \
1002 printf("WARNING: The median and mean for " what " are not within a normal deviation\n" \
1003 " These results are probably not that reliable.\n"); \
1005 SANE("the initial connection time", totalcon, meancon, sdcon);
1006 SANE("the processing time", totald, meand, sdd);
1007 SANE("the waiting time", totalwait, meanwait, sdwait);
1008 SANE("the total time", total, meantot, sdtot);
1011 printf(" min avg max\n");
1012 #define CONF_FMT_STRING "%5" APR_TIME_T_FMT " %5" APR_TIME_T_FMT "%5" APR_TIME_T_FMT "\n"
1013 printf("Connect: " CONF_FMT_STRING,
1014 mincon, totalcon / requests, maxcon);
1015 printf("Processing: " CONF_FMT_STRING, mintot - mincon,
1016 (total / requests) - (totalcon / requests),
1018 printf("Total: " CONF_FMT_STRING,
1019 mintot, total / requests, maxtot);
1020 #undef CONF_FMT_STRING
1024 /* Sorted on total connect times */
1025 if (percentile && (requests > 1)) {
1026 printf("\nPercentage of the requests served within a certain time (ms)\n");
1027 for (i = 0; i < sizeof(percs) / sizeof(int); i++)
1029 printf(" 0%% <0> (never)\n");
1030 else if (percs[i] >= 100)
1031 printf(" 100%% %5" APR_TIME_T_FMT " (longest request)\n",
1032 stats[requests - 1].time);
1034 printf(" %d%% %5" APR_TIME_T_FMT "\n", percs[i],
1035 stats[(int) (requests * percs[i] / 100)].time);
1038 FILE *out = fopen(csvperc, "w");
1041 perror("Cannot open CSV output file");
1044 fprintf(out, "" "Percentage served" "," "Time in ms" "\n");
1045 for (i = 0; i < 100; i++) {
1050 t = stats[requests - 1].time;
1052 t = stats[(int) (0.5 + requests * i / 100.0)].time;
1053 fprintf(out, "%d,%e\n", i, (double)t);
1061 /* --------------------------------------------------------- */
1063 /* calculate and output results in HTML */
1065 static void output_html_results(void)
1069 endtime = apr_time_now();
1070 timetaken = (long)((endtime - start) / 1000);
1072 printf("\n\n<table %s>\n", tablestring);
1073 printf("<tr %s><th colspan=2 %s>Server Software:</th>"
1074 "<td colspan=2 %s>%s</td></tr>\n",
1075 trstring, tdstring, tdstring, servername);
1076 printf("<tr %s><th colspan=2 %s>Server Hostname:</th>"
1077 "<td colspan=2 %s>%s</td></tr>\n",
1078 trstring, tdstring, tdstring, hostname);
1079 printf("<tr %s><th colspan=2 %s>Server Port:</th>"
1080 "<td colspan=2 %s>%hd</td></tr>\n",
1081 trstring, tdstring, tdstring, port);
1082 printf("<tr %s><th colspan=2 %s>Document Path:</th>"
1083 "<td colspan=2 %s>%s</td></tr>\n",
1084 trstring, tdstring, tdstring, path);
1085 printf("<tr %s><th colspan=2 %s>Document Length:</th>"
1086 "<td colspan=2 %s>%" APR_SIZE_T_FMT " bytes</td></tr>\n",
1087 trstring, tdstring, tdstring, doclen);
1088 printf("<tr %s><th colspan=2 %s>Concurrency Level:</th>"
1089 "<td colspan=2 %s>%d</td></tr>\n",
1090 trstring, tdstring, tdstring, concurrency);
1091 printf("<tr %s><th colspan=2 %s>Time taken for tests:</th>"
1092 "<td colspan=2 %s>%" APR_INT64_T_FMT ".%03ld seconds</td></tr>\n",
1093 trstring, tdstring, tdstring, apr_time_sec(timetaken),
1094 (long)apr_time_usec(timetaken));
1095 printf("<tr %s><th colspan=2 %s>Complete requests:</th>"
1096 "<td colspan=2 %s>%ld</td></tr>\n",
1097 trstring, tdstring, tdstring, done);
1098 printf("<tr %s><th colspan=2 %s>Failed requests:</th>"
1099 "<td colspan=2 %s>%ld</td></tr>\n",
1100 trstring, tdstring, tdstring, bad);
1102 printf("<tr %s><td colspan=4 %s > (Connect: %d, Length: %d, Exceptions: %d)</td></tr>\n",
1103 trstring, tdstring, err_conn, err_length, err_except);
1105 printf("<tr %s><th colspan=2 %s>Non-2xx responses:</th>"
1106 "<td colspan=2 %s>%d</td></tr>\n",
1107 trstring, tdstring, tdstring, err_response);
1109 printf("<tr %s><th colspan=2 %s>Keep-Alive requests:</th>"
1110 "<td colspan=2 %s>%ld</td></tr>\n",
1111 trstring, tdstring, tdstring, doneka);
1112 printf("<tr %s><th colspan=2 %s>Total transferred:</th>"
1113 "<td colspan=2 %s>%ld bytes</td></tr>\n",
1114 trstring, tdstring, tdstring, totalread);
1116 printf("<tr %s><th colspan=2 %s>Total POSTed:</th>"
1117 "<td colspan=2 %s>%ld</td></tr>\n",
1118 trstring, tdstring, tdstring, totalposted);
1119 printf("<tr %s><th colspan=2 %s>HTML transferred:</th>"
1120 "<td colspan=2 %s>%ld bytes</td></tr>\n",
1121 trstring, tdstring, tdstring, totalbread);
1123 /* avoid divide by zero */
1125 printf("<tr %s><th colspan=2 %s>Requests per second:</th>"
1126 "<td colspan=2 %s>%.2f</td></tr>\n",
1127 trstring, tdstring, tdstring, 1000 * (float) (done) / timetaken);
1128 printf("<tr %s><th colspan=2 %s>Transfer rate:</th>"
1129 "<td colspan=2 %s>%.2f kb/s received</td></tr>\n",
1130 trstring, tdstring, tdstring, (float) (totalread) / timetaken);
1132 printf("<tr %s><td colspan=2 %s> </td>"
1133 "<td colspan=2 %s>%.2f kb/s sent</td></tr>\n",
1134 trstring, tdstring, tdstring,
1135 (float) (totalposted) / timetaken);
1136 printf("<tr %s><td colspan=2 %s> </td>"
1137 "<td colspan=2 %s>%.2f kb/s total</td></tr>\n",
1138 trstring, tdstring, tdstring,
1139 (float) (totalread + totalposted) / timetaken);
1142 /* work out connection times */
1144 apr_interval_time_t totalcon = 0, total = 0;
1145 apr_interval_time_t mincon = AB_MAX, mintot = AB_MAX;
1146 apr_interval_time_t maxcon = 0, maxtot = 0;
1148 for (i = 0; i < requests; i++) {
1149 struct data s = stats[i];
1150 mincon = ap_min(mincon, s.ctime);
1151 mintot = ap_min(mintot, s.time);
1152 maxcon = ap_max(maxcon, s.ctime);
1153 maxtot = ap_max(maxtot, s.time);
1154 totalcon += s.ctime;
1158 if (requests > 0) { /* avoid division by zero (if 0 requests) */
1159 printf("<tr %s><th %s colspan=4>Connnection Times (ms)</th></tr>\n",
1160 trstring, tdstring);
1161 printf("<tr %s><th %s> </th> <th %s>min</th> <th %s>avg</th> <th %s>max</th></tr>\n",
1162 trstring, tdstring, tdstring, tdstring, tdstring);
1163 printf("<tr %s><th %s>Connect:</th>"
1164 "<td %s>%5" APR_TIME_T_FMT "</td>"
1165 "<td %s>%5" APR_TIME_T_FMT "</td>"
1166 "<td %s>%5" APR_TIME_T_FMT "</td></tr>\n",
1167 trstring, tdstring, tdstring, mincon, tdstring, totalcon / requests, tdstring, maxcon);
1168 printf("<tr %s><th %s>Processing:</th>"
1169 "<td %s>%5" APR_TIME_T_FMT "</td>"
1170 "<td %s>%5" APR_TIME_T_FMT "</td>"
1171 "<td %s>%5" APR_TIME_T_FMT "</td></tr>\n",
1172 trstring, tdstring, tdstring, mintot - mincon, tdstring,
1173 (total / requests) - (totalcon / requests), tdstring, maxtot - maxcon);
1174 printf("<tr %s><th %s>Total:</th>"
1175 "<td %s>%5" APR_TIME_T_FMT "</td>"
1176 "<td %s>%5" APR_TIME_T_FMT "</td>"
1177 "<td %s>%5" APR_TIME_T_FMT "</td></tr>\n",
1178 trstring, tdstring, tdstring, mintot, tdstring, total / requests, tdstring, maxtot);
1180 printf("</table>\n");
1184 /* --------------------------------------------------------- */
1186 /* start asnchronous non-blocking connection */
1188 static void start_connect(struct connection * c)
1194 ssl_start_connect(c);
1199 if (!(started < requests))
1209 apr_pool_destroy(c->ctx);
1210 apr_pool_create(&c->ctx, cntxt);
1212 if ((rv = apr_socket_create(&c->aprsock, destsa->family,
1213 SOCK_STREAM, 0, c->ctx)) != APR_SUCCESS) {
1214 apr_err("socket", rv);
1216 if ((rv = apr_socket_opt_set(c->aprsock, APR_SO_NONBLOCK, 1))
1218 apr_err("socket nonblock", rv);
1220 c->start = apr_time_now();
1221 if ((rv = apr_socket_connect(c->aprsock, destsa)) != APR_SUCCESS) {
1222 if (APR_STATUS_IS_EINPROGRESS(rv)) {
1223 apr_pollfd_t new_pollfd;
1224 c->state = STATE_CONNECTING;
1226 new_pollfd.desc_type = APR_POLL_SOCKET;
1227 new_pollfd.reqevents = APR_POLLOUT;
1228 new_pollfd.desc.s = c->aprsock;
1229 new_pollfd.client_data = c;
1230 apr_pollset_add(readbits, &new_pollfd);
1234 apr_pollfd_t remove_pollfd;
1235 remove_pollfd.desc_type = APR_POLL_SOCKET;
1236 remove_pollfd.desc.s = c->aprsock;
1237 apr_pollset_remove(readbits, &remove_pollfd);
1238 apr_socket_close(c->aprsock);
1242 "\nTest aborted after 10 failures\n\n");
1243 apr_err("apr_socket_connect()", rv);
1245 c->state = STATE_UNCONNECTED;
1251 /* connected first time */
1252 c->state = STATE_CONNECTED;
1257 /* --------------------------------------------------------- */
1259 /* close down connection and save stats */
1261 static void close_connection(struct connection * c)
1263 if (c->read == 0 && c->keepalive) {
1265 * server has legitimately shut down an idle keep alive request
1268 good--; /* connection never happened */
1272 /* first time here */
1275 else if (c->bread != doclen) {
1280 if (done < requests) {
1282 if ((done) && heartbeatres && !(done % heartbeatres)) {
1283 fprintf(stderr, "Completed %ld requests\n", done);
1286 c->done = apr_time_now();
1288 s.starttime = c->start;
1289 s.ctime = (c->connect - c->start) / 1000;
1290 s.time = (c->done - c->start) / 1000;
1291 s.waittime = (c->beginread - c->endwrite) / 1000;
1298 SSL_shutdown(c->ssl);
1304 apr_pollfd_t remove_pollfd;
1305 remove_pollfd.desc_type = APR_POLL_SOCKET;
1306 remove_pollfd.desc.s = c->aprsock;
1307 apr_pollset_remove(readbits, &remove_pollfd);
1308 apr_socket_close(c->aprsock);
1310 c->state = STATE_UNCONNECTED;
1317 /* --------------------------------------------------------- */
1319 /* read data from connection */
1321 static void read_connection(struct connection * c)
1324 apr_status_t status;
1326 char respcode[4]; /* 3 digits and null */
1332 status = SSL_read (c->ssl, buffer, r);
1334 good++; c->read = 0;
1335 if (status < 0) printf("SSL read failed - closing connection\n");
1336 close_connection(c);
1343 status = apr_socket_recv(c->aprsock, buffer, &r);
1344 if (APR_STATUS_IS_EAGAIN(status))
1346 else if (r == 0 && APR_STATUS_IS_EOF(status)) {
1348 close_connection(c);
1351 /* catch legitimate fatal apr_socket_recv errors */
1352 else if (status != APR_SUCCESS) {
1353 err_except++; /* XXX: is this the right error counter? */
1354 /* XXX: Should errors here be fatal, or should we allow a
1355 * certain number of them before completely failing? -aaron */
1356 apr_err("apr_socket_recv", status);
1364 c->beginread = apr_time_now();
1369 if (!c->gotheader) {
1372 apr_size_t space = CBUFFSIZE - c->cbx - 1; /* -1 allows for \0 term */
1373 int tocopy = (space < r) ? space : r;
1375 apr_size_t inbytes_left = space, outbytes_left = space;
1377 status = apr_xlate_conv_buffer(from_ascii, buffer, &inbytes_left,
1378 c->cbuff + c->cbx, &outbytes_left);
1379 if (status || inbytes_left || outbytes_left) {
1380 fprintf(stderr, "only simple translation is supported (%d/%u/%u)\n",
1381 status, inbytes_left, outbytes_left);
1385 memcpy(c->cbuff + c->cbx, buffer, space);
1386 #endif /* NOT_ASCII */
1389 c->cbuff[c->cbx] = 0; /* terminate for benefit of strstr */
1390 if (verbosity >= 2) {
1391 printf("LOG: header received:\n%s\n", c->cbuff);
1393 s = strstr(c->cbuff, "\r\n\r\n");
1395 * this next line is so that we talk to NCSA 1.5 which blatantly
1396 * breaks the http specifaction
1399 s = strstr(c->cbuff, "\n\n");
1404 /* read rest next time */
1409 /* header is in invalid or too big - close connection */
1410 apr_pollfd_t remove_pollfd;
1411 remove_pollfd.desc_type = APR_POLL_SOCKET;
1412 remove_pollfd.desc.s = c->aprsock;
1413 apr_pollset_remove(readbits, &remove_pollfd);
1414 apr_socket_close(c->aprsock);
1417 err("\nTest aborted after 10 failures\n\n");
1423 /* have full header */
1426 * this is first time, extract some interesting info
1429 p = strstr(c->cbuff, "Server:");
1439 * XXX: this parsing isn't even remotely HTTP compliant... but in
1440 * the interest of speed it doesn't totally have to be, it just
1441 * needs to be extended to handle whatever servers folks want to
1442 * test against. -djg
1445 /* check response code */
1446 part = strstr(c->cbuff, "HTTP"); /* really HTTP/1.x_ */
1447 if (part && strlen(part) > strlen("HTTP/1.x_")) {
1448 strncpy(respcode, (part + strlen("HTTP/1.x_")), 3);
1452 strcpy(respcode, "500");
1455 if (respcode[0] != '2') {
1458 printf("WARNING: Response code not 2xx (%s)\n", respcode);
1460 else if (verbosity >= 3) {
1461 printf("LOG: Response code = %s\n", respcode);
1464 *s = 0; /* terminate at end of header */
1466 (strstr(c->cbuff, "Keep-Alive")
1467 || strstr(c->cbuff, "keep-alive"))) { /* for benefit of MSIIS */
1469 cl = strstr(c->cbuff, "Content-Length:");
1470 /* handle NCSA, which sends Content-length: */
1472 cl = strstr(c->cbuff, "Content-length:");
1475 c->length = atoi(cl + 16);
1478 c->bread += c->cbx - (s + l - c->cbuff) + r - tocopy;
1479 totalbread += c->bread;
1483 /* outside header, everything we have read is entity body */
1488 if (c->keepalive && (c->bread >= c->length)) {
1489 /* finished a keep-alive connection */
1494 /* first time here */
1497 else if (c->bread != doclen) {
1501 if (done < requests) {
1503 if (done && heartbeatres && !(done % heartbeatres)) {
1504 fprintf(stderr, "Completed %ld requests\n", done);
1507 c->done = apr_time_now();
1509 s.starttime = c->start;
1510 s.ctime = (c->connect - c->start) / 1000;
1511 s.waittime = (c->beginread - c->endwrite) / 1000;
1512 s.time = (c->done - c->start) / 1000;
1519 c->read = c->bread = 0;
1521 c->start = c->connect; /* zero connect time with keep-alive */
1525 /* --------------------------------------------------------- */
1529 static void test(void)
1534 apr_status_t status;
1536 apr_size_t inbytes_left, outbytes_left;
1540 connecthost = apr_pstrdup(cntxt, proxyhost);
1541 connectport = proxyport;
1544 connecthost = apr_pstrdup(cntxt, hostname);
1549 printf("Benchmarking %s ", hostname);
1551 printf("[through %s:%d] ", proxyhost, proxyport);
1552 printf("(be patient)%s",
1553 (heartbeatres ? "\n" : "..."));
1557 now = apr_time_now();
1559 con = calloc(concurrency * sizeof(struct connection), 1);
1561 stats = calloc(requests * sizeof(struct data), 1);
1562 apr_pollset_create(&readbits, concurrency, cntxt, 0);
1566 sprintf(request, "%s %s HTTP/1.0\r\n"
1567 "User-Agent: ApacheBench/%s\r\n"
1572 (posting == 0) ? "GET" : "HEAD",
1573 (isproxy) ? fullurl : path,
1575 keepalive ? "Connection: Keep-Alive\r\n" : "",
1576 cookie, auth, host_field, colonhost, hdrs);
1579 sprintf(request, "POST %s HTTP/1.0\r\n"
1580 "User-Agent: ApacheBench/%s\r\n"
1584 "Content-length: %" APR_SIZE_T_FMT "\r\n"
1585 "Content-type: %s\r\n"
1588 (isproxy) ? fullurl : path,
1590 keepalive ? "Connection: Keep-Alive\r\n" : "",
1592 host_field, colonhost, postlen,
1593 (content_type[0]) ? content_type : "text/plain", hdrs);
1597 printf("INFO: POST header == \n---\n%s\n---\n", request);
1599 reqlen = strlen(request);
1602 * Combine headers and (optional) post file into one contineous buffer
1605 char *buff = malloc(postlen + reqlen + 1);
1607 fprintf(stderr, "error creating request buffer: out of memory\n");
1610 strcpy(buff, request);
1611 strcpy(buff + reqlen, postdata);
1616 inbytes_left = outbytes_left = reqlen;
1617 status = apr_xlate_conv_buffer(to_ascii, request, &inbytes_left,
1618 request, &outbytes_left);
1619 if (status || inbytes_left || outbytes_left) {
1620 fprintf(stderr, "only simple translation is supported (%d/%u/%u)\n",
1621 status, inbytes_left, outbytes_left);
1624 #endif /* NOT_ASCII */
1626 /* This only needs to be done once */
1630 if ((rv = apr_sockaddr_info_get(&destsa, connecthost, APR_UNSPEC, connectport, 0, cntxt))
1633 apr_snprintf(buf, sizeof(buf),
1634 "apr_sockaddr_info_get() for %s", connecthost);
1638 /* ok - lets start */
1639 start = apr_time_now();
1641 /* initialise lots of requests */
1642 for (i = 0; i < concurrency; i++) {
1644 start_connect(&con[i]);
1647 while (done < requests) {
1650 const apr_pollfd_t *pollresults;
1652 /* check for time limit expiry */
1653 now = apr_time_now();
1654 timed = (apr_int32_t)apr_time_sec(now - start);
1655 if (tlimit && timed >= tlimit) {
1656 requests = done; /* so stats are correct */
1657 break; /* no need to do another round */
1663 status = APR_SUCCESS;
1666 status = apr_pollset_poll(readbits, aprtimeout, &n, &pollresults);
1667 if (status != APR_SUCCESS)
1668 apr_err("apr_poll", status);
1671 err("\nServer timed out\n\n");
1674 for (i = 0; i < n; i++) {
1675 const apr_pollfd_t *next_fd = &(pollresults[i]);
1676 struct connection *c;
1683 c = next_fd->client_data;
1686 * If the connection isn't connected how can we check it?
1688 if (c->state == STATE_UNCONNECTED)
1696 rv = next_fd->rtnevents;
1699 * Notes: APR_POLLHUP is set after FIN is received on some
1700 * systems, so treat that like APR_POLLIN so that we try to read
1703 * Some systems return APR_POLLERR with APR_POLLHUP. We need to
1704 * call read_connection() for APR_POLLHUP, so check for
1705 * APR_POLLHUP first so that a closed connection isn't treated
1706 * like an I/O error. If it is, we never figure out that the
1707 * connection is done and we loop here endlessly calling
1710 if ((rv & APR_POLLIN) || (rv & APR_POLLPRI) || (rv & APR_POLLHUP))
1712 if ((rv & APR_POLLERR) || (rv & APR_POLLNVAL)) {
1718 if (rv & APR_POLLOUT) {
1719 if (c->state == STATE_CONNECTING) {
1720 apr_pollfd_t remove_pollfd;
1721 rv = apr_socket_connect(c->aprsock, destsa);
1722 remove_pollfd.desc_type = APR_POLL_SOCKET;
1723 remove_pollfd.desc.s = c->aprsock;
1724 apr_pollset_remove(readbits, &remove_pollfd);
1725 if (rv != APR_SUCCESS) {
1726 apr_socket_close(c->aprsock);
1730 "\nTest aborted after 10 failures\n\n");
1731 apr_err("apr_socket_connect()", rv);
1733 c->state = STATE_UNCONNECTED;
1738 c->state = STATE_CONNECTED;
1748 * When using a select based poll every time we check the bits
1749 * are reset. In 1.3's ab we copied the FD_SET's each time
1750 * through, but here we're going to check the state and if the
1751 * connection is in STATE_READ or STATE_CONNECTING we'll add the
1752 * socket back in as APR_POLLIN.
1757 if (c->state == STATE_READ) {
1758 apr_pollfd_t new_pollfd;
1759 new_pollfd.desc_type = APR_POLL_SOCKET;
1760 new_pollfd.reqevents = APR_POLLIN;
1761 new_pollfd.desc.s = c->aprsock;
1762 new_pollfd.client_data = c;
1763 apr_pollset_add(readbits, &new_pollfd);
1769 fprintf(stderr, "Finished %ld requests\n", done);
1774 output_html_results();
1779 /* ------------------------------------------------------- */
1781 /* display copyright information */
1782 static void copyright(void)
1785 printf("This is ApacheBench, Version %s\n", AP_AB_BASEREVISION " <$Revision: 1.137 $> apache-2.0");
1786 printf("Copyright (c) 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/\n");
1787 printf("Copyright (c) 1998-2002 The Apache Software Foundation, http://www.apache.org/\n");
1792 printf(" This is ApacheBench, Version %s <i><%s></i> apache-2.0<br>\n", AP_AB_BASEREVISION, "$Revision: 1.137 $");
1793 printf(" Copyright (c) 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/<br>\n");
1794 printf(" Copyright (c) 1998-2002 The Apache Software Foundation, http://www.apache.org/<br>\n");
1795 printf("</p>\n<p>\n");
1799 /* display usage information */
1800 static void usage(const char *progname)
1802 fprintf(stderr, "Usage: %s [options] [http"
1806 "://]hostname[:port]/path\n", progname);
1807 fprintf(stderr, "Options are:\n");
1808 fprintf(stderr, " -n requests Number of requests to perform\n");
1809 fprintf(stderr, " -c concurrency Number of multiple requests to make\n");
1810 fprintf(stderr, " -t timelimit Seconds to max. wait for responses\n");
1811 fprintf(stderr, " -p postfile File containing data to POST\n");
1812 fprintf(stderr, " -T content-type Content-type header for POSTing\n");
1813 fprintf(stderr, " -v verbosity How much troubleshooting info to print\n");
1814 fprintf(stderr, " -w Print out results in HTML tables\n");
1815 fprintf(stderr, " -i Use HEAD instead of GET\n");
1816 fprintf(stderr, " -x attributes String to insert as table attributes\n");
1817 fprintf(stderr, " -y attributes String to insert as tr attributes\n");
1818 fprintf(stderr, " -z attributes String to insert as td or th attributes\n");
1819 fprintf(stderr, " -C attribute Add cookie, eg. 'Apache=1234. (repeatable)\n");
1820 fprintf(stderr, " -H attribute Add Arbitrary header line, eg. 'Accept-Encoding: gzip'\n");
1821 fprintf(stderr, " Inserted after all normal header lines. (repeatable)\n");
1822 fprintf(stderr, " -A attribute Add Basic WWW Authentication, the attributes\n");
1823 fprintf(stderr, " are a colon separated username and password.\n");
1824 fprintf(stderr, " -P attribute Add Basic Proxy Authentication, the attributes\n");
1825 fprintf(stderr, " are a colon separated username and password.\n");
1826 fprintf(stderr, " -X proxy:port Proxyserver and port number to use\n");
1827 fprintf(stderr, " -V Print version number and exit\n");
1828 fprintf(stderr, " -k Use HTTP KeepAlive feature\n");
1829 fprintf(stderr, " -d Do not show percentiles served table.\n");
1830 fprintf(stderr, " -S Do not show confidence estimators and warnings.\n");
1831 fprintf(stderr, " -g filename Output collected data to gnuplot format file.\n");
1832 fprintf(stderr, " -e filename Output CSV file with percentages served\n");
1834 fprintf(stderr, " -s Use httpS instead of HTTP (SSL)\n");
1836 fprintf(stderr, " -h Display usage information (this message)\n");
1840 /* ------------------------------------------------------- */
1842 /* split URL into parts */
1844 static int parse_url(char *url)
1851 /* Save a copy for the proxy */
1852 fullurl = apr_pstrdup(cntxt, url);
1854 if (strlen(url) > 7 && strncmp(url, "http://", 7) == 0) {
1862 if (strlen(url) > 8 && strncmp(url, "https://", 8) == 0) {
1867 if (strlen(url) > 8 && strncmp(url, "https://", 8) == 0) {
1868 fprintf(stderr, "SSL not compiled in; no https support\n");
1873 if ((cp = strchr(url, '/')) == NULL)
1875 h = apr_palloc(cntxt, cp - url + 1);
1876 memcpy(h, url, cp - url);
1878 rv = apr_parse_addr_port(&hostname, &scope_id, &port, h, cntxt);
1879 if (rv != APR_SUCCESS || !hostname || scope_id) {
1882 path = apr_pstrdup(cntxt, cp);
1884 if (*url == '[') { /* IPv6 numeric address string */
1885 host_field = apr_psprintf(cntxt, "[%s]", hostname);
1888 host_field = hostname;
1891 if (port == 0) { /* no port specified */
1902 (ssl == 1) && (port != 443)) || (( ssl == 0 ) &&
1906 colonhost = apr_psprintf(cntxt,":%d",port);
1912 /* ------------------------------------------------------- */
1914 /* read data to POST from file, save contents and length */
1916 static int open_postfile(const char *pfile)
1918 apr_file_t *postfd = NULL;
1920 apr_fileperms_t mode = APR_OS_DEFAULT;
1925 rv = apr_file_open(&postfd, pfile, APR_READ, mode, cntxt);
1926 if (rv != APR_SUCCESS) {
1927 printf("Invalid postfile name (%s): %s\n", pfile,
1928 apr_strerror(rv, errmsg, sizeof errmsg));
1932 apr_file_info_get(&finfo, APR_FINFO_NORM, postfd);
1933 postlen = (apr_size_t)finfo.size;
1934 postdata = (char *) malloc(postlen);
1936 printf("Can\'t alloc postfile buffer\n");
1940 rv = apr_file_read(postfd, postdata, &length);
1941 if (rv != APR_SUCCESS) {
1942 printf("error reading postfile: %s\n",
1943 apr_strerror(rv, errmsg, sizeof errmsg));
1946 if (length != postlen) {
1947 printf("error reading postfile: read only %"
1948 APR_SIZE_T_FMT " bytes",
1952 apr_file_close(postfd);
1956 /* ------------------------------------------------------- */
1958 /* sort out command-line args and call test */
1959 int main(int argc, const char * const argv[])
1963 apr_status_t status;
1968 /* table defaults */
1971 tdstring = "bgcolor=white";
1974 proxyhost[0] = '\0';
1977 apr_app_initialize(&argc, &argv, NULL);
1978 atexit(apr_terminate);
1979 apr_pool_create(&cntxt, NULL);
1982 status = apr_xlate_open(&to_ascii, "ISO8859-1", APR_DEFAULT_CHARSET, cntxt);
1984 fprintf(stderr, "apr_xlate_open(to ASCII)->%d\n", status);
1987 status = apr_xlate_open(&from_ascii, APR_DEFAULT_CHARSET, "ISO8859-1", cntxt);
1989 fprintf(stderr, "apr_xlate_open(from ASCII)->%d\n", status);
1992 status = apr_base64init_ebcdic(to_ascii, from_ascii);
1994 fprintf(stderr, "apr_base64init_ebcdic()->%d\n", status);
1999 apr_getopt_init(&opt, cntxt, argc, argv);
2000 while ((status = apr_getopt(opt, "n:c:t:T:p:v:kVhwix:y:z:C:H:P:A:g:X:de:Sq"
2004 ,&c, &optarg)) == APR_SUCCESS) {
2011 fprintf(stderr, "SSL not compiled in; no https support\n");
2015 requests = atoi(optarg);
2017 err("Invalid number of requests\n");
2027 concurrency = atoi(optarg);
2031 err("Cannot mix POST and HEAD\n");
2035 gnuplot = strdup(optarg);
2041 csvperc = strdup(optarg);
2048 err("Cannot mix POST and HEAD\n");
2050 if (0 == (r = open_postfile(optarg))) {
2053 else if (postdata) {
2058 verbosity = atoi(optarg);
2061 tlimit = atoi(optarg);
2062 requests = MAX_REQUESTS; /* need to size data array on
2066 strcpy(content_type, optarg);
2069 cookie = apr_pstrcat(cntxt, "Cookie: ", optarg, "\r\n", NULL);
2073 * assume username passwd already to be in colon separated form.
2074 * Ready to be uu-encoded.
2076 while (apr_isspace(*optarg))
2078 if (apr_base64_encode_len(strlen(optarg)) > sizeof(tmp)) {
2079 err("Authentication credentials too long\n");
2081 l = apr_base64_encode(tmp, optarg, strlen(optarg));
2084 auth = apr_pstrcat(cntxt, auth, "Authorization: Basic ", tmp,
2089 * assume username passwd already to be in colon separated form.
2091 while (apr_isspace(*optarg))
2093 if (apr_base64_encode_len(strlen(optarg)) > sizeof(tmp)) {
2094 err("Proxy credentials too long\n");
2096 l = apr_base64_encode(tmp, optarg, strlen(optarg));
2099 auth = apr_pstrcat(cntxt, auth, "Proxy-Authorization: Basic ",
2103 hdrs = apr_pstrcat(cntxt, hdrs, optarg, "\r\n", NULL);
2109 * if any of the following three are used, turn on html output
2114 tablestring = optarg;
2120 * assume proxy-name[:port]
2122 if ((p = strchr(optarg, ':'))) {
2125 proxyport = atoi(p);
2127 strcpy(proxyhost, optarg);
2148 if (opt->ind != argc - 1) {
2149 fprintf(stderr, "%s: wrong number of arguments\n", argv[0]);
2153 if (parse_url(apr_pstrdup(cntxt, opt->argv[opt->ind++]))) {
2154 fprintf(stderr, "%s: invalid URL\n", argv[0]);
2159 if ((heartbeatres) && (requests > 150)) {
2160 heartbeatres = requests / 10; /* Print line every 10% of requests */
2161 if (heartbeatres < 100)
2162 heartbeatres = 100; /* but never more often than once every 100
2172 CRYPTO_malloc_init();
2174 SSL_load_error_strings();
2176 bio_out=BIO_new_fp(stdout,BIO_NOCLOSE);
2177 bio_err=BIO_new_fp(stderr,BIO_NOCLOSE);
2179 /* TODO: Allow force SSLv2_client_method() (TLSv1?) */
2180 if (!(ctx = SSL_CTX_new(SSLv23_client_method()))) {
2181 fprintf(stderr, "Could not init SSL CTX");
2182 ERR_print_errors_fp(stderr);
2185 SSL_CTX_set_options(ctx, SSL_OP_ALL);
2187 ssl_util_thread_setup(cntxt);
2191 apr_signal(SIGPIPE, SIG_IGN); /* Ignore writes to connections that
2192 * have been closed at the other end. */
2196 apr_pool_destroy(cntxt);