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