This patch modifies the support/ab.c to handle SSL/TLS
properly.

The current implementation in 2.0.54 seems to be broken
because it dumps core when I compile it with "-DUSE_SSL".
Even when I go back to 2.0.39, it still has many problems.

i.e.
- Asynchronous I/O does not work with SSL, which means
 only one slow connection prevents all other concurrent
 connections from proceeding.
- It sleeps one second for each SSL connections during
 SSL handshake.
- SIGSEGV occurs with "-v 4" because of the buffer
 overflow inside ssl_print_cert_info().
- Cannot specify either protocol version or cipher suites.

This patch makes ab work with asynchronous I/O even in
SSL/TLS, while it introduces 2 more options for SSL/TLS.

 -Z ciphersuite  Specify SSL/TLS cipher suite (See openssl ciphers)
 -f protocol     Specify SSL/TLS protocol (SSL2, SSL3, TLS1, or ALL)

 Example:
   ab -f SSL3 -Z DES-CBC3-SHA -n 1000 -c 100 https://server/

This patch also includes the modification for configure.in
to set "-DAB_USE_SSL" automatically when you configure
apache with "--enable-ssl".  You have to run buildconf
after applying this patch, of course.

--
Masaoki Kobayashi
<[EMAIL PROTECTED]>
diff -urN httpd-2.0.54/configure.in httpd-2.0.54-ab-ssl-patch/configure.in
--- httpd-2.0.54/configure.in   2005-03-30 20:00:06.000000000 +0900
+++ httpd-2.0.54-ab-ssl-patch/configure.in      2005-05-08 23:36:00.000000000 
+0900
@@ -395,6 +395,10 @@
 APACHE_SUBST(SHLIBPATH_VAR)
 APACHE_SUBST(OS_SPECIFIC_VARS)
 
+if test "$enable_ssl" != "no"; then
+  APR_ADDTO(DEFS, "-DAB_USE_SSL")
+fi
+
 PRE_SHARED_CMDS='echo ""'
 POST_SHARED_CMDS='echo ""'
 
diff -urN httpd-2.0.54/support/ab.c httpd-2.0.54-ab-ssl-patch/support/ab.c
--- httpd-2.0.54/support/ab.c   2005-02-05 05:21:18.000000000 +0900
+++ httpd-2.0.54-ab-ssl-patch/support/ab.c      2005-05-08 23:36:00.000000000 
+0900
@@ -91,7 +91,7 @@
  * ab - or to due to a change in the distribution it is compiled with 
  * (such as an APR change in for example blocking).
  */
-#define AP_AB_BASEREVISION "2.0.41-dev"    
+#define AP_AB_BASEREVISION "2.0.41-dev-ssl-patch"    
 
 /*
  * BUGS:
@@ -144,7 +144,7 @@
 #if APR_HAVE_STDLIB_H
 #include <stdlib.h>
 
-#ifdef USE_SSL
+#ifdef AB_USE_SSL
 #if ((!(RSAREF)) && (!(SYSSSL)))
 /* Libraries on most systems.. */
 #include <openssl/rsa.h>
@@ -154,6 +154,15 @@
 #include <openssl/err.h>
 #include <openssl/ssl.h>
 #include <openssl/rand.h>
+#ifdef RSAREF
+    typedef STACK X509_STACK_TYPE;
+#   define SK_NUM(x) sk_num(x)
+#   define SK_VALUE(x,y) sk_value(x,y)
+#else
+    typedef STACK_OF(X509) X509_STACK_TYPE;
+#   define SK_NUM(x) sk_X509_num(x)
+#   define SK_VALUE(x,y) sk_X509_value(x,y)
+#endif
 #else
 /* Libraries for RSAref and SYSSSL */
 #include <rsa.h>
@@ -214,15 +223,12 @@
                done;           /* Connection closed */
 
     int socknum;
-#ifdef USE_SSL
+#ifdef AB_USE_SSL
     SSL *ssl;
 #endif
 };
 
 struct data {
-#ifdef USE_SSL
-    /* XXXX insert SSL timings */
-#endif
     int read;              /* number of bytes read */
     apr_time_t starttime;  /* start time of connection in seconds since
                             * Jan. 1, 1970 */
@@ -288,10 +294,12 @@
 long good = 0, bad = 0;                /* number of good and bad requests */
 long epipe = 0;                        /* number of broken pipe writes */
 
-#ifdef USE_SSL
-int ssl = 0;
-SSL_CTX *ctx;
-BIO *bio_out,*bio_err;
+#ifdef AB_USE_SSL
+int is_ssl;
+SSL_CTX *ssl_ctx;
+char *ssl_cipher = NULL;
+char *ssl_info = NULL;
+BIO *bio_out, *bio_err;
 static void write_request(struct connection * c);
 #endif
 
@@ -351,81 +359,13 @@
     exit(rv);
 }
 
