]> granicus.if.org Git - apache/blob - support/ab.c
Switched ab to the new abstract pollset API (this will
[apache] / support / ab.c
1 /* ====================================================================
2  * The Apache Software License, Version 1.1
3  *
4  * Copyright (c) 2000-2002 The Apache Software Foundation.  All rights
5  * reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  *
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in
16  *    the documentation and/or other materials provided with the
17  *    distribution.
18  *
19  * 3. The end-user documentation included with the redistribution,
20  *    if any, must include the following acknowledgment:
21  *       "This product includes software developed by the
22  *        Apache Software Foundation (http://www.apache.org/)."
23  *    Alternately, this acknowledgment may appear in the software itself,
24  *    if and wherever such third-party acknowledgments normally appear.
25  *
26  * 4. The names "Apache" and "Apache Software Foundation" must
27  *    not be used to endorse or promote products derived from this
28  *    software without prior written permission. For written
29  *    permission, please contact apache@apache.org.
30  *
31  * 5. Products derived from this software may not be called "Apache",
32  *    nor may "Apache" appear in their name, without prior written
33  *    permission of the Apache Software Foundation.
34  *
35  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
36  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
37  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
38  * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
39  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
41  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
42  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
43  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
44  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
45  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
46  * SUCH DAMAGE.
47  * ====================================================================
48  *
49  * This software consists of voluntary contributions made by many
50  * individuals on behalf of the Apache Software Foundation.  For more
51  * information on the Apache Software Foundation, please see
52  * <http://www.apache.org/>.
53  *
54  * Portions of this software are based upon public domain software
55  * originally written at the National Center for Supercomputing Applications,
56  * University of Illinois, Urbana-Champaign.
57  */
58
59 /*
60    ** This program is based on ZeusBench V1.0 written by Adam Twiss
61    ** which is Copyright (c) 1996 by Zeus Technology Ltd. http://www.zeustech.net/
62    **
63    ** This software is provided "as is" and any express or implied waranties,
64    ** including but not limited to, the implied warranties of merchantability and
65    ** fitness for a particular purpose are disclaimed.  In no event shall
66    ** Zeus Technology Ltd. be liable for any direct, indirect, incidental, special,
67    ** exemplary, or consequential damaged (including, but not limited to,
68    ** procurement of substitute good or services; loss of use, data, or profits;
69    ** or business interruption) however caused and on theory of liability.  Whether
70    ** in contract, strict liability or tort (including negligence or otherwise)
71    ** arising in any way out of the use of this software, even if advised of the
72    ** possibility of such damage.
73    **
74  */
75
76 /*
77    ** HISTORY:
78    **    - Originally written by Adam Twiss <adam@zeus.co.uk>, March 1996
79    **      with input from Mike Belshe <mbelshe@netscape.com> and
80    **      Michael Campanella <campanella@stevms.enet.dec.com>
81    **    - Enhanced by Dean Gaudet <dgaudet@apache.org>, November 1997
82    **    - Cleaned up by Ralf S. Engelschall <rse@apache.org>, March 1998
83    **    - POST and verbosity by Kurt Sussman <kls@merlot.com>, August 1998
84    **    - HTML table output added by David N. Welton <davidw@prosa.it>, January 1999
85    **    - Added Cookie, Arbitrary header and auth support. <dirkx@webweaving.org>, April 1999
86    ** Version 1.3d
87    **    - Increased version number - as some of the socket/error handling has
88    **      fundamentally changed - and will give fundamentally different results
89    **      in situations where a server is dropping requests. Therefore you can
90    **      no longer compare results of AB as easily. Hence the inc of the version.
91    **      They should be closer to the truth though. Sander & <dirkx@covalent.net>, End 2000.
92    **    - Fixed proxy functionality, added median/mean statistics, added gnuplot
93    **      output option, added _experimental/rudimentary_ SSL support. Added
94    **      confidence guestimators and warnings. Sander & <dirkx@covalent.net>, End 2000
95    **    - Fixed serious int overflow issues which would cause realistic (longer
96    **      than a few minutes) run's to have wrong (but believable) results. Added
97    **      trapping of connection errors which influenced measurements.
98    **      Contributed by Sander Temme, Early 2001
99    ** Version 1.3e
100    **    - Changed timeout behavour during write to work whilst the sockets
101    **      are filling up and apr_write() does writes a few - but not all.
102    **      This will potentially change results. <dirkx@webweaving.org>, April 2001
103    ** Version 2.0.36-dev
104    **    Improvements to concurrent processing:
105    **      - Enabled non-blocking connect()s.
106    **      - Prevent blocking calls to apr_recv() (thereby allowing AB to
107    **        manage its entire set of socket descriptors).
108    **      - Any error returned from apr_recv() that is not EAGAIN or EOF
109    **        is now treated as fatal.
110    **      Contributed by Aaron Bannert, April 24, 2002
111    **
112    ** Version 2.0.36-2
113    **     Internalized the version string - this string is part
114    **     of the Agent: header and the result output.
115    **
116    ** Version 2.0.37-dev
117    **     Adopted SSL code by Madhu Mathihalli <madhusudan_mathihalli@hp.com>
118    **     [PATCH] ab with SSL support  Posted Wed, 15 Aug 2001 20:55:06 GMT
119    **     Introduces four 'if (int == value)' tests per non-ssl request.
120    **/
121
122 /* Note: this version string should start with \d+[\d\.]* and be a valid
123  * string for an HTTP Agent: header when prefixed with 'ApacheBench/'. 
124  * It should reflect the version of AB - and not that of the apache server 
125  * it happens to accompany. And it should be updated or changed whenever 
126  * the results are no longer fundamentally comparable to the results of 
127  * a previous version of ab. Either due to a change in the logic of
128  * ab - or to due to a change in the distribution it is compiled with 
129  * (such as an APR change in for example blocking).
130  */
131 #define AP_AB_BASEREVISION "2.0.40-dev"    
132
133 /*
134  * BUGS:
135  *
136  * - uses strcpy/etc.
137  * - has various other poor buffer attacks related to the lazy parsing of
138  *   response headers from the server
139  * - doesn't implement much of HTTP/1.x, only accepts certain forms of
140  *   responses
141  * - (performance problem) heavy use of strstr shows up top in profile
142  *   only an issue for loopback usage
143  */
144
145 /*  -------------------------------------------------------------------- */
146
147 #if 'A' != 0x41
148 /* Hmmm... This source code isn't being compiled in ASCII.
149  * In order for data that flows over the network to make
150  * sense, we need to translate to/from ASCII.
151  */
152 #define NOT_ASCII
153 #endif
154
155 /* affects include files on Solaris */
156 #define BSD_COMP
157
158 #include "apr.h"
159 #include "apr_signal.h"
160 #include "apr_strings.h"
161 #include "apr_network_io.h"
162 #include "apr_file_io.h"
163 #include "apr_time.h"
164 #include "apr_getopt.h"
165 #include "apr_general.h"
166 #include "apr_lib.h"
167 #include "apr_portable.h"
168 #include "ap_release.h"
169 #include "apr_poll.h"
170
171 #define APR_WANT_STRFUNC
172 #include "apr_want.h"
173
174 #include "apr_base64.h"
175 #ifdef NOT_ASCII
176 #include "apr_xlate.h"
177 #endif
178 #if APR_HAVE_STDIO_H
179 #include <stdio.h>
180 #endif
181 #if APR_HAVE_STDLIB_H
182 #include <stdlib.h>
183
184 #ifdef  USE_SSL
185 #if ((!(RSAREF)) && (!(SYSSSL)))
186 /* Libraries on most systems.. */
187 #include <openssl/rsa.h>
188 #include <openssl/crypto.h>
189 #include <openssl/x509.h>
190 #include <openssl/pem.h>
191 #include <openssl/err.h>
192 #include <openssl/ssl.h>
193 #include <openssl/rand.h>
194 #else
195 /* Libraries for RSAref and SYSSSL */
196 #include <rsa.h>
197 #include <crypto.h>
198 #include <x509.h>
199 #include <pem.h>
200 #include <err.h>
201 #include <ssl.h>
202 #include <rand.h>
203 #endif
204 #endif
205
206 #include <math.h>
207 #endif
208 #if APR_HAVE_CTYPE_H
209 #include <ctype.h>
210 #endif
211
212 /* ------------------- DEFINITIONS -------------------------- */
213
214 #ifndef LLONG_MAX
215 #define AB_MAX APR_INT64_C(0x7fffffffffffffff)
216 #else
217 #define AB_MAX LLONG_MAX
218 #endif
219
220 /* maximum number of requests on a time limited test */
221 #define MAX_REQUESTS 50000
222
223 /* good old state hostname */
224 #define STATE_UNCONNECTED 0
225 #define STATE_CONNECTING  1
226 #define STATE_READ        2
227
228 #define CBUFFSIZE (2048)
229
230 struct connection {
231     apr_pool_t *ctx;
232     apr_socket_t *aprsock;
233     int state;
234     apr_size_t read;            /* amount of bytes read */
235     apr_size_t bread;           /* amount of body read */
236     apr_size_t rwrite, rwrote;  /* keep pointers in what we write - across
237                                  * EAGAINs */
238     apr_size_t length;          /* Content-Length value used for keep-alive */
239     char cbuff[CBUFFSIZE];      /* a buffer to store server response header */
240     int cbx;                    /* offset in cbuffer */
241     int keepalive;              /* non-zero if a keep-alive request */
242     int gotheader;              /* non-zero if we have the entire header in
243                                  * cbuff */
244     apr_time_t start,           /* Start of connection */
245                connect,         /* Connected, start writing */
246                endwrite,        /* Request written */
247                beginread,       /* First byte of input */
248                done;            /* Connection closed */
249
250     int socknum;
251 #ifdef USE_SSL
252     SSL *ssl;
253 #endif
254 };
255
256 struct data {
257 #ifdef USE_SSL
258     /* XXXX insert SSL timings */
259 #endif
260     int read;              /* number of bytes read */
261     apr_time_t starttime;  /* start time of connection in seconds since
262                             * Jan. 1, 1970 */
263     apr_interval_time_t waittime;   /* Between writing request and reading
264                                      * response */
265     apr_interval_time_t ctime;      /* time in ms to connect */
266     apr_interval_time_t time;       /* time in ms for connection */
267 };
268
269 #define ap_min(a,b) ((a)<(b))?(a):(b)
270 #define ap_max(a,b) ((a)>(b))?(a):(b)
271
272 /* --------------------- GLOBALS ---------------------------- */
273
274 int verbosity = 0;              /* no verbosity by default */
275 int posting = 0;                /* GET by default */
276 int requests = 1;               /* Number of requests to make */
277 int heartbeatres = 100;         /* How often do we say we're alive */
278 int concurrency = 1;            /* Number of multiple requests to make */
279 int percentile = 1;             /* Show percentile served */
280 int confidence = 1;             /* Show confidence estimator and warnings */
281 int tlimit = 0;                 /* time limit in secs */
282 int keepalive = 0;              /* try and do keepalive connections */
283 char servername[1024];          /* name that server reports */
284 char *hostname;                 /* host name from URL */
285 char *host_field;               /* value of "Host:" header field */
286 char path[1024];                /* path name */
287 char postfile[1024];            /* name of file containing post data */
288 char *postdata;                 /* *buffer containing data from postfile */
289 apr_size_t postlen = 0;         /* length of data to be POSTed */
290 char content_type[1024];        /* content type to put in POST header */
291 char cookie[1024],              /* optional cookie line */
292      auth[1024],                /* optional (basic/uuencoded)
293                                  * authentification */
294      hdrs[4096];                /* optional arbitrary headers */
295 apr_port_t port;                /* port number */
296 char proxyhost[1024];           /* proxy host name */
297 int proxyport = 0;              /* proxy port */
298 char connecthost[1024];
299 apr_port_t connectport;
300 char *gnuplot;                  /* GNUplot file */
301 char *csvperc;                  /* CSV Percentile file */
302 char url[1024];
303 char * fullurl, * colonhost;
304 int isproxy = 0;
305 apr_interval_time_t aprtimeout = apr_time_from_sec(30); /* timeout value */
306  /*
307   * XXX - this is now a per read/write transact type of value
308   */
309
310 int use_html = 0;               /* use html in the report */
311 const char *tablestring;
312 const char *trstring;
313 const char *tdstring;
314
315 apr_size_t doclen = 0;          /* the length the document should be */
316 long started = 0;               /* number of requests started, so no excess */
317 long totalread = 0;             /* total number of bytes read */
318 long totalbread = 0;            /* totoal amount of entity body read */
319 long totalposted = 0;           /* total number of bytes posted, inc. headers */
320 long done = 0;                  /* number of requests we have done */
321 long doneka = 0;                /* number of keep alive connections done */
322 long good = 0, bad = 0;         /* number of good and bad requests */
323 long epipe = 0;                 /* number of broken pipe writes */
324
325 #ifdef USE_SSL
326 int ssl = 0;
327 SSL_CTX *ctx;
328 BIO *bio_out,*bio_err;
329 static void write_request(struct connection * c);
330 #endif
331
332 /* store error cases */
333 int err_length = 0, err_conn = 0, err_except = 0;
334 int err_response = 0;
335
336 apr_time_t start, endtime;
337
338 /* global request (and its length) */
339 char _request[512];
340 char *request = _request;
341 apr_size_t reqlen;
342
343 /* one global throw-away buffer to read stuff into */
344 char buffer[8192];
345
346 /* interesting percentiles */
347 int percs[] = {50, 66, 75, 80, 90, 95, 98, 99, 100};
348
349 struct connection *con;         /* connection array */
350 struct data *stats;             /* date for each request */
351 apr_pool_t *cntxt;
352
353 apr_pollset_t *readbits;
354
355 apr_sockaddr_t *destsa;
356
357 #ifdef NOT_ASCII
358 apr_xlate_t *from_ascii, *to_ascii;
359 #endif
360
361 static void close_connection(struct connection * c);
362 /* --------------------------------------------------------- */
363
364 /* simple little function to write an error string and exit */
365
366 static void err(char *s)
367 {
368     fprintf(stderr, "%s\n", s);
369     if (done)
370         printf("Total of %ld requests completed\n" , done);
371     exit(1);
372 }
373
374 /* simple little function to write an APR error string and exit */
375
376 static void apr_err(char *s, apr_status_t rv)
377 {
378     char buf[120];
379
380     fprintf(stderr,
381             "%s: %s (%d)\n",
382             s, apr_strerror(rv, buf, sizeof buf), rv);
383     if (done)
384         printf("Total of %ld requests completed\n" , done);
385     exit(rv);
386 }
387
388 #if defined(USE_SSL) && USE_THREADS
389 /*
390  * To ensure thread-safetyness in OpenSSL - work in progress
391  */
392
393 static apr_thread_mutex_t **lock_cs;
394 static int                  lock_num_locks;
395
396 static void ssl_util_thr_lock(int mode, int type,
397                               const char *file, int line)
398 {
399     if (type < lock_num_locks) {
400         if (mode & CRYPTO_LOCK) {
401             apr_thread_mutex_lock(lock_cs[type]);
402         }
403         else {
404             apr_thread_mutex_unlock(lock_cs[type]);
405         }
406     }
407 }
408
409 static unsigned long ssl_util_thr_id(void)
410 {
411     /* OpenSSL needs this to return an unsigned long.  On OS/390, the pthread 
412      * id is a structure twice that big.  Use the TCB pointer instead as a 
413      * unique unsigned long.
414      */
415 #ifdef __MVS__
416     struct PSA {
417         char unmapped[540];
418         unsigned long PSATOLD;
419     } *psaptr = 0;
420
421     return psaptr->PSATOLD;
422 #else
423     return (unsigned long) apr_os_thread_current();
424 #endif
425 }
426
427 static apr_status_t ssl_util_thread_cleanup(void *data)
428 {
429     CRYPTO_set_locking_callback(NULL);
430
431     /* Let the registered mutex cleanups do their own thing 
432      */
433     return APR_SUCCESS;
434 }
435
436 void ssl_util_thread_setup(apr_pool_t *p)
437 {
438     int i;
439
440     lock_num_locks = CRYPTO_num_locks();
441     lock_cs = apr_palloc(p, lock_num_locks * sizeof(*lock_cs));
442
443     for (i = 0; i < lock_num_locks; i++) {
444         apr_thread_mutex_create(&(lock_cs[i]), APR_THREAD_MUTEX_DEFAULT, p);
445     }
446
447     CRYPTO_set_id_callback(ssl_util_thr_id);
448
449     CRYPTO_set_locking_callback(ssl_util_thr_lock);
450
451     apr_pool_cleanup_register(p, NULL, ssl_util_thread_cleanup,
452                                        apr_pool_cleanup_null);
453 }
454 #endif
455
456 /* --------------------------------------------------------- */
457 /* write out request to a connection - assumes we can write
458  * (small) request out in one go into our new socket buffer
459  *
460  */
461 #ifdef USE_SSL
462 long ssl_print_cb(BIO *bio,int cmd,const char *argp,int argi,long argl,long ret)
463 {
464     BIO *out;
465
466     out=(BIO *)BIO_get_callback_arg(bio);
467     if (out == NULL) return(ret);
468
469     if (cmd == (BIO_CB_READ|BIO_CB_RETURN))
470     {
471         BIO_printf(out,"read from %08X [%08lX] (%d bytes => %ld (0x%X))\n",
472                 bio,argp,argi,ret,ret);
473         BIO_dump(out,(char *)argp,(int)ret);
474         return(ret);
475     }
476     else if (cmd == (BIO_CB_WRITE|BIO_CB_RETURN))
477     {
478         BIO_printf(out,"write to %08X [%08lX] (%d bytes => %ld (0x%X))\n",
479             bio,argp,argi,ret,ret);
480         BIO_dump(out,(char *)argp,(int)ret);
481     }
482     return(ret);
483 }
484
485 #ifndef RAND_MAX
486 #include <limits.h>
487 #define RAND_MAX INT_MAX
488 #endif
489
490 static int ssl_rand_choosenum(int l, int h)
491 {
492     int i;
493     char buf[50];
494
495     srand((unsigned int)time(NULL));
496     apr_snprintf(buf, sizeof(buf), "%.0f",
497                  (((double)(rand()%RAND_MAX)/RAND_MAX)*(h-l)));
498     i = atoi(buf)+1;
499     if (i < l) i = l;
500     if (i > h) i = h;
501     return i;
502 }
503
504 void ssl_rand_seed()
505 {
506     int nDone = 0;
507     int n, l;
508     time_t t;
509     pid_t pid;
510     unsigned char stackdata[256];
511
512     /*
513      * seed in the current time (usually just 4 bytes)
514      */
515     t = time(NULL);
516     l = sizeof(time_t);
517     RAND_seed((unsigned char *)&t, l);
518     nDone += l;
519
520     /*
521      * seed in the current process id (usually just 4 bytes)
522      */
523     pid = getpid();
524     l = sizeof(pid_t);
525     RAND_seed((unsigned char *)&pid, l);
526     nDone += l;
527
528     /*
529      * seed in some current state of the run-time stack (128 bytes)
530      */
531     n = ssl_rand_choosenum(0, sizeof(stackdata)-128-1);
532     RAND_seed(stackdata+n, 128);
533     nDone += 128;
534 }
535
536 int ssl_print_connection_info(bio,ssl)
537 BIO *bio;
538 SSL *ssl;
539 {
540         SSL_CIPHER *c;
541         int alg_bits,bits;
542
543         c=SSL_get_current_cipher(ssl);
544         BIO_printf(bio,"Cipher Suite Protocol   :%s\n", SSL_CIPHER_get_version(c));
545         BIO_printf(bio,"Cipher Suite Name       :%s\n",SSL_CIPHER_get_name(c));
546
547         bits=SSL_CIPHER_get_bits(c,&alg_bits);
548         BIO_printf(bio,"Cipher Suite Cipher Bits:%d (%d)\n",bits,alg_bits);
549
550         return(1);
551 }
552
553 int ssl_print_cert_info(bio,x509cert)
554 BIO *bio;
555 X509 *x509cert;
556 {
557         X509_NAME *dn;
558         char buf[64];
559
560         BIO_printf(bio,"Certificate version: %d\n",X509_get_version(x509cert)+1);
561
562         BIO_printf(bio,"Valid from: ");
563         ASN1_UTCTIME_print(bio, X509_get_notBefore(x509cert));
564         BIO_printf(bio,"\n");
565
566         BIO_printf(bio,"Valid to  : ");
567         ASN1_UTCTIME_print(bio, X509_get_notAfter(x509cert));
568         BIO_printf(bio,"\n");
569
570         BIO_printf(bio,"Public key is %d bits\n",
571             EVP_PKEY_bits(X509_get_pubkey(x509cert)));
572
573         dn=X509_get_issuer_name(x509cert);
574         X509_NAME_oneline(dn, buf, BUFSIZ);
575         BIO_printf(bio,"The issuer name is %s\n", buf);
576
577         dn=X509_get_subject_name(x509cert);
578         X509_NAME_oneline(dn, buf, BUFSIZ);
579         BIO_printf(bio,"The subject name is %s\n", buf);
580
581         /* dump the extension list too */
582         BIO_printf(bio,"Extension Count: %d\n",X509_get_ext_count(x509cert));
583
584         return(1);
585 }
586
587 void ssl_start_connect(struct connection * c)
588 {
589     BIO *bio;
590     X509 *x509cert;
591 #ifdef RSAREF
592     STACK *sk;
593 #else
594     STACK_OF(X509) *sk;
595 #endif
596     int i, count, hdone = 0;
597     char ssl_hostname[80];
598     
599     /* XXX - Verify if it's okay - TBD */
600     if (requests < concurrency)
601         requests = concurrency;
602
603     if (!(started < requests))
604         return;
605
606     c->read = 0;
607     c->bread = 0;
608     c->keepalive = 0;
609     c->cbx = 0;
610     c->gotheader = 0;
611     c->rwrite = 0;
612     if (c->ctx)
613         apr_pool_destroy(c->ctx);
614     apr_pool_create(&c->ctx, cntxt);
615
616     if ((c->ssl=SSL_new(ctx)) == NULL)
617     {
618         BIO_printf(bio_err,"SSL_new failed\n");
619         exit(1);
620     }
621
622     ssl_rand_seed();
623
624     c->start = apr_time_now();
625     memset(ssl_hostname, 0, 80);
626     sprintf(ssl_hostname, "%s:%d", hostname, port);
627
628     if ((bio = BIO_new_connect(ssl_hostname)) == NULL)
629     {
630         BIO_printf(bio_err,"BIO_new_connect failed\n");
631         exit(1);
632     }
633     SSL_set_bio(c->ssl,bio,bio);
634     SSL_set_connect_state(c->ssl);
635
636     if (verbosity >= 4)
637     {
638         BIO_set_callback(bio,ssl_print_cb);
639         BIO_set_callback_arg(bio,(void*)bio_err);
640     }
641
642     while (!hdone)
643     {
644         i = SSL_do_handshake(c->ssl);
645
646         switch (SSL_get_error(c->ssl,i))
647         {
648             case SSL_ERROR_NONE:
649                 hdone=1;
650                 break;
651             case SSL_ERROR_SSL:
652             case SSL_ERROR_SYSCALL:
653                 BIO_printf(bio_err,"SSL connection failed\n");
654                 err_conn++;
655                 c->state = STATE_UNCONNECTED;
656                 if (bad++ > 10) {
657                     SSL_free (c->ssl);
658                     BIO_printf(bio_err,"\nTest aborted after 10 failures\n\n");
659                     exit (1);
660                 }
661                 break;
662             case SSL_ERROR_WANT_READ:
663             case SSL_ERROR_WANT_WRITE:
664             case SSL_ERROR_WANT_CONNECT:
665                 BIO_printf(bio_err, "Waiting .. sleep(1)\n");
666                 apr_sleep(apr_time_from_sec(1));
667                 c->state = STATE_CONNECTING;
668                 c->rwrite = 0;
669                 break;
670             case SSL_ERROR_ZERO_RETURN:
671                 BIO_printf(bio_err,"socket closed\n");
672                 break;
673         }
674     }
675     
676     if (verbosity >= 2)
677     {
678         BIO_printf(bio_err, "\n");
679         sk = SSL_get_peer_cert_chain(c->ssl);
680 #ifdef RSAREF
681         if ((count = sk_num(sk)) > 0)
682 #else
683         if ((count = sk_X509_num(sk)) > 0)
684 #endif
685         {
686             for (i=1; i<count; i++)
687             {
688 #ifdef RSAREF
689                 x509cert = (X509 *)sk_value(sk,i);
690 #else
691                 x509cert = (X509 *)sk_X509_value(sk,i);
692 #endif
693                 ssl_print_cert_info(bio_out,x509cert);
694                 X509_free(x509cert);
695             }
696         }
697
698         x509cert = SSL_get_peer_certificate(c->ssl);
699         if (x509cert == NULL)
700             BIO_printf(bio_out, "Anon DH\n");
701         else
702         {
703             BIO_printf(bio_out, "Peer certificate\n");
704             ssl_print_cert_info(bio_out,x509cert);
705             X509_free(x509cert);
706         }
707
708         ssl_print_connection_info(bio_err,c->ssl);
709         SSL_SESSION_print(bio_err,SSL_get_session(c->ssl));
710     }
711
712     /* connected first time */
713     started++;
714     write_request(c);
715 }
716 #endif /* USE_SSL */
717
718 static void write_request(struct connection * c)
719 {
720     do {
721         apr_time_t tnow = apr_time_now();
722         apr_size_t l = c->rwrite;
723         apr_status_t e;
724
725         /*
726          * First time round ?
727          */
728         if (c->rwrite == 0) {
729 #ifdef USE_SSL
730             if (ssl != 1)
731 #endif
732             apr_socket_timeout_set(c->aprsock, 0);
733             c->connect = tnow;
734             c->rwrite = reqlen;
735             c->rwrote = 0;
736             if (posting)
737                 c->rwrite += postlen;
738         }
739         else if (tnow > c->connect + aprtimeout) {
740             printf("Send request timed out!\n");
741             close_connection(c);
742             return;
743         }
744
745 #ifdef USE_SSL
746         if (ssl == 1) {
747             apr_size_t e_ssl;
748             e_ssl = SSL_write(c->ssl,request + c->rwrote, l);
749             if (e_ssl != l)
750             {
751                 printf("SSL write failed - closing connection\n");
752                 close_connection (c);
753                 return;
754             }
755             l = e_ssl;
756         }
757         else
758 #endif
759         e = apr_send(c->aprsock, request + c->rwrote, &l);
760
761         /*
762          * Bail early on the most common case
763          */
764         if (l == c->rwrite)
765             break;
766
767 #ifdef USE_SSL
768         if (ssl != 1)
769         if (e != APR_SUCCESS) {
770             /*
771              * Let's hope this traps EWOULDBLOCK too !
772              */
773             if (!APR_STATUS_IS_EAGAIN(e)) {
774                 epipe++;
775                 printf("Send request failed!\n");
776                 close_connection(c);
777             }
778             return;
779         }
780 #endif
781         c->rwrote += l;
782         c->rwrite -= l;
783     } while (1);
784
785     totalposted += c->rwrite;
786     c->state = STATE_READ;
787     c->endwrite = apr_time_now();
788 #ifdef USE_SSL
789     if (ssl != 1)
790 #endif
791     {
792         apr_pollfd_t new_pollfd;
793         new_pollfd.desc_type = APR_POLL_SOCKET;
794         new_pollfd.reqevents = APR_POLLIN;
795         new_pollfd.desc.s = c->aprsock;
796         new_pollfd.client_data = c;
797         apr_pollset_add(readbits, &new_pollfd);
798     }
799 }
800
801 /* --------------------------------------------------------- */
802
803 /* calculate and output results */
804
805 static int compradre(struct data * a, struct data * b)
806 {
807     if ((a->ctime) < (b->ctime))
808         return -1;
809     if ((a->ctime) > (b->ctime))
810         return +1;
811     return 0;
812 }
813
814 static int comprando(struct data * a, struct data * b)
815 {
816     if ((a->time) < (b->time))
817         return -1;
818     if ((a->time) > (b->time))
819         return +1;
820     return 0;
821 }
822
823 static int compri(struct data * a, struct data * b)
824 {
825     apr_interval_time_t p = a->time - a->ctime;
826     apr_interval_time_t q = b->time - b->ctime;
827     if (p < q)
828         return -1;
829     if (p > q)
830         return +1;
831     return 0;
832 }
833
834 static int compwait(struct data * a, struct data * b)
835 {
836     if ((a->waittime) < (b->waittime))
837         return -1;
838     if ((a->waittime) > (b->waittime))
839         return 1;
840     return 0;
841 }
842
843 static void output_results(void)
844 {
845     apr_interval_time_t timetakenusec;
846     float timetaken;
847
848     endtime = apr_time_now();
849     timetakenusec = endtime - start;
850     timetaken = ((float)apr_time_sec(timetakenusec)) +
851         ((float)apr_time_usec(timetakenusec)) / 1000000.0F;
852     
853     printf("\n\n");
854     printf("Server Software:        %s\n", servername);
855     printf("Server Hostname:        %s\n", hostname);
856     printf("Server Port:            %hd\n", port);
857     printf("\n");
858     printf("Document Path:          %s\n", path);
859     printf("Document Length:        %" APR_SIZE_T_FMT " bytes\n", doclen);
860     printf("\n");
861     printf("Concurrency Level:      %d\n", concurrency);
862     printf("Time taken for tests:   %ld.%03ld seconds\n",
863            (long) apr_time_sec(timetakenusec),
864            (long) apr_time_usec(timetakenusec));
865     printf("Complete requests:      %ld\n", done);
866     printf("Failed requests:        %ld\n", bad);
867     if (bad)
868         printf("   (Connect: %d, Length: %d, Exceptions: %d)\n",
869                err_conn, err_length, err_except);
870     printf("Write errors:           %ld\n", epipe);
871     if (err_response)
872         printf("Non-2xx responses:      %d\n", err_response);
873     if (keepalive)
874         printf("Keep-Alive requests:    %ld\n", doneka);
875     printf("Total transferred:      %ld bytes\n", totalread);
876     if (posting > 0)
877         printf("Total POSTed:           %ld\n", totalposted);
878     printf("HTML transferred:       %ld bytes\n", totalbread);
879
880     /* avoid divide by zero */
881     if (timetaken) {
882         printf("Requests per second:    %.2f [#/sec] (mean)\n", 
883                (float) (done / timetaken));
884         printf("Time per request:       %.3f [ms] (mean)\n", 
885                (float) (1000 * concurrency * timetaken / done));
886         printf("Time per request:       %.3f [ms] (mean, across all concurrent requests)\n",
887                (float) (1000 * timetaken / done));
888         printf("Transfer rate:          %.2f [Kbytes/sec] received\n",
889                (float) (totalread / 1024 / timetaken));
890         if (posting > 0) {
891             printf("                        %.2f kb/s sent\n",
892                    (float) (totalposted / timetaken / 1024));
893             printf("                        %.2f kb/s total\n",
894                    (float) ((totalread + totalposted) / timetaken / 1024));
895         }
896     }
897
898     if (requests) {
899         /* work out connection times */
900         long i;
901         apr_time_t totalcon = 0, total = 0, totald = 0, totalwait = 0;
902         apr_interval_time_t mincon = AB_MAX, mintot = AB_MAX, mind = AB_MAX, 
903                             minwait = AB_MAX;
904         apr_interval_time_t maxcon = 0, maxtot = 0, maxd = 0, maxwait = 0;
905         apr_interval_time_t meancon = 0, meantot = 0, meand = 0, meanwait = 0;
906         double sdtot = 0, sdcon = 0, sdd = 0, sdwait = 0;
907
908         for (i = 0; i < requests; i++) {
909             struct data s = stats[i];
910             mincon = ap_min(mincon, s.ctime);
911             mintot = ap_min(mintot, s.time);
912             mind = ap_min(mind, s.time - s.ctime);
913             minwait = ap_min(minwait, s.waittime);
914
915             maxcon = ap_max(maxcon, s.ctime);
916             maxtot = ap_max(maxtot, s.time);
917             maxd = ap_max(maxd, s.time - s.ctime);
918             maxwait = ap_max(maxwait, s.waittime);
919
920             totalcon += s.ctime;
921             total += s.time;
922             totald += s.time - s.ctime;
923             totalwait += s.waittime;
924         }
925         totalcon /= requests;
926         total /= requests;
927         totald /= requests;
928         totalwait /= requests;
929
930         for (i = 0; i < requests; i++) {
931             struct data s = stats[i];
932             double a;
933             a = ((double)s.time - total);
934             sdtot += a * a;
935             a = ((double)s.ctime - totalcon);
936             sdcon += a * a;
937             a = ((double)s.time - (double)s.ctime - totald);
938             sdd += a * a;
939             a = ((double)s.waittime - totalwait);
940             sdwait += a * a;
941         }
942
943         sdtot = (requests > 1) ? sqrt(sdtot / (requests - 1)) : 0;
944         sdcon = (requests > 1) ? sqrt(sdcon / (requests - 1)) : 0;
945         sdd = (requests > 1) ? sqrt(sdd / (requests - 1)) : 0;
946         sdwait = (requests > 1) ? sqrt(sdwait / (requests - 1)) : 0;
947
948         if (gnuplot) {
949             FILE *out = fopen(gnuplot, "w");
950             long i;
951             apr_time_t sttime;
952             char tmstring[1024];/* XXXX */
953             if (!out) {
954                 perror("Cannot open gnuplot output file");
955                 exit(1);
956             }
957             fprintf(out, "starttime\tseconds\tctime\tdtime\tttime\twait\n");
958             for (i = 0; i < requests; i++) {
959                 apr_time_t diff = stats[i].time - stats[i].ctime;
960
961                 sttime = stats[i].starttime;
962                 (void) apr_ctime(tmstring, sttime);
963                 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",
964                         tmstring,
965                         sttime,
966                         stats[i].ctime,
967                         diff,
968                         stats[i].time,
969                         stats[i].waittime);
970             }
971             fclose(out);
972         }
973     /*
974      * XXX: what is better; this hideous cast of the compradre function; or
975      * the four warnings during compile ? dirkx just does not know and
976      * hates both/
977      */
978         qsort(stats, requests, sizeof(struct data),
979               (int (*) (const void *, const void *)) compradre);
980         if ((requests > 1) && (requests % 2))
981             meancon = (stats[requests / 2].ctime + stats[requests / 2 + 1].ctime) / 2;
982         else
983             meancon = stats[requests / 2].ctime;
984
985         qsort(stats, requests, sizeof(struct data),
986               (int (*) (const void *, const void *)) compri);
987         if ((requests > 1) && (requests % 2))
988             meand = (stats[requests / 2].time + stats[requests / 2 + 1].time \
989             -stats[requests / 2].ctime - stats[requests / 2 + 1].ctime) / 2;
990         else
991             meand = stats[requests / 2].time - stats[requests / 2].ctime;
992
993         qsort(stats, requests, sizeof(struct data),
994               (int (*) (const void *, const void *)) compwait);
995         if ((requests > 1) && (requests % 2))
996             meanwait = (stats[requests / 2].waittime + stats[requests / 2 + 1].waittime) / 2;
997         else
998             meanwait = stats[requests / 2].waittime;
999
1000         qsort(stats, requests, sizeof(struct data),
1001               (int (*) (const void *, const void *)) comprando);
1002         if ((requests > 1) && (requests % 2))
1003             meantot = (stats[requests / 2].time + stats[requests / 2 + 1].time) / 2;
1004         else
1005             meantot = stats[requests / 2].time;
1006
1007         printf("\nConnection Times (ms)\n");
1008
1009         if (confidence) {
1010 #define CONF_FMT_STRING "%5" APR_TIME_T_FMT " %4d %5.1f %6" APR_TIME_T_FMT " %7" APR_TIME_T_FMT "\n"
1011             printf("              min  mean[+/-sd] median   max\n");
1012             printf("Connect:    " CONF_FMT_STRING, 
1013                    mincon, (int) (totalcon + 0.5), sdcon, meancon, maxcon);
1014             printf("Processing: " CONF_FMT_STRING,
1015                    mind, (int) (totald + 0.5), sdd, meand, maxd);
1016             printf("Waiting:    " CONF_FMT_STRING,
1017                    minwait, (int) (totalwait + 0.5), sdwait, meanwait, maxwait);
1018             printf("Total:      " CONF_FMT_STRING,
1019                    mintot, (int) (total + 0.5), sdtot, meantot, maxtot);
1020 #undef CONF_FMT_STRING
1021
1022 #define     SANE(what,avg,mean,sd) \
1023               { \
1024                 double d = (double)avg - mean; \
1025                 if (d < 0) d = -d; \
1026                 if (d > 2 * sd ) \
1027                     printf("ERROR: The median and mean for " what " are more than twice the standard\n" \
1028                            "       deviation apart. These results are NOT reliable.\n"); \
1029                 else if (d > sd ) \
1030                     printf("WARNING: The median and mean for " what " are not within a normal deviation\n" \
1031                            "        These results are probably not that reliable.\n"); \
1032             }
1033             SANE("the initial connection time", totalcon, meancon, sdcon);
1034             SANE("the processing time", totald, meand, sdd);
1035             SANE("the waiting time", totalwait, meanwait, sdwait);
1036             SANE("the total time", total, meantot, sdtot);
1037         }
1038         else {
1039             printf("              min   avg   max\n");
1040 #define CONF_FMT_STRING "%5" APR_TIME_T_FMT " %5" APR_TIME_T_FMT "%5" APR_TIME_T_FMT "\n"
1041             printf("Connect:    " CONF_FMT_STRING, 
1042                    mincon, totalcon / requests, maxcon);
1043             printf("Processing: " CONF_FMT_STRING, mintot - mincon, 
1044                    (total / requests) - (totalcon / requests), 
1045                    maxtot - maxcon);
1046             printf("Total:      " CONF_FMT_STRING, 
1047                    mintot, total / requests, maxtot);
1048 #undef CONF_FMT_STRING
1049         }
1050
1051
1052         /* Sorted on total connect times */
1053         if (percentile && (requests > 1)) {
1054             printf("\nPercentage of the requests served within a certain time (ms)\n");
1055             for (i = 0; i < sizeof(percs) / sizeof(int); i++)
1056                 if (percs[i] <= 0)
1057                     printf(" 0%%  <0> (never)\n");
1058                 else if (percs[i] >= 100)
1059                     printf(" 100%%  %5" APR_TIME_T_FMT " (longest request)\n",
1060                            stats[requests - 1].time);
1061                 else
1062                     printf("  %d%%  %5" APR_TIME_T_FMT "\n", percs[i], 
1063                            stats[(int) (requests * percs[i] / 100)].time);
1064         }
1065         if (csvperc) {
1066             FILE *out = fopen(csvperc, "w");
1067             int i;
1068             if (!out) {
1069                 perror("Cannot open CSV output file");
1070                 exit(1);
1071             }
1072             fprintf(out, "" "Percentage served" "," "Time in ms" "\n");
1073             for (i = 0; i < 100; i++) {
1074                 apr_time_t t;
1075                 if (i == 0)
1076                     t = stats[0].time;
1077                 else if (i == 100)
1078                     t = stats[requests - 1].time;
1079                 else
1080                     t = stats[(int) (0.5 + requests * i / 100.0)].time;
1081                 fprintf(out, "%d,%e\n", i, (double)t);
1082             }
1083             fclose(out);
1084         }
1085
1086     }
1087 }
1088
1089 /* --------------------------------------------------------- */
1090
1091 /* calculate and output results in HTML  */
1092
1093 static void output_html_results(void)
1094 {
1095     long timetaken;
1096
1097     endtime = apr_time_now();
1098     timetaken = (long)((endtime - start) / 1000);
1099
1100     printf("\n\n<table %s>\n", tablestring);
1101     printf("<tr %s><th colspan=2 %s>Server Software:</th>"
1102            "<td colspan=2 %s>%s</td></tr>\n",
1103            trstring, tdstring, tdstring, servername);
1104     printf("<tr %s><th colspan=2 %s>Server Hostname:</th>"
1105            "<td colspan=2 %s>%s</td></tr>\n",
1106            trstring, tdstring, tdstring, hostname);
1107     printf("<tr %s><th colspan=2 %s>Server Port:</th>"
1108            "<td colspan=2 %s>%hd</td></tr>\n",
1109            trstring, tdstring, tdstring, port);
1110     printf("<tr %s><th colspan=2 %s>Document Path:</th>"
1111            "<td colspan=2 %s>%s</td></tr>\n",
1112            trstring, tdstring, tdstring, path);
1113     printf("<tr %s><th colspan=2 %s>Document Length:</th>"
1114            "<td colspan=2 %s>%" APR_SIZE_T_FMT " bytes</td></tr>\n",
1115            trstring, tdstring, tdstring, doclen);
1116     printf("<tr %s><th colspan=2 %s>Concurrency Level:</th>"
1117            "<td colspan=2 %s>%d</td></tr>\n",
1118            trstring, tdstring, tdstring, concurrency);
1119     printf("<tr %s><th colspan=2 %s>Time taken for tests:</th>"
1120            "<td colspan=2 %s>%qd.%03ld seconds</td></tr>\n",
1121            trstring, tdstring, tdstring, apr_time_sec(timetaken),
1122            (long)apr_time_usec(timetaken));
1123     printf("<tr %s><th colspan=2 %s>Complete requests:</th>"
1124            "<td colspan=2 %s>%ld</td></tr>\n",
1125            trstring, tdstring, tdstring, done);
1126     printf("<tr %s><th colspan=2 %s>Failed requests:</th>"
1127            "<td colspan=2 %s>%ld</td></tr>\n",
1128            trstring, tdstring, tdstring, bad);
1129     if (bad)
1130         printf("<tr %s><td colspan=4 %s >   (Connect: %d, Length: %d, Exceptions: %d)</td></tr>\n",
1131                trstring, tdstring, err_conn, err_length, err_except);
1132     if (err_response)
1133         printf("<tr %s><th colspan=2 %s>Non-2xx responses:</th>"
1134                "<td colspan=2 %s>%d</td></tr>\n",
1135                trstring, tdstring, tdstring, err_response);
1136     if (keepalive)
1137         printf("<tr %s><th colspan=2 %s>Keep-Alive requests:</th>"
1138                "<td colspan=2 %s>%ld</td></tr>\n",
1139                trstring, tdstring, tdstring, doneka);
1140     printf("<tr %s><th colspan=2 %s>Total transferred:</th>"
1141            "<td colspan=2 %s>%ld bytes</td></tr>\n",
1142            trstring, tdstring, tdstring, totalread);
1143     if (posting > 0)
1144         printf("<tr %s><th colspan=2 %s>Total POSTed:</th>"
1145                "<td colspan=2 %s>%ld</td></tr>\n",
1146                trstring, tdstring, tdstring, totalposted);
1147     printf("<tr %s><th colspan=2 %s>HTML transferred:</th>"
1148            "<td colspan=2 %s>%ld bytes</td></tr>\n",
1149            trstring, tdstring, tdstring, totalbread);
1150
1151     /* avoid divide by zero */
1152     if (timetaken) {
1153         printf("<tr %s><th colspan=2 %s>Requests per second:</th>"
1154                "<td colspan=2 %s>%.2f</td></tr>\n",
1155            trstring, tdstring, tdstring, 1000 * (float) (done) / timetaken);
1156         printf("<tr %s><th colspan=2 %s>Transfer rate:</th>"
1157                "<td colspan=2 %s>%.2f kb/s received</td></tr>\n",
1158              trstring, tdstring, tdstring, (float) (totalread) / timetaken);
1159         if (posting > 0) {
1160             printf("<tr %s><td colspan=2 %s>&nbsp;</td>"
1161                    "<td colspan=2 %s>%.2f kb/s sent</td></tr>\n",
1162                    trstring, tdstring, tdstring,
1163                    (float) (totalposted) / timetaken);
1164             printf("<tr %s><td colspan=2 %s>&nbsp;</td>"
1165                    "<td colspan=2 %s>%.2f kb/s total</td></tr>\n",
1166                    trstring, tdstring, tdstring,
1167                    (float) (totalread + totalposted) / timetaken);
1168         }
1169     } {
1170         /* work out connection times */
1171         long i;
1172         apr_interval_time_t totalcon = 0, total = 0;
1173         apr_interval_time_t mincon = AB_MAX, mintot = AB_MAX;
1174         apr_interval_time_t maxcon = 0, maxtot = 0;
1175
1176         for (i = 0; i < requests; i++) {
1177             struct data s = stats[i];
1178             mincon = ap_min(mincon, s.ctime);
1179             mintot = ap_min(mintot, s.time);
1180             maxcon = ap_max(maxcon, s.ctime);
1181             maxtot = ap_max(maxtot, s.time);
1182             totalcon += s.ctime;
1183             total += s.time;
1184         }
1185
1186         if (requests > 0) {     /* avoid division by zero (if 0 requests) */
1187             printf("<tr %s><th %s colspan=4>Connnection Times (ms)</th></tr>\n",
1188                    trstring, tdstring);
1189             printf("<tr %s><th %s>&nbsp;</th> <th %s>min</th>   <th %s>avg</th>   <th %s>max</th></tr>\n",
1190                    trstring, tdstring, tdstring, tdstring, tdstring);
1191             printf("<tr %s><th %s>Connect:</th>"
1192                    "<td %s>%5" APR_TIME_T_FMT "</td>"
1193                    "<td %s>%5" APR_TIME_T_FMT "</td>"
1194                    "<td %s>%5" APR_TIME_T_FMT "</td></tr>\n",
1195                    trstring, tdstring, tdstring, mincon, tdstring, totalcon / requests, tdstring, maxcon);
1196             printf("<tr %s><th %s>Processing:</th>"
1197                    "<td %s>%5" APR_TIME_T_FMT "</td>"
1198                    "<td %s>%5" APR_TIME_T_FMT "</td>"
1199                    "<td %s>%5" APR_TIME_T_FMT "</td></tr>\n",
1200                    trstring, tdstring, tdstring, mintot - mincon, tdstring,
1201                    (total / requests) - (totalcon / requests), tdstring, maxtot - maxcon);
1202             printf("<tr %s><th %s>Total:</th>"
1203                    "<td %s>%5" APR_TIME_T_FMT "</td>"
1204                    "<td %s>%5" APR_TIME_T_FMT "</td>"
1205                    "<td %s>%5" APR_TIME_T_FMT "</td></tr>\n",
1206                    trstring, tdstring, tdstring, mintot, tdstring, total / requests, tdstring, maxtot);
1207         }
1208         printf("</table>\n");
1209     }
1210 }
1211
1212 /* --------------------------------------------------------- */
1213
1214 /* start asnchronous non-blocking connection */
1215
1216 static void start_connect(struct connection * c)
1217 {
1218     apr_status_t rv;
1219
1220 #ifdef USE_SSL
1221     if (ssl == 1) {
1222         ssl_start_connect(c);
1223         return;
1224     }
1225 #endif
1226     
1227     if (!(started < requests))
1228         return;
1229
1230     c->read = 0;
1231     c->bread = 0;
1232     c->keepalive = 0;
1233     c->cbx = 0;
1234     c->gotheader = 0;
1235     c->rwrite = 0;
1236     if (c->ctx)
1237         apr_pool_destroy(c->ctx);
1238     apr_pool_create(&c->ctx, cntxt);
1239
1240     if ((rv = apr_socket_create(&c->aprsock, destsa->family,
1241                                 SOCK_STREAM, c->ctx)) != APR_SUCCESS) {
1242         apr_err("socket", rv);
1243     }
1244     if ((rv = apr_socket_opt_set(c->aprsock, APR_SO_NONBLOCK, 1))
1245          != APR_SUCCESS) {
1246         apr_err("socket nonblock", rv);
1247     }
1248     c->start = apr_time_now();
1249     if ((rv = apr_connect(c->aprsock, destsa)) != APR_SUCCESS) {
1250         if (APR_STATUS_IS_EINPROGRESS(rv)) {
1251             apr_pollfd_t new_pollfd;
1252             c->state = STATE_CONNECTING;
1253             c->rwrite = 0;
1254             new_pollfd.desc_type = APR_POLL_SOCKET;
1255             new_pollfd.reqevents = APR_POLLIN;
1256             new_pollfd.desc.s = c->aprsock;
1257             new_pollfd.client_data = c;
1258             apr_pollset_add(readbits, &new_pollfd);
1259             return;
1260         }
1261         else {
1262             apr_pollfd_t remove_pollfd;
1263             remove_pollfd.desc_type = APR_POLL_SOCKET;
1264             remove_pollfd.desc.s = c->aprsock;
1265             apr_pollset_remove(readbits, &remove_pollfd);
1266             apr_socket_close(c->aprsock);
1267             err_conn++;
1268             if (bad++ > 10) {
1269                 fprintf(stderr,
1270                         "\nTest aborted after 10 failures\n\n");
1271                 apr_err("apr_connect()", rv);
1272             }
1273             c->state = STATE_UNCONNECTED;
1274             start_connect(c);
1275             return;
1276         }
1277     }
1278
1279     /* connected first time */
1280     started++;
1281     write_request(c);
1282 }
1283
1284 /* --------------------------------------------------------- */
1285
1286 /* close down connection and save stats */
1287
1288 static void close_connection(struct connection * c)
1289 {
1290     if (c->read == 0 && c->keepalive) {
1291         /*
1292          * server has legitimately shut down an idle keep alive request
1293          */
1294         if (good)
1295             good--;             /* connection never happened */
1296     }
1297     else {
1298         if (good == 1) {
1299             /* first time here */
1300             doclen = c->bread;
1301         }
1302         else if (c->bread != doclen) {
1303             bad++;
1304             err_length++;
1305         }
1306         /* save out time */
1307         if (done < requests) {
1308             struct data s;
1309             if ((done) && heartbeatres && !(done % heartbeatres)) {
1310                 fprintf(stderr, "Completed %ld requests\n", done);
1311                 fflush(stderr);
1312             }
1313             c->done = apr_time_now();
1314             s.read = c->read;
1315             s.starttime = c->start;
1316             s.ctime = (c->connect - c->start) / 1000;
1317             s.time = (c->done - c->start) / 1000;
1318             s.waittime = (c->beginread - c->endwrite) / 1000;
1319             stats[done++] = s;
1320         }
1321     }
1322
1323 #ifdef USE_SSL
1324     if (ssl == 1) {
1325         SSL_shutdown(c->ssl);
1326         SSL_free(c->ssl);
1327     }
1328     else
1329 #endif
1330     {
1331         apr_pollfd_t remove_pollfd;
1332         remove_pollfd.desc_type = APR_POLL_SOCKET;
1333         remove_pollfd.desc.s = c->aprsock;
1334         apr_pollset_remove(readbits, &remove_pollfd);
1335         apr_socket_close(c->aprsock);
1336     }
1337     c->state = STATE_UNCONNECTED;
1338
1339     /* connect again */
1340     start_connect(c);
1341     return;
1342 }
1343
1344 /* --------------------------------------------------------- */
1345
1346 /* read data from connection */
1347
1348 static void read_connection(struct connection * c)
1349 {
1350     apr_size_t r;
1351     apr_status_t status;
1352     char *part;
1353     char respcode[4];           /* 3 digits and null */
1354
1355     r = sizeof(buffer);
1356 #ifdef USE_SSL
1357     if (ssl == 1)
1358     {
1359         status = SSL_read (c->ssl, buffer, r);
1360         if (status <= 0) {
1361             good++; c->read = 0;
1362             if (status < 0) printf("SSL read failed - closing connection\n");
1363             close_connection(c);
1364             return;
1365         }
1366     r = status;
1367     }
1368     else {
1369 #endif
1370     status = apr_recv(c->aprsock, buffer, &r);
1371     if (APR_STATUS_IS_EAGAIN(status))
1372         return;
1373     else if (r == 0 && APR_STATUS_IS_EOF(status)) {
1374         good++;
1375         close_connection(c);
1376         return;
1377     }
1378     /* catch legitimate fatal apr_recv errors */
1379     else if (status != APR_SUCCESS) {
1380         err_except++; /* XXX: is this the right error counter? */
1381         /* XXX: Should errors here be fatal, or should we allow a
1382          * certain number of them before completely failing? -aaron */
1383         apr_err("apr_recv", status);
1384     }
1385 #ifdef USE_SSL
1386     }
1387 #endif
1388
1389     totalread += r;
1390     if (c->read == 0) {
1391         c->beginread = apr_time_now();
1392     }
1393     c->read += r;
1394
1395
1396     if (!c->gotheader) {
1397         char *s;
1398         int l = 4;
1399         apr_size_t space = CBUFFSIZE - c->cbx - 1; /* -1 allows for \0 term */
1400         int tocopy = (space < r) ? space : r;
1401 #ifdef NOT_ASCII
1402         apr_size_t inbytes_left = space, outbytes_left = space;
1403
1404         status = apr_xlate_conv_buffer(from_ascii, buffer, &inbytes_left,
1405                                        c->cbuff + c->cbx, &outbytes_left);
1406         if (status || inbytes_left || outbytes_left) {
1407             fprintf(stderr, "only simple translation is supported (%d/%u/%u)\n",
1408                     status, inbytes_left, outbytes_left);
1409             exit(1);
1410         }
1411 #else
1412         memcpy(c->cbuff + c->cbx, buffer, space);
1413 #endif                          /* NOT_ASCII */
1414         c->cbx += tocopy;
1415         space -= tocopy;
1416         c->cbuff[c->cbx] = 0;   /* terminate for benefit of strstr */
1417         if (verbosity >= 2) {
1418             printf("LOG: header received:\n%s\n", c->cbuff);
1419         }
1420         s = strstr(c->cbuff, "\r\n\r\n");
1421         /*
1422          * this next line is so that we talk to NCSA 1.5 which blatantly
1423          * breaks the http specifaction
1424          */
1425         if (!s) {
1426             s = strstr(c->cbuff, "\n\n");
1427             l = 2;
1428         }
1429
1430         if (!s) {
1431             /* read rest next time */
1432             if (space) {
1433                 return;
1434             }
1435             else {
1436                 /* header is in invalid or too big - close connection */
1437                 apr_pollfd_t remove_pollfd;
1438                 remove_pollfd.desc_type = APR_POLL_SOCKET;
1439                 remove_pollfd.desc.s = c->aprsock;
1440                 apr_pollset_remove(readbits, &remove_pollfd);
1441                 apr_socket_close(c->aprsock);
1442                 err_response++;
1443                 if (bad++ > 10) {
1444                     err("\nTest aborted after 10 failures\n\n");
1445                 }
1446                 start_connect(c);
1447             }
1448         }
1449         else {
1450             /* have full header */
1451             if (!good) {
1452                 /*
1453                  * this is first time, extract some interesting info
1454                  */
1455                 char *p, *q;
1456                 p = strstr(c->cbuff, "Server:");
1457                 q = servername;
1458                 if (p) {
1459                     p += 8;
1460                     while (*p > 32)
1461                         *q++ = *p++;
1462                 }
1463                 *q = 0;
1464             }
1465             /*
1466              * XXX: this parsing isn't even remotely HTTP compliant... but in
1467              * the interest of speed it doesn't totally have to be, it just
1468              * needs to be extended to handle whatever servers folks want to
1469              * test against. -djg
1470              */
1471
1472             /* check response code */
1473             part = strstr(c->cbuff, "HTTP");    /* really HTTP/1.x_ */
1474             strncpy(respcode, (part + strlen("HTTP/1.x_")), 3);
1475             respcode[3] = '\0';
1476             if (respcode[0] != '2') {
1477                 err_response++;
1478                 if (verbosity >= 2)
1479                     printf("WARNING: Response code not 2xx (%s)\n", respcode);
1480             }
1481             else if (verbosity >= 3) {
1482                 printf("LOG: Response code = %s\n", respcode);
1483             }
1484             c->gotheader = 1;
1485             *s = 0;             /* terminate at end of header */
1486             if (keepalive &&
1487                 (strstr(c->cbuff, "Keep-Alive")
1488                  || strstr(c->cbuff, "keep-alive"))) {  /* for benefit of MSIIS */
1489                 char *cl;
1490                 cl = strstr(c->cbuff, "Content-Length:");
1491                 /* handle NCSA, which sends Content-length: */
1492                 if (!cl)
1493                     cl = strstr(c->cbuff, "Content-length:");
1494                 if (cl) {
1495                     c->keepalive = 1;
1496                     c->length = atoi(cl + 16);
1497                 }
1498             }
1499             c->bread += c->cbx - (s + l - c->cbuff) + r - tocopy;
1500             totalbread += c->bread;
1501         }
1502     }
1503     else {
1504         /* outside header, everything we have read is entity body */
1505         c->bread += r;
1506         totalbread += r;
1507     }
1508
1509     if (c->keepalive && (c->bread >= c->length)) {
1510         /* finished a keep-alive connection */
1511         good++;
1512         doneka++;
1513         /* save out time */
1514         if (good == 1) {
1515             /* first time here */
1516             doclen = c->bread;
1517         }
1518         else if (c->bread != doclen) {
1519             bad++;
1520             err_length++;
1521         }
1522         if (done < requests) {
1523             struct data s;
1524             if (done && heartbeatres && !(done % heartbeatres)) {
1525                 fprintf(stderr, "Completed %ld requests\n", done);
1526                 fflush(stderr);
1527             }
1528             c->done = apr_time_now();
1529             s.read = c->read;
1530             s.starttime = c->start;
1531             s.ctime = (c->connect - c->start) / 1000;
1532             s.waittime = (c->beginread - c->endwrite) / 1000;
1533             s.time = (c->done - c->start) / 1000;
1534             stats[done++] = s;
1535         }
1536         c->keepalive = 0;
1537         c->length = 0;
1538         c->gotheader = 0;
1539         c->cbx = 0;
1540         c->read = c->bread = 0;
1541         write_request(c);
1542         c->start = c->connect;  /* zero connect time with keep-alive */
1543     }
1544 }
1545
1546 /* --------------------------------------------------------- */
1547
1548 /* run the tests */
1549
1550 static void test(void)
1551 {
1552     apr_time_t now;
1553     apr_int16_t rv;
1554     long i;
1555     apr_status_t status;
1556 #ifdef NOT_ASCII
1557     apr_size_t inbytes_left, outbytes_left;
1558 #endif
1559
1560     if (isproxy) {
1561         strcpy(connecthost, proxyhost);
1562         connectport = proxyport;
1563     }
1564     else {
1565         strcpy(connecthost, hostname);
1566         connectport = port;
1567     }
1568
1569     if (!use_html) {
1570         printf("Benchmarking %s ", hostname);
1571         if (isproxy)
1572             printf("[through %s:%d] ", proxyhost, proxyport);
1573         printf("(be patient)%s",
1574                (heartbeatres ? "\n" : "..."));
1575         fflush(stdout);
1576     }
1577
1578     now = apr_time_now();
1579
1580     con = calloc(concurrency * sizeof(struct connection), 1);
1581     
1582     stats = calloc(requests * sizeof(struct data), 1);
1583     apr_pollset_create(&readbits, concurrency, cntxt, 0);
1584
1585     /* setup request */
1586     if (posting <= 0) {
1587         sprintf(request, "%s %s HTTP/1.0\r\n"
1588                 "User-Agent: ApacheBench/%s\r\n"
1589                 "%s" "%s" "%s"
1590                 "Host: %s%s\r\n"
1591                 "Accept: */*\r\n"
1592                 "%s" "\r\n",
1593                 (posting == 0) ? "GET" : "HEAD",
1594                 (isproxy) ? fullurl : path,
1595                 AP_AB_BASEREVISION,
1596                 keepalive ? "Connection: Keep-Alive\r\n" : "",
1597                 cookie, auth, host_field, colonhost, hdrs);
1598     }
1599     else {
1600         sprintf(request, "POST %s HTTP/1.0\r\n"
1601                 "User-Agent: ApacheBench/%s\r\n"
1602                 "%s" "%s" "%s"
1603                 "Host: %s%s\r\n"
1604                 "Accept: */*\r\n"
1605                 "Content-length: %" APR_SIZE_T_FMT "\r\n"
1606                 "Content-type: %s\r\n"
1607                 "%s"
1608                 "\r\n",
1609                 (isproxy) ? fullurl : path,
1610                 AP_AB_BASEREVISION,
1611                 keepalive ? "Connection: Keep-Alive\r\n" : "",
1612                 cookie, auth,
1613                 host_field, colonhost, postlen,
1614                 (content_type[0]) ? content_type : "text/plain", hdrs);
1615     }
1616
1617     if (verbosity >= 2)
1618         printf("INFO: POST header == \n---\n%s\n---\n", request);
1619
1620     reqlen = strlen(request);
1621
1622     /*
1623      * Combine headers and (optional) post file into one contineous buffer
1624      */
1625     if (posting == 1) {
1626         char *buff = (char *) malloc(postlen + reqlen + 1);
1627         strcpy(buff, request);
1628         strcpy(buff + reqlen, postdata);
1629         request = buff;
1630     }
1631
1632 #ifdef NOT_ASCII
1633     inbytes_left = outbytes_left = reqlen;
1634     status = apr_xlate_conv_buffer(to_ascii, request, &inbytes_left,
1635                                    request, &outbytes_left);
1636     if (status || inbytes_left || outbytes_left) {
1637         fprintf(stderr, "only simple translation is supported (%d/%u/%u)\n",
1638                 status, inbytes_left, outbytes_left);
1639         exit(1);
1640     }
1641 #endif                          /* NOT_ASCII */
1642
1643     /* This only needs to be done once */
1644 #ifdef USE_SSL
1645     if (ssl != 1)
1646 #endif
1647     if ((rv = apr_sockaddr_info_get(&destsa, connecthost, APR_UNSPEC, connectport, 0, cntxt))
1648         != APR_SUCCESS) {
1649         char buf[120];
1650         apr_snprintf(buf, sizeof(buf),
1651                      "apr_sockaddr_info_get() for %s", connecthost);
1652         apr_err(buf, rv);
1653     }
1654
1655     /* ok - lets start */
1656     start = apr_time_now();
1657
1658     /* initialise lots of requests */
1659     for (i = 0; i < concurrency; i++) {
1660         con[i].socknum = i;
1661         start_connect(&con[i]);
1662     }
1663
1664     while (done < requests) {
1665         apr_int32_t n;
1666         apr_int32_t timed;
1667         const apr_pollfd_t *pollresults;
1668
1669         /* check for time limit expiry */
1670         now = apr_time_now();
1671         timed = (apr_int32_t)apr_time_sec(now - start);
1672         if (tlimit && timed >= tlimit) {
1673             requests = done;    /* so stats are correct */
1674             break;              /* no need to do another round */
1675         }
1676
1677         n = concurrency;
1678 #ifdef USE_SSL
1679         if (ssl == 1)
1680             status = APR_SUCCESS;
1681         else
1682 #endif
1683         status = apr_pollset_poll(readbits, aprtimeout, &n, &pollresults);
1684         if (status != APR_SUCCESS)
1685             apr_err("apr_poll", status);
1686
1687         if (!n) {
1688             err("\nServer timed out\n\n");
1689         }
1690
1691         for (i = 0; i < n; i++) {
1692             const apr_pollfd_t *next_fd = &(pollresults[i]);
1693             struct connection *c = next_fd->client_data;
1694
1695             /*
1696              * If the connection isn't connected how can we check it?
1697              */
1698             if (c->state == STATE_UNCONNECTED)
1699                 continue;
1700
1701 #ifdef USE_SSL
1702             if (ssl == 1)
1703                 rv = APR_POLLIN;
1704             else
1705 #endif
1706             rv = next_fd->rtnevents;
1707
1708             /*
1709              * Notes: APR_POLLHUP is set after FIN is received on some
1710              * systems, so treat that like APR_POLLIN so that we try to read
1711              * again.
1712              *
1713              * Some systems return APR_POLLERR with APR_POLLHUP.  We need to
1714              * call read_connection() for APR_POLLHUP, so check for
1715              * APR_POLLHUP first so that a closed connection isn't treated
1716              * like an I/O error.  If it is, we never figure out that the
1717              * connection is done and we loop here endlessly calling
1718              * apr_poll().
1719              */
1720             if ((rv & APR_POLLIN) || (rv & APR_POLLPRI) || (rv & APR_POLLHUP))
1721                 read_connection(c);
1722             if ((rv & APR_POLLERR) || (rv & APR_POLLNVAL)) {
1723                 bad++;
1724                 err_except++;
1725                 start_connect(c);
1726                 continue;
1727             }
1728             if (rv & APR_POLLOUT)
1729                 write_request(c);
1730
1731             /*
1732              * When using a select based poll every time we check the bits
1733              * are reset. In 1.3's ab we copied the FD_SET's each time
1734              * through, but here we're going to check the state and if the
1735              * connection is in STATE_READ or STATE_CONNECTING we'll add the
1736              * socket back in as APR_POLLIN.
1737              */
1738 #ifdef USE_SSL
1739             if (ssl != 1)
1740 #endif
1741             if (c->state == STATE_READ ||
1742                 c->state == STATE_CONNECTING) {
1743                     apr_pollfd_t new_pollfd;
1744                     new_pollfd.desc_type = APR_POLL_SOCKET;
1745                     new_pollfd.reqevents = APR_POLLIN;
1746                     new_pollfd.desc.s = c->aprsock;
1747                     new_pollfd.client_data = c;
1748                     apr_pollset_add(readbits, &new_pollfd);
1749                 }
1750         }
1751     }
1752
1753     if (heartbeatres)
1754         fprintf(stderr, "Finished %ld requests\n", done);
1755     else
1756         printf("..done\n");
1757
1758     if (use_html)
1759         output_html_results();
1760     else
1761         output_results();
1762 }
1763
1764 /* ------------------------------------------------------- */
1765
1766 /* display copyright information */
1767 static void copyright(void)
1768 {
1769     if (!use_html) {
1770         printf("This is ApacheBench, Version %s\n", AP_AB_BASEREVISION " <$Revision: 1.118 $> apache-2.0");
1771         printf("Copyright (c) 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/\n");
1772         printf("Copyright (c) 1998-2002 The Apache Software Foundation, http://www.apache.org/\n");
1773         printf("\n");
1774     }
1775     else {
1776         printf("<p>\n");
1777         printf(" This is ApacheBench, Version %s <i>&lt;%s&gt;</i> apache-2.0<br>\n", AP_AB_BASEREVISION, "$Revision: 1.118 $");
1778         printf(" Copyright (c) 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/<br>\n");
1779         printf(" Copyright (c) 1998-2002 The Apache Software Foundation, http://www.apache.org/<br>\n");
1780         printf("</p>\n<p>\n");
1781     }
1782 }
1783
1784 /* display usage information */
1785 static void usage(const char *progname)
1786 {
1787     fprintf(stderr, "Usage: %s [options] [http"
1788 #ifdef USE_SSL
1789             "[s]"
1790 #endif
1791             "://]hostname[:port]/path\n", progname);
1792     fprintf(stderr, "Options are:\n");
1793     fprintf(stderr, "    -n requests     Number of requests to perform\n");
1794     fprintf(stderr, "    -c concurrency  Number of multiple requests to make\n");
1795     fprintf(stderr, "    -t timelimit    Seconds to max. wait for responses\n");
1796     fprintf(stderr, "    -p postfile     File containing data to POST\n");
1797     fprintf(stderr, "    -T content-type Content-type header for POSTing\n");
1798     fprintf(stderr, "    -v verbosity    How much troubleshooting info to print\n");
1799     fprintf(stderr, "    -w              Print out results in HTML tables\n");
1800     fprintf(stderr, "    -i              Use HEAD instead of GET\n");
1801     fprintf(stderr, "    -x attributes   String to insert as table attributes\n");
1802     fprintf(stderr, "    -y attributes   String to insert as tr attributes\n");
1803     fprintf(stderr, "    -z attributes   String to insert as td or th attributes\n");
1804     fprintf(stderr, "    -C attribute    Add cookie, eg. 'Apache=1234. (repeatable)\n");
1805     fprintf(stderr, "    -H attribute    Add Arbitrary header line, eg. 'Accept-Encoding: gzip'\n");
1806     fprintf(stderr, "                    Inserted after all normal header lines. (repeatable)\n");
1807     fprintf(stderr, "    -A attribute    Add Basic WWW Authentication, the attributes\n");
1808     fprintf(stderr, "                    are a colon separated username and password.\n");
1809     fprintf(stderr, "    -P attribute    Add Basic Proxy Authentication, the attributes\n");
1810     fprintf(stderr, "                    are a colon separated username and password.\n");
1811     fprintf(stderr, "    -X proxy:port   Proxyserver and port number to use\n");
1812     fprintf(stderr, "    -V              Print version number and exit\n");
1813     fprintf(stderr, "    -k              Use HTTP KeepAlive feature\n");
1814     fprintf(stderr, "    -d              Do not show percentiles served table.\n");
1815     fprintf(stderr, "    -S              Do not show confidence estimators and warnings.\n");
1816     fprintf(stderr, "    -g filename     Output collected data to gnuplot format file.\n");
1817     fprintf(stderr, "    -e filename     Output CSV file with percentages served\n");
1818 #ifdef USE_SSL
1819     fprintf(stderr, "    -s              Use httpS instead of HTTP (SSL)\n");
1820 #endif
1821     fprintf(stderr, "    -h              Display usage information (this message)\n");
1822     exit(EINVAL);
1823 }
1824
1825 /* ------------------------------------------------------- */
1826
1827 /* split URL into parts */
1828
1829 static int parse_url(char *url)
1830 {
1831     char *cp;
1832     char *h;
1833     char *scope_id;
1834     apr_status_t rv;
1835
1836     /* Save a copy for the proxy */
1837     fullurl = apr_pstrdup(cntxt, url);
1838
1839     if (strlen(url) > 7 && strncmp(url, "http://", 7) == 0) {
1840         url += 7;
1841 #ifdef USE_SSL
1842         ssl = 0;
1843 #endif
1844     }
1845     else
1846 #ifdef USE_SSL
1847     if (strlen(url) > 8 && strncmp(url, "https://", 8) == 0) {
1848         url += 8;
1849         ssl = 1;
1850     }
1851 #else
1852     if (strlen(url) > 8 && strncmp(url, "https://", 8) == 0) {
1853         fprintf(stderr, "SSL not compiled in; no https support\n");
1854         exit(1);
1855     }
1856 #endif
1857
1858     if ((cp = strchr(url, '/')) == NULL)
1859         return 1;
1860     h = apr_palloc(cntxt, cp - url + 1);
1861     memcpy(h, url, cp - url);
1862     h[cp - url] = '\0';
1863     rv = apr_parse_addr_port(&hostname, &scope_id, &port, h, cntxt);
1864     if (rv != APR_SUCCESS || !hostname || scope_id) {
1865         return 1;
1866     }
1867     strcpy(path, cp);
1868     *cp = '\0';
1869     if (*url == '[') {          /* IPv6 numeric address string */
1870         host_field = apr_psprintf(cntxt, "[%s]", hostname);
1871     }
1872     else {
1873         host_field = hostname;
1874     }
1875
1876     if (port == 0) {            /* no port specified */
1877 #ifdef USE_SSL
1878         if (ssl == 1)
1879             port = 443;
1880         else
1881 #endif
1882             port = 80;
1883     }
1884
1885     if ((
1886 #ifdef USE_SSL
1887          (ssl == 1) && (port != 443)) || (( ssl == 0 ) && 
1888 #endif
1889          (port != 80)))
1890     {
1891         colonhost = apr_psprintf(cntxt,":%d",port);
1892     } else
1893         colonhost = "";
1894     return 0;
1895 }
1896
1897 /* ------------------------------------------------------- */
1898
1899 /* read data to POST from file, save contents and length */
1900
1901 static int open_postfile(const char *pfile)
1902 {
1903     apr_file_t *postfd = NULL;
1904     apr_finfo_t finfo;
1905     apr_fileperms_t mode = APR_OS_DEFAULT;
1906     apr_size_t length;
1907     apr_status_t rv;
1908     char errmsg[120];
1909
1910     rv = apr_file_open(&postfd, pfile, APR_READ, mode, cntxt);
1911     if (rv != APR_SUCCESS) {
1912         printf("Invalid postfile name (%s): %s\n", pfile,
1913                apr_strerror(rv, errmsg, sizeof errmsg));
1914         return rv;
1915     }
1916
1917     apr_file_info_get(&finfo, APR_FINFO_NORM, postfd);
1918     postlen = (apr_size_t)finfo.size;
1919     postdata = (char *) malloc(postlen);
1920     if (!postdata) {
1921         printf("Can\'t alloc postfile buffer\n");
1922         return APR_ENOMEM;
1923     }
1924     length = postlen;
1925     rv = apr_file_read(postfd, postdata, &length);
1926     if (rv != APR_SUCCESS) {
1927         printf("error reading postfile: %s\n",
1928                apr_strerror(rv, errmsg, sizeof errmsg));
1929         return rv;
1930     }
1931     if (length != postlen) {
1932         printf("error reading postfile: read only %"
1933                APR_SIZE_T_FMT " bytes",
1934                length);
1935         return APR_EINVAL;
1936     }
1937     apr_file_close(postfd);
1938     return 0;
1939 }
1940
1941 /* ------------------------------------------------------- */
1942
1943 /* sort out command-line args and call test */
1944 int main(int argc, const char * const argv[])
1945 {
1946     int r, l;
1947     char tmp[1024];
1948     apr_status_t status;
1949     apr_getopt_t *opt;
1950     const char *optarg;
1951     char c;
1952
1953     /* table defaults  */
1954     tablestring = "";
1955     trstring = "";
1956     tdstring = "bgcolor=white";
1957     cookie[0] = '\0';
1958     auth[0] = '\0';
1959     proxyhost[0] = '\0';
1960     hdrs[0] = '\0';
1961
1962     apr_app_initialize(&argc, &argv, NULL);
1963     atexit(apr_terminate);
1964     apr_pool_create(&cntxt, NULL);
1965
1966 #ifdef NOT_ASCII
1967     status = apr_xlate_open(&to_ascii, "ISO8859-1", APR_DEFAULT_CHARSET, cntxt);
1968     if (status) {
1969         fprintf(stderr, "apr_xlate_open(to ASCII)->%d\n", status);
1970         exit(1);
1971     }
1972     status = apr_xlate_open(&from_ascii, APR_DEFAULT_CHARSET, "ISO8859-1", cntxt);
1973     if (status) {
1974         fprintf(stderr, "apr_xlate_open(from ASCII)->%d\n", status);
1975         exit(1);
1976     }
1977     status = apr_base64init_ebcdic(to_ascii, from_ascii);
1978     if (status) {
1979         fprintf(stderr, "apr_base64init_ebcdic()->%d\n", status);
1980         exit(1);
1981     }
1982 #endif
1983
1984     apr_getopt_init(&opt, cntxt, argc, argv);
1985     while ((status = apr_getopt(opt, "n:c:t:T:p:v:kVhwix:y:z:C:H:P:A:g:X:de:Sq"
1986 #ifdef USE_SSL
1987                                 "s"
1988 #endif
1989                                 ,&c, &optarg)) == APR_SUCCESS) {
1990         switch (c) {
1991         case 's':
1992 #ifdef USE_SSL
1993         ssl = 1;
1994         break;
1995 #else
1996         fprintf(stderr, "SSL not compiled in; no https support\n");
1997         exit(1);
1998 #endif
1999         case 'n':
2000             requests = atoi(optarg);
2001             if (!requests) {
2002                 err("Invalid number of requests\n");
2003             }
2004             break;
2005         case 'k':
2006             keepalive = 1;
2007             break;
2008         case 'q':
2009             heartbeatres = 0;
2010             break;
2011         case 'c':
2012             concurrency = atoi(optarg);
2013             break;
2014         case 'i':
2015             if (posting == 1)
2016                 err("Cannot mix POST and HEAD\n");
2017             posting = -1;
2018             break;
2019         case 'g':
2020             gnuplot = strdup(optarg);
2021             break;
2022         case 'd':
2023             percentile = 0;
2024             break;
2025         case 'e':
2026             csvperc = strdup(optarg);
2027             break;
2028         case 'S':
2029             confidence = 0;
2030             break;
2031         case 'p':
2032             if (posting != 0)
2033                 err("Cannot mix POST and HEAD\n");
2034
2035             if (0 == (r = open_postfile(optarg))) {
2036                 posting = 1;
2037             }
2038             else if (postdata) {
2039                 exit(r);
2040             }
2041             break;
2042         case 'v':
2043             verbosity = atoi(optarg);
2044             break;
2045         case 't':
2046             tlimit = atoi(optarg);
2047             requests = MAX_REQUESTS;    /* need to size data array on
2048                                          * something */
2049             break;
2050         case 'T':
2051             strcpy(content_type, optarg);
2052             break;
2053         case 'C':
2054             strncat(cookie, "Cookie: ", sizeof(cookie));
2055             strncat(cookie, optarg, sizeof(cookie));
2056             strncat(cookie, "\r\n", sizeof(cookie));
2057             break;
2058         case 'A':
2059             /*
2060              * assume username passwd already to be in colon separated form.
2061              * Ready to be uu-encoded.
2062              */
2063             while (apr_isspace(*optarg))
2064                 optarg++;
2065             l = apr_base64_encode(tmp, optarg, strlen(optarg));
2066             tmp[l] = '\0';
2067
2068             strncat(auth, "Authorization: Basic ", sizeof(auth));
2069             strncat(auth, tmp, sizeof(auth));
2070             strncat(auth, "\r\n", sizeof(auth));
2071             break;
2072         case 'P':
2073             /*
2074              * assume username passwd already to be in colon separated form.
2075              */
2076             while (apr_isspace(*optarg))
2077                 optarg++;
2078             l = apr_base64_encode(tmp, optarg, strlen(optarg));
2079             tmp[l] = '\0';
2080
2081             strncat(auth, "Proxy-Authorization: Basic ", sizeof(auth));
2082             strncat(auth, tmp, sizeof(auth));
2083             strncat(auth, "\r\n", sizeof(auth));
2084             break;
2085         case 'H':
2086             strncat(hdrs, optarg, sizeof(hdrs));
2087             strncat(hdrs, "\r\n", sizeof(hdrs));
2088             break;
2089         case 'w':
2090             use_html = 1;
2091             break;
2092             /*
2093              * if any of the following three are used, turn on html output
2094              * automatically
2095              */
2096         case 'x':
2097             use_html = 1;
2098             tablestring = optarg;
2099             break;
2100         case 'X':
2101             {
2102                 char *p;
2103                 /*
2104                  * assume proxy-name[:port]
2105                  */
2106                 if ((p = strchr(optarg, ':'))) {
2107                     *p = '\0';
2108                     p++;
2109                     proxyport = atoi(p);
2110                 }
2111                 strcpy(proxyhost, optarg);
2112                 isproxy = 1;
2113             }
2114             break;
2115         case 'y':
2116             use_html = 1;
2117             trstring = optarg;
2118             break;
2119         case 'z':
2120             use_html = 1;
2121             tdstring = optarg;
2122             break;
2123         case 'h':
2124             usage(argv[0]);
2125             break;
2126         case 'V':
2127             copyright();
2128             return 0;
2129         }
2130     }
2131
2132     if (opt->ind != argc - 1) {
2133         fprintf(stderr, "%s: wrong number of arguments\n", argv[0]);
2134         usage(argv[0]);
2135     }
2136
2137     if (parse_url(apr_pstrdup(cntxt, opt->argv[opt->ind++]))) {
2138         fprintf(stderr, "%s: invalid URL\n", argv[0]);
2139         usage(argv[0]);
2140     }
2141
2142
2143     if ((heartbeatres) && (requests > 150)) {
2144         heartbeatres = requests / 10;   /* Print line every 10% of requests */
2145         if (heartbeatres < 100)
2146             heartbeatres = 100; /* but never more often than once every 100
2147                                  * connections. */
2148     }
2149     else
2150         heartbeatres = 0;
2151
2152 #ifdef USE_SSL
2153 #ifdef RSAREF
2154     R_malloc_init();
2155 #else
2156     CRYPTO_malloc_init();
2157 #endif
2158     SSL_load_error_strings();
2159     SSL_library_init();
2160     bio_out=BIO_new_fp(stdout,BIO_NOCLOSE);
2161     bio_err=BIO_new_fp(stderr,BIO_NOCLOSE);
2162
2163     /* TODO: Allow force SSLv2_client_method() (TLSv1?) */
2164     if (!(ctx = SSL_CTX_new(SSLv23_client_method()))) {
2165         fprintf(stderr, "Could not init SSL CTX");
2166         ERR_print_errors_fp(stderr);
2167         exit(1);
2168     }
2169     SSL_CTX_set_options(ctx, SSL_OP_ALL);
2170 #ifdef USE_THREADS
2171     ssl_util_thread_setup(cntxt);
2172 #endif
2173 #endif
2174 #ifdef SIGPIPE
2175     apr_signal(SIGPIPE, SIG_IGN);       /* Ignore writes to connections that
2176                                          * have been closed at the other end. */
2177 #endif
2178     copyright();
2179     test();
2180     apr_pool_destroy(cntxt);
2181
2182     return 0;
2183 }