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