-#if defined(USE_SSL) && USE_THREADS
-/*
- * To ensure thread-safetyness in OpenSSL - work in progress
- */
-
-static apr_thread_mutex_t **lock_cs;
-static int                  lock_num_locks;
-
-static void ssl_util_thr_lock(int mode, int type,
-                              const char *file, int line)
-{
-    if (type < lock_num_locks) {
-        if (mode & CRYPTO_LOCK) {
-            apr_thread_mutex_lock(lock_cs[type]);
-        }
-        else {
-            apr_thread_mutex_unlock(lock_cs[type]);
-        }
-    }
-}
-
-static unsigned long ssl_util_thr_id(void)
-{
-    /* OpenSSL needs this to return an unsigned long.  On OS/390, the pthread 
-     * id is a structure twice that big.  Use the TCB pointer instead as a 
-     * unique unsigned long.
-     */
-#ifdef __MVS__
-    struct PSA {
-        char unmapped[540];
-        unsigned long PSATOLD;
-    } *psaptr = 0;
-
-    return psaptr->PSATOLD;
-#else
-    return (unsigned long) apr_os_thread_current();
-#endif
-}
-
-static apr_status_t ssl_util_thread_cleanup(void *data)
-{
-    CRYPTO_set_locking_callback(NULL);
-
-    /* Let the registered mutex cleanups do their own thing 
-     */
-    return APR_SUCCESS;
-}
-
-void ssl_util_thread_setup(apr_pool_t *p)
-{
-    int i;
-
-    lock_num_locks = CRYPTO_num_locks();
-    lock_cs = apr_palloc(p, lock_num_locks * sizeof(*lock_cs));
-
-    for (i = 0; i < lock_num_locks; i++) {
-        apr_thread_mutex_create(&(lock_cs[i]), APR_THREAD_MUTEX_DEFAULT, p);
-    }
-
-    CRYPTO_set_id_callback(ssl_util_thr_id);
-
-    CRYPTO_set_locking_callback(ssl_util_thr_lock);
-
-    apr_pool_cleanup_register(p, NULL, ssl_util_thread_cleanup,
-                                       apr_pool_cleanup_null);
-}
-#endif
-
 /* --------------------------------------------------------- */
 /* write out request to a connection - assumes we can write
  * (small) request out in one go into our new socket buffer
  *
  */
-#ifdef USE_SSL
-long ssl_print_cb(BIO *bio,int cmd,const char *argp,int argi,long argl,long 
ret)
+#ifdef AB_USE_SSL
+static long ssl_print_cb(BIO *bio, int cmd, const char *argp, int argi, long 
argl, long ret)
 {
     BIO *out;
 
@@ -434,20 +374,38 @@
 
     if (cmd == (BIO_CB_READ|BIO_CB_RETURN))
     {
-        BIO_printf(out,"read from %08X [%08lX] (%d bytes => %ld (0x%X))\n",
-                bio,argp,argi,ret,ret);
-        BIO_dump(out,(char *)argp,(int)ret);
+        BIO_printf(out, "read from %08X [%08lX] (%d bytes => %ld (0x%X))\n",
+                bio, argp, argi, ret, ret);
+        BIO_dump(out, (char *)argp, (int)ret);
         return(ret);
     }
     else if (cmd == (BIO_CB_WRITE|BIO_CB_RETURN))
     {
-        BIO_printf(out,"write to %08X [%08lX] (%d bytes => %ld (0x%X))\n",
-            bio,argp,argi,ret,ret);
-        BIO_dump(out,(char *)argp,(int)ret);
+        BIO_printf(out, "write to %08X [%08lX] (%d bytes => %ld (0x%X))\n",
+            bio, argp, argi, ret, ret);
+        BIO_dump(out, (char *)argp, (int)ret);
     }
     return(ret);
 }
 
