Guest User

Thomas Løcke

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