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