+static void ssl_state_cb(const SSL *s, int w, int r)
+{
+    if (w & SSL_CB_ALERT) {
+       BIO_printf(bio_err, "SSL/TLS Alert [%s] %s:%s\n",
+           (w & SSL_CB_READ ? "read" : "write"),
+            SSL_alert_type_string_long(r),
+            SSL_alert_desc_string_long(r));
+    } else if (w & SSL_CB_LOOP) {
+       BIO_printf(bio_err, "SSL/TLS State [%s] %s\n",
+           (SSL_in_connect_init(s) ? "connect" : "-"),
+           SSL_state_string_long(s));
+    } else if (w & (SSL_CB_HANDSHAKE_START|SSL_CB_HANDSHAKE_DONE)) {
+       BIO_printf(bio_err, "SSL/TLS Handshake [%s] %s\n",
+           (w & SSL_CB_HANDSHAKE_START ? "Start" : "Done"),
+           SSL_state_string_long(s));
+    }
+}
+
 #ifndef RAND_MAX
 #include <limits.h>
 #define RAND_MAX INT_MAX
@@ -499,14 +457,12 @@
     nDone += 128;
 }
 
-int ssl_print_connection_info(bio,ssl)
-BIO *bio;
-SSL *ssl;
+int ssl_print_connection_info(BIO *bio, SSL *ssl)
 {
         SSL_CIPHER *c;
         int alg_bits,bits;
 
-        c=SSL_get_current_cipher(ssl);
+        c = SSL_get_current_cipher(ssl);
         BIO_printf(bio,"Cipher Suite Protocol   :%s\n", 
SSL_CIPHER_get_version(c));
         BIO_printf(bio,"Cipher Suite Name       :%s\n",SSL_CIPHER_get_name(c));
 
@@ -516,170 +472,125 @@
         return(1);
 }
 
-int ssl_print_cert_info(bio,x509cert)
-BIO *bio;
-X509 *x509cert;
+void ssl_print_cert_info(BIO *bio, X509 *cert)
 {
         X509_NAME *dn;
-        char buf[64];
+        char buf[1024];
 
-        BIO_printf(bio,"Certificate version: 
%d\n",X509_get_version(x509cert)+1);
+        BIO_printf(bio, "Certificate version: %d\n", X509_get_version(cert)+1);
 
         BIO_printf(bio,"Valid from: ");
-        ASN1_UTCTIME_print(bio, X509_get_notBefore(x509cert));
+        ASN1_UTCTIME_print(bio, X509_get_notBefore(cert));
         BIO_printf(bio,"\n");
 
         BIO_printf(bio,"Valid to  : ");
-        ASN1_UTCTIME_print(bio, X509_get_notAfter(x509cert));
+        ASN1_UTCTIME_print(bio, X509_get_notAfter(cert));
         BIO_printf(bio,"\n");
 
         BIO_printf(bio,"Public key is %d bits\n",
-            EVP_PKEY_bits(X509_get_pubkey(x509cert)));
+            EVP_PKEY_bits(X509_get_pubkey(cert)));
 
-        dn=X509_get_issuer_name(x509cert);
-        X509_NAME_oneline(dn, buf, BUFSIZ);
-        BIO_printf(bio,"The issuer name is %s\n", buf);
-
-        dn=X509_get_subject_name(x509cert);
-        X509_NAME_oneline(dn, buf, BUFSIZ);
-        BIO_printf(bio,"The subject name is %s\n", buf);
+        dn = X509_get_issuer_name(cert);
+        X509_NAME_oneline(dn, buf, sizeof(buf));
+        BIO_printf(bio, "The issuer name is %s\n", buf);
+
+        dn=X509_get_subject_name(cert);
+        X509_NAME_oneline(dn, buf, sizeof(buf));
+        BIO_printf(bio, "The subject name is %s\n", buf);
 
         /* dump the extension list too */
-        BIO_printf(bio,"Extension Count: %d\n",X509_get_ext_count(x509cert));
-
-        return(1);
+        BIO_printf(bio, "Extension Count: %d\n", X509_get_ext_count(cert));
 }
 
-void ssl_start_connect(struct connection * c)
+void ssl_print_info(struct connection *c)
 {
-    BIO *bio;
-    X509 *x509cert;
-#ifdef RSAREF
-    STACK *sk;
-#else
-    STACK_OF(X509) *sk;
-#endif
-    int i, count, hdone = 0;
-    char ssl_hostname[80];
-    
-    /* XXX - Verify if it's okay - TBD */
-    if (requests < concurrency)
-        requests = concurrency;
-
-    if (!(started < requests))
-        return;
-
-    c->read = 0;
-    c->bread = 0;
-    c->keepalive = 0;
-    c->cbx = 0;
-    c->gotheader = 0;
-    c->rwrite = 0;
-    if (c->ctx)
-        apr_pool_destroy(c->ctx);
-    apr_pool_create(&c->ctx, cntxt);
-
-    if ((c->ssl=SSL_new(ctx)) == NULL)
-    {
-        BIO_printf(bio_err,"SSL_new failed\n");
-        exit(1);
-    }
-
-    ssl_rand_seed();
-
-    c->start = apr_time_now();
-    memset(ssl_hostname, 0, 80);
-    sprintf(ssl_hostname, "%s:%d", hostname, port);
-
-    if ((bio = BIO_new_connect(ssl_hostname)) == NULL)
-    {
-        BIO_printf(bio_err,"BIO_new_connect failed\n");
-        exit(1);
-    }
-    SSL_set_bio(c->ssl,bio,bio);
-    SSL_set_connect_state(c->ssl);
-
-    if (verbosity >= 4)
-    {
-        BIO_set_callback(bio,ssl_print_cb);
-        BIO_set_callback_arg(bio,(void*)bio_err);
-    }
-
-    while (!hdone)
-    {
-        i = SSL_do_handshake(c->ssl);
-
-        switch (SSL_get_error(c->ssl,i))
-        {
-            case SSL_ERROR_NONE:
-                hdone=1;
-                break;
-            case SSL_ERROR_SSL:
-            case SSL_ERROR_SYSCALL:
-                BIO_printf(bio_err,"SSL connection failed\n");
-                err_conn++;
-                c->state = STATE_UNCONNECTED;
-                if (bad++ > 10) {
-                    SSL_free (c->ssl);
-                    BIO_printf(bio_err,"\nTest aborted after 10 failures\n\n");
-                    exit (1);
-                }
-                break;
-            case SSL_ERROR_WANT_READ:
-            case SSL_ERROR_WANT_WRITE:
-            case SSL_ERROR_WANT_CONNECT:
-                BIO_printf(bio_err, "Waiting .. sleep(1)\n");
-                apr_sleep(apr_time_from_sec(1));
-                c->state = STATE_CONNECTED;
-                c->rwrite = 0;
-                break;
-            case SSL_ERROR_ZERO_RETURN:
-                BIO_printf(bio_err,"socket closed\n");
-                break;
-        }
-    }
-    
-    if (verbosity >= 2)
-    {
-        BIO_printf(bio_err, "\n");
-        sk = SSL_get_peer_cert_chain(c->ssl);
-#ifdef RSAREF
-        if ((count = sk_num(sk)) > 0)
-#else
-        if ((count = sk_X509_num(sk)) > 0)
-#endif
-        {
-            for (i=1; i<count; i++)
-            {
-#ifdef RSAREF
-                x509cert = (X509 *)sk_value(sk,i);
-#else
-                x509cert = (X509 *)sk_X509_value(sk,i);
-#endif
-                ssl_print_cert_info(bio_out,x509cert);
-                X509_free(x509cert);
-            }
-        }
-
-        x509cert = SSL_get_peer_certificate(c->ssl);
-        if (x509cert == NULL)
-            BIO_printf(bio_out, "Anon DH\n");
-        else
-        {
-            BIO_printf(bio_out, "Peer certificate\n");
-            ssl_print_cert_info(bio_out,x509cert);
-            X509_free(x509cert);
-        }
+    X509_STACK_TYPE *sk;
+    X509 *cert;
+    int count;
+
+    BIO_printf(bio_err, "\n");
+    sk = SSL_get_peer_cert_chain(c->ssl);
+    if ((count = SK_NUM(sk)) > 0) {
+       int i;
+       for (i=1; i<count; i++) {
+           cert = (X509 *)SK_VALUE(sk, i);
+           ssl_print_cert_info(bio_out, cert);
+           X509_free(cert);
+       }
+    }
+    cert = SSL_get_peer_certificate(c->ssl);
+    if (cert == NULL) {
+       BIO_printf(bio_out, "Anon DH\n");
+    } else {
+       BIO_printf(bio_out, "Peer certificate\n");
+       ssl_print_cert_info(bio_out, cert);
+       X509_free(cert);
+    }
+    ssl_print_connection_info(bio_err,c->ssl);
+    SSL_SESSION_print(bio_err, SSL_get_session(c->ssl));
+}
+
+void ssl_proceed_handshake(struct connection *c)
+{
+    int do_next = 1;
+
+    while(do_next) {
+       int ret, ecode;
+       apr_pollfd_t new_pollfd;
+
+       ret = SSL_do_handshake(c->ssl);
+       ecode = SSL_get_error(c->ssl, ret);
+
+       switch(ecode) {
+       case SSL_ERROR_NONE:
+           if (verbosity >= 2)
+               ssl_print_info(c);
+           if (ssl_info == NULL) {
+               SSL_CIPHER *ci;
+               X509 *cert;
+               int sk_bits, pk_bits;
+
+               ci = SSL_get_current_cipher(c->ssl);
+               SSL_CIPHER_get_bits(ci, &sk_bits);
+               cert = SSL_get_peer_certificate(c->ssl);
+               if (cert)
+                   pk_bits = EVP_PKEY_bits(X509_get_pubkey(cert));
+               else
+                   pk_bits = 0;  /* Anon DH */
 
-        ssl_print_connection_info(bio_err,c->ssl);
-        SSL_SESSION_print(bio_err,SSL_get_session(c->ssl));
+               ssl_info = malloc(128);
+               apr_snprintf(ssl_info, 128, "%s,%s,%d,%d",
+                   SSL_CIPHER_get_version(ci),
+                   SSL_CIPHER_get_name(ci),
+                   pk_bits, sk_bits);
+           }
+           write_request(c);
+           do_next = 0;
+           break;
+       case SSL_ERROR_WANT_READ:
+           new_pollfd.desc_type = APR_POLL_SOCKET;
+           new_pollfd.reqevents = APR_POLLIN;
+           new_pollfd.desc.s = c->aprsock;
+           new_pollfd.client_data = c;
+           apr_pollset_add(readbits, &new_pollfd);
+           do_next = 0;
+           break;
+       case SSL_ERROR_WANT_WRITE:
+           /* Try again */
+           do_next = 1;
+           break;
+       case SSL_ERROR_WANT_CONNECT:
+       case SSL_ERROR_SSL:
+       case SSL_ERROR_SYSCALL:
+           /* Unexpected result */
+           BIO_printf(bio_err, "SSL handshake failed (%d).\n", ecode);
+           ERR_print_errors(bio_err);
+           close_connection(c);
+           break;
+       }
     }
-
-    /* connected first time */
-    started++;
-    write_request(c);
 }
-#endif /* USE_SSL */
+#endif /* AB_USE_SSL */
 
 static void write_request(struct connection * c)
 {
@@ -692,9 +603,6 @@
         * First time round ?
         */
        if (c->rwrite == 0) {
-#ifdef USE_SSL
-            if (ssl != 1)
-#endif
            apr_socket_timeout_set(c->aprsock, 0);
            c->connect = tnow;
            c->rwrite = reqlen;
@@ -708,19 +616,19 @@
            return;
        }
 
-#ifdef USE_SSL
-        if (ssl == 1) {
+#ifdef AB_USE_SSL
+        if (c->ssl) {
             apr_size_t e_ssl;
-            e_ssl = SSL_write(c->ssl,request + c->rwrote, l);
-            if (e_ssl != l)
-            {
+            e_ssl = SSL_write(c->ssl, request + c->rwrote, l);
+            if (e_ssl != l) {
                 printf("SSL write failed - closing connection\n");
+               ERR_print_errors(bio_err);
                 close_connection (c);
                 return;
             }
             l = e_ssl;
-        }
-        else
+           e = APR_SUCCESS;
+        } else
 #endif
        e = apr_send(c->aprsock, request + c->rwrote, &l);
 
@@ -730,9 +638,6 @@
        if (l == c->rwrite)
            break;
 
-#ifdef USE_SSL
-        if (ssl != 1)
-#endif
        if (e != APR_SUCCESS) {
            /*
             * Let's hope this traps EWOULDBLOCK too !
@@ -751,9 +656,6 @@
     totalposted += c->rwrite;
     c->state = STATE_READ;
     c->endwrite = apr_time_now();
-#ifdef USE_SSL
-    if (ssl != 1)
-#endif
     {
         apr_pollfd_t new_pollfd;
         new_pollfd.desc_type = APR_POLL_SOCKET;
@@ -820,6 +722,10 @@
     printf("Server Software:        %s\n", servername);
     printf("Server Hostname:        %s\n", hostname);
     printf("Server Port:            %hd\n", port);
+#ifdef AB_USE_SSL
+    if (is_ssl)
+    printf("SSL/TLS Protocol:       %s\n", ssl_info);
+#endif
     printf("\n");
     printf("Document Path:          %s\n", path);
     printf("Document Length:        %" APR_SIZE_T_FMT " bytes\n", doclen);
@@ -1184,13 +1090,6 @@
 {
     apr_status_t rv;
 
-#ifdef USE_SSL
-    if (ssl == 1) {
-        ssl_start_connect(c);
-        return;
-    }
-#endif
-    
     if (!(started < requests))
        return;
 
@@ -1213,6 +1112,28 @@
         apr_err("socket nonblock", rv);
     }
     c->start = apr_time_now();
+#ifdef AB_USE_SSL
+    if (is_ssl) {
+       BIO *bio;
+       apr_os_sock_t fd;
+       if ((c->ssl = SSL_new(ssl_ctx)) == NULL) {
+           BIO_printf(bio_err, "SSL_new failed.\n");
+           ERR_print_errors(bio_err);
+           exit(1);
+       }
+       ssl_rand_seed();
+       apr_os_sock_get(&fd, c->aprsock);
+       bio = BIO_new_socket(fd, BIO_NOCLOSE);
+       SSL_set_bio(c->ssl, bio, bio);
+       SSL_set_connect_state(c->ssl);
+       if (verbosity >= 4) {
+           BIO_set_callback(bio, ssl_print_cb);
+           BIO_set_callback_arg(bio, bio_err);
+       }
+    } else {
+       c->ssl = NULL;
+    }
+#endif
     if ((rv = apr_connect(c->aprsock, destsa)) != APR_SUCCESS) {
        if (APR_STATUS_IS_EINPROGRESS(rv)) {
             apr_pollfd_t new_pollfd;
@@ -1246,6 +1167,11 @@
     /* connected first time */
     c->state = STATE_CONNECTED;
     started++;
+#ifdef AB_USE_SSL
+    if (c->ssl)
+       ssl_proceed_handshake(c);
+    else
+#endif
     write_request(c);
 }
 
@@ -1288,18 +1214,18 @@
        }
     }
 
-#ifdef USE_SSL
-    if (ssl == 1) {
-        SSL_shutdown(c->ssl);
-        SSL_free(c->ssl);
-    }
-    else
-#endif
     {
         apr_pollfd_t remove_pollfd;
         remove_pollfd.desc_type = APR_POLL_SOCKET;
         remove_pollfd.desc.s = c->aprsock;
         apr_pollset_remove(readbits, &remove_pollfd);
+#ifdef AB_USE_SSL
+       if (c->ssl) {
+           SSL_shutdown(c->ssl);
+           SSL_free(c->ssl);
+           c->ssl = NULL;
+       }
+#endif
         apr_socket_close(c->aprsock);
     }
     c->state = STATE_UNCONNECTED;
@@ -1321,17 +1247,17 @@
     char respcode[4];          /* 3 digits and null */
 
     r = sizeof(buffer);
-#ifdef USE_SSL
-    if (ssl == 1)
-    {
+#ifdef AB_USE_SSL
+    if (c->ssl) {
         status = SSL_read (c->ssl, buffer, r);
         if (status <= 0) {
             good++; c->read = 0;
             if (status < 0) printf("SSL read failed - closing connection\n");
+           ERR_print_errors(bio_err);
             close_connection(c);
             return;
         }
-    r = status;
+       r = status;
     }
     else {
 #endif
@@ -1350,7 +1276,7 @@
          * certain number of them before completely failing? -aaron */
         apr_err("apr_recv", status);
     }
-#ifdef USE_SSL
+#ifdef AB_USE_SSL
     }
 #endif
 
@@ -1622,9 +1548,6 @@
 #endif                         /* NOT_ASCII */
 
     /* This only needs to be done once */
-#ifdef USE_SSL
-    if (ssl != 1)
-#endif
     if ((rv = apr_sockaddr_info_get(&destsa, connecthost, APR_UNSPEC, 
connectport, 0, cntxt))
        != APR_SUCCESS) {
        char buf[120];
@@ -1656,11 +1579,6 @@
        }
 
        n = concurrency;
-#ifdef USE_SSL
-        if (ssl == 1)
-            status = APR_SUCCESS;
-        else
-#endif
        status = apr_pollset_poll(readbits, aprtimeout, &n, &pollresults);
        if (status != APR_SUCCESS)
            apr_err("apr_poll", status);
@@ -1676,16 +1594,18 @@
            /*
             * If the connection isn't connected how can we check it?
             */
-           if (c->state == STATE_UNCONNECTED)
+           if (c->state == STATE_UNCONNECTED) {
                continue;
+           }
 
-#ifdef USE_SSL
-            if (ssl == 1)
-                rv = APR_POLLIN;
-            else
-#endif
             rv = next_fd->rtnevents;
 
+#ifdef AB_USE_SSL
+           if (c->state == STATE_CONNECTED && c->ssl && SSL_in_init(c->ssl)) {
+               ssl_proceed_handshake(c);
+               continue;
+           }
+#endif
            /*
             * Notes: APR_POLLHUP is set after FIN is received on some
             * systems, so treat that like APR_POLLIN so that we try to read
@@ -1727,6 +1647,11 @@
                     }
                     else {
                         c->state = STATE_CONNECTED;
+#ifdef AB_USE_SSL
+                       if (c->ssl)
+                           ssl_proceed_handshake(c);
+                       else
+#endif
                         write_request(c);
                     }
                 }
@@ -1742,17 +1667,14 @@
             * connection is in STATE_READ or STATE_CONNECTING we'll add the
             * socket back in as APR_POLLIN.
             */
-#ifdef USE_SSL
-            if (ssl != 1)
-#endif
-                if (c->state == STATE_READ) {
-                    apr_pollfd_t new_pollfd;
-                    new_pollfd.desc_type = APR_POLL_SOCKET;
-                    new_pollfd.reqevents = APR_POLLIN;
-                    new_pollfd.desc.s = c->aprsock;
-                    new_pollfd.client_data = c;
-                    apr_pollset_add(readbits, &new_pollfd);
-                }
+           if (c->state == STATE_READ) {
+               apr_pollfd_t new_pollfd;
+               new_pollfd.desc_type = APR_POLL_SOCKET;
+               new_pollfd.reqevents = APR_POLLIN;
+               new_pollfd.desc.s = c->aprsock;
+               new_pollfd.client_data = c;
+               apr_pollset_add(readbits, &new_pollfd);
+           }
        }
     }
 
@@ -1791,7 +1713,7 @@
 static void usage(const char *progname)
 {
     fprintf(stderr, "Usage: %s [options] [http"
-#ifdef USE_SSL
+#ifdef AB_USE_SSL
            "[s]"
 #endif
            "://]hostname[:port]/path\n", progname);
@@ -1821,10 +1743,11 @@
     fprintf(stderr, "    -S              Do not show confidence estimators and 
warnings.\n");
     fprintf(stderr, "    -g filename     Output collected data to gnuplot 
format file.\n");
     fprintf(stderr, "    -e filename     Output CSV file with percentages 
served\n");
-#ifdef USE_SSL
-    fprintf(stderr, "    -s              Use httpS instead of HTTP (SSL)\n");
-#endif
     fprintf(stderr, "    -h              Display usage information (this 
message)\n");
+#ifdef AB_USE_SSL
+    fprintf(stderr, "    -Z ciphersuite  Specify SSL/TLS cipher suite (See 
openssl ciphers)\n");
+    fprintf(stderr, "    -f protocol     Specify SSL/TLS protocol (SSL2, SSL3, 
TLS1, or ALL)\n");
+#endif
     exit(EINVAL);
 }
 
@@ -1844,22 +1767,20 @@
 
     if (strlen(url) > 7 && strncmp(url, "http://";, 7) == 0) {
        url += 7;
-#ifdef USE_SSL
-       ssl = 0;
+#ifdef AB_USE_SSL
+       is_ssl = 0;
 #endif
     }
     else
-#ifdef USE_SSL
     if (strlen(url) > 8 && strncmp(url, "https://";, 8) == 0) {
+#ifdef AB_USE_SSL
        url += 8;
-       ssl = 1;
-    }
+       is_ssl = 1;
 #else
-    if (strlen(url) > 8 && strncmp(url, "https://";, 8) == 0) {
        fprintf(stderr, "SSL not compiled in; no https support\n");
        exit(1);
-    }
 #endif
+    }
 
     if ((cp = strchr(url, '/')) == NULL)
        return 1;
@@ -1880,8 +1801,8 @@
     }
 
     if (port == 0) {           /* no port specified */
-#ifdef USE_SSL
-        if (ssl == 1)
+#ifdef AB_USE_SSL
+        if (is_ssl)
             port = 443;
         else
 #endif
@@ -1889,8 +1810,8 @@
     }
 
     if ((
-#ifdef USE_SSL
-         (ssl == 1) && (port != 443)) || (( ssl == 0 ) && 
+#ifdef AB_USE_SSL
+         is_ssl && (port != 443)) || (!is_ssl && 
 #endif
          (port != 80)))
     {
@@ -1955,6 +1876,9 @@
     apr_getopt_t *opt;
     const char *optarg;
     char c;
+#ifdef AB_USE_SSL
+    SSL_METHOD *meth = SSLv23_client_method();
+#endif
 
     /* table defaults  */
     tablestring = "";
@@ -1989,19 +1913,11 @@
 
     apr_getopt_init(&opt, cntxt, argc, argv);
     while ((status = apr_getopt(opt, "n:c:t:T:p:v:kVhwix:y:z:C:H:P:A:g:X:de:Sq"
-#ifdef USE_SSL
-                               "s"
+#ifdef AB_USE_SSL
+       "Z:f:"
 #endif
                                ,&c, &optarg)) == APR_SUCCESS) {
        switch (c) {
-       case 's':
-#ifdef USE_SSL
-        ssl = 1;
-        break;
-#else
-        fprintf(stderr, "SSL not compiled in; no https support\n");
-        exit(1);
-#endif
        case 'n':
            requests = atoi(optarg);
            if (!requests) {
@@ -2133,6 +2049,22 @@
        case 'V':
            copyright();
            return 0;
+#ifdef AB_USE_SSL
+       case 'Z':
+           ssl_cipher = strdup(optarg);
+           break;
+       case 'f':
+           if (strncasecmp(optarg, "ALL", 3) == 0) {
+               meth = SSLv23_client_method();
+           } else if (strncasecmp(optarg, "SSL2", 4) == 0) {
+               meth = SSLv2_client_method();
+           } else if (strncasecmp(optarg, "SSL3", 4) == 0) {
+               meth = SSLv3_client_method();
+           } else if (strncasecmp(optarg, "TLS1", 4) == 0) {
+               meth = TLSv1_client_method();
+           }
+           break;
+#endif
        }
     }
 
@@ -2161,7 +2093,7 @@
     else
        heartbeatres = 0;
 
-#ifdef USE_SSL
+#ifdef AB_USE_SSL
 #ifdef RSAREF
     R_malloc_init();
 #else
@@ -2169,19 +2101,25 @@
 #endif
     SSL_load_error_strings();
     SSL_library_init();
-    bio_out=BIO_new_fp(stdout,BIO_NOCLOSE);
-    bio_err=BIO_new_fp(stderr,BIO_NOCLOSE);
+    bio_out = BIO_new_fp(stdout, BIO_NOCLOSE);
+    bio_err = BIO_new_fp(stderr, BIO_NOCLOSE);
 
-    /* TODO: Allow force SSLv2_client_method() (TLSv1?) */
-    if (!(ctx = SSL_CTX_new(SSLv23_client_method()))) {
-       fprintf(stderr, "Could not init SSL CTX");
+    if (!(ssl_ctx = SSL_CTX_new(meth))) {
+       fprintf(stderr, "Could not initialize an SSL context.\n");
        ERR_print_errors_fp(stderr);
        exit(1);
     }
-    SSL_CTX_set_options(ctx, SSL_OP_ALL);
-#ifdef USE_THREADS
-    ssl_util_thread_setup(cntxt);
-#endif
+    SSL_CTX_set_options(ssl_ctx, SSL_OP_ALL);
+    if (ssl_cipher != NULL) {
+       if (!SSL_CTX_set_cipher_list(ssl_ctx, ssl_cipher)) {
+           fprintf(stderr, "error setting cipher list [%s]\n", ssl_cipher);
+           ERR_print_errors_fp(stderr);
+           exit(1);
+       }
+    }
+    if (verbosity >= 3) {
+       SSL_CTX_set_info_callback(ssl_ctx, ssl_state_cb);
+    }
 #endif
 #ifdef SIGPIPE
     apr_signal(SIGPIPE, SIG_IGN);       /* Ignore writes to connections that

Reply via email to