Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 01 Apr 2009 16:45:54 +0900
From:      Jun Kuriyama <kuriyama@FreeBSD.org>
To:        apache@FreeBSD.org
Subject:   ab(1) fix (Operation already in progress (37))
Message-ID:  <7m7i2424wd.wl%kuriyama@s2factory.co.jp>

next in thread | raw e-mail | index | archive | help
--Multipart_Wed_Apr__1_16:45:54_2009-1
Content-Type: text/plain; charset=US-ASCII


Hi,

It seems Philip already watch this issue, but I just got same problem
so propose fix to our ports CVS repo.

As reported in Bugzilla for Apache (bug#44584), ab(1) failed to
continue connecting when using concurrent (or many) connections.

> apr_socket_connect(): Operation already in progress (37)

Fix for this was committed into trunk, and this patch can be applied
to 2.2.11 without problem.

I tested this patch locally, and it works fine.


--- suggested log
- Add a patch to fix ab(1) fails to connect with "Operation already in
  progress (37)" errno.

References:	https://issues.apache.org/bugzilla/show_bug.cgi?id=44584
Obtained from:	http://svn.apache.org/viewvc/httpd/httpd/trunk/support/ab.c?r1=748396&r2=749438


-- 
Jun Kuriyama <kuriyama@FreeBSD.org> // FreeBSD Project
         <kuriyama@s2factory.co.jp> // S2 Factory, Inc.

--Multipart_Wed_Apr__1_16:45:54_2009-1
Content-Type: application/octet-stream; type=patch
Content-Disposition: attachment; filename="apache22.diff"
Content-Transfer-Encoding: 7bit

Index: Makefile
===================================================================
RCS file: /home/ncvs/ports/www/apache22/Makefile,v
retrieving revision 1.232
diff -u -r1.232 Makefile
--- Makefile	29 Jan 2009 23:51:46 -0000	1.232
+++ Makefile	1 Apr 2009 07:22:26 -0000
@@ -9,7 +9,7 @@
 
 PORTNAME=	apache
 PORTVERSION=	2.2.11
-PORTREVISION?=	3
+PORTREVISION?=	4
 CATEGORIES=	www
 MASTER_SITES=	${MASTER_SITE_APACHE_HTTPD}
 DISTNAME=	httpd-${PORTVERSION}
Index: files/patch-support:ab.c
===================================================================
RCS file: files/patch-support:ab.c
diff -N files/patch-support:ab.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ files/patch-support:ab.c	1 Apr 2009 07:09:34 -0000
@@ -0,0 +1,262 @@
+--- support/ab.c.orig	2008-12-01 00:47:31.000000000 +0900
++++ support/ab.c	2009-04-01 16:08:09.000000000 +0900
+@@ -208,13 +208,18 @@
+ /* maximum number of requests on a time limited test */
+ #define MAX_REQUESTS (INT_MAX > 50000 ? 50000 : INT_MAX)
+ 
+-/* good old state hostname */
+-#define STATE_UNCONNECTED 0
+-#define STATE_CONNECTING  1     /* TCP connect initiated, but we don't
++/* connection state
++ * don't add enums or rearrange or otherwise change values without
++ * visiting set_conn_state()
++ */
++typedef enum {
++    STATE_UNCONNECTED = 0,
++    STATE_CONNECTING,           /* TCP connect initiated, but we don't
+                                  * know if it worked yet
+                                  */
+-#define STATE_CONNECTED   2     /* we know TCP connect completed */
+-#define STATE_READ        3
++    STATE_CONNECTED,            /* we know TCP connect completed */
++    STATE_READ
++} connect_state_e;
+ 
+ #define CBUFFSIZE (2048)
+ 
+@@ -239,6 +244,7 @@
+                done;            /* Connection closed */
+ 
+     int socknum;
++    apr_int16_t reqevents;      /* current poll events for this socket */
+ #ifdef USE_SSL
+     SSL *ssl;
+ #endif
+@@ -383,6 +389,56 @@
+     exit(rv);
+ }
+ 
++static void set_polled_events(struct connection *c, apr_int16_t new_reqevents)
++{
++    apr_int16_t old_reqevents = c->reqevents;
++    apr_pollfd_t pfd;
++    apr_status_t rv;
++    char buf[120];
++
++    if (old_reqevents != new_reqevents) {
++        pfd.desc_type = APR_POLL_SOCKET;
++        pfd.desc.s = c->aprsock;
++        pfd.client_data = c;
++
++        if (old_reqevents != 0) {
++            pfd.reqevents = old_reqevents;
++            rv = apr_pollset_remove(readbits, &pfd);
++            if (rv != APR_SUCCESS) {
++                apr_err("apr_pollset_remove()", rv);
++            }
++        }
++
++        if (new_reqevents != 0) {
++            pfd.reqevents = new_reqevents;
++            rv = apr_pollset_add(readbits, &pfd);
++            if (rv != APR_SUCCESS) {
++                apr_err("apr_pollset_add()", rv);
++                exit(1);
++            }
++        }
++
++        c->reqevents = new_reqevents;
++    }
++}
++
++static void set_conn_state(struct connection *c, connect_state_e new_state)
++{
++    apr_int16_t events_by_state[] = {
++        0,           /* for STATE_UNCONNECTED */
++        APR_POLLOUT, /* for STATE_CONNECTING */
++        APR_POLLIN,  /* for STATE_CONNECTED; we don't poll in this state,
++                      * so prepare for polling in the following state --
++                      * STATE_READ
++                      */
++        APR_POLLIN   /* for STATE_READ */
++    };
++
++    c->state = new_state;
++
++    set_polled_events(c, events_by_state[new_state]);
++}
++
+ /* --------------------------------------------------------- */
+ /* write out request to a connection - assumes we can write
+  * (small) request out in one go into our new socket buffer
+@@ -556,7 +612,6 @@
+ 
+     while (do_next) {
+         int ret, ecode;
+-        apr_pollfd_t new_pollfd;
+ 
+         ret = SSL_do_handshake(c->ssl);
+         ecode = SSL_get_error(c->ssl, ret);
+@@ -588,11 +643,7 @@
+             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);
++            set_polled_events(c, APR_POLLIN);
+             do_next = 0;
+             break;
+         case SSL_ERROR_WANT_WRITE:
+@@ -668,16 +719,8 @@
+         c->rwrite -= l;
+     } while (c->rwrite);
+ 
+-    c->state = STATE_READ;
+     c->endwrite = lasttime = apr_time_now();
+-    {
+-        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);
+-    }
++    set_conn_state(c, STATE_READ);
+ }
+ 
+ /* --------------------------------------------------------- */
+@@ -1191,21 +1234,12 @@
+ #endif
+     if ((rv = apr_socket_connect(c->aprsock, destsa)) != APR_SUCCESS) {
+         if (APR_STATUS_IS_EINPROGRESS(rv)) {
+-            apr_pollfd_t new_pollfd;
+-            c->state = STATE_CONNECTING;
++            set_conn_state(c, STATE_CONNECTING);
+             c->rwrite = 0;
+-            new_pollfd.desc_type = APR_POLL_SOCKET;
+-            new_pollfd.reqevents = APR_POLLOUT;
+-            new_pollfd.desc.s = c->aprsock;
+-            new_pollfd.client_data = c;
+-            apr_pollset_add(readbits, &new_pollfd);
+             return;
+         }
+         else {
+-            apr_pollfd_t remove_pollfd;
+-            remove_pollfd.desc_type = APR_POLL_SOCKET;
+-            remove_pollfd.desc.s = c->aprsock;
+-            apr_pollset_remove(readbits, &remove_pollfd);
++            set_conn_state(c, STATE_UNCONNECTED);
+             apr_socket_close(c->aprsock);
+             err_conn++;
+             if (bad++ > 10) {
+@@ -1213,14 +1247,14 @@
+                    "\nTest aborted after 10 failures\n\n");
+                 apr_err("apr_socket_connect()", rv);
+             }
+-            c->state = STATE_UNCONNECTED;
++            
+             start_connect(c);
+             return;
+         }
+     }
+ 
+     /* connected first time */
+-    c->state = STATE_CONNECTED;
++    set_conn_state(c, STATE_CONNECTED); /* will this waste a pollset call? */
+     started++;
+ #ifdef USE_SSL
+     if (c->ssl) {
+@@ -1269,21 +1303,15 @@
+         }
+     }
+ 
+-    {
+-        apr_pollfd_t remove_pollfd;
+-        remove_pollfd.desc_type = APR_POLL_SOCKET;
+-        remove_pollfd.desc.s = c->aprsock;
+-        apr_pollset_remove(readbits, &remove_pollfd);
++    set_conn_state(c, STATE_UNCONNECTED);
+ #ifdef USE_SSL
+-        if (c->ssl) {
+-            SSL_shutdown(c->ssl);
+-            SSL_free(c->ssl);
+-            c->ssl = NULL;
+-        }
+-#endif
+-        apr_socket_close(c->aprsock);
++    if (c->ssl) {
++        SSL_shutdown(c->ssl);
++        SSL_free(c->ssl);
++        c->ssl = NULL;
+     }
+-    c->state = STATE_UNCONNECTED;
++#endif
++    apr_socket_close(c->aprsock);
+ 
+     /* connect again */
+     start_connect(c);
+@@ -1401,10 +1429,7 @@
+             }
+             else {
+             /* header is in invalid or too big - close connection */
+-                apr_pollfd_t remove_pollfd;
+-                remove_pollfd.desc_type = APR_POLL_SOCKET;
+-                remove_pollfd.desc.s = c->aprsock;
+-                apr_pollset_remove(readbits, &remove_pollfd);
++                set_conn_state(c, STATE_UNCONNECTED);
+                 apr_socket_close(c->aprsock);
+                 err_response++;
+                 if (bad++ > 10) {
+@@ -1727,11 +1752,7 @@
+             }
+             if (rv & APR_POLLOUT) {
+                 if (c->state == STATE_CONNECTING) {
+-                    apr_pollfd_t remove_pollfd;
+                     rv = apr_socket_connect(c->aprsock, destsa);
+-                    remove_pollfd.desc_type = APR_POLL_SOCKET;
+-                    remove_pollfd.desc.s = c->aprsock;
+-                    apr_pollset_remove(readbits, &remove_pollfd);
+                     if (rv != APR_SUCCESS) {
+                         apr_socket_close(c->aprsock);
+                         err_conn++;
+@@ -1740,12 +1761,12 @@
+                                     "\nTest aborted after 10 failures\n\n");
+                             apr_err("apr_socket_connect()", rv);
+                         }
+-                        c->state = STATE_UNCONNECTED;
++                        set_conn_state(c, STATE_UNCONNECTED);
+                         start_connect(c);
+                         continue;
+                     }
+                     else {
+-                        c->state = STATE_CONNECTED;
++                        set_conn_state(c, STATE_CONNECTED);
+                         started++;
+ #ifdef USE_SSL
+                         if (c->ssl)
+@@ -1759,22 +1780,6 @@
+                     write_request(c);
+                 }
+             }
+-
+-            /*
+-             * When using a select based poll every time we check the bits
+-             * are reset. In 1.3's ab we copied the FD_SET's each time
+-             * through, but here we're going to check the state and if the
+-             * connection is in STATE_READ or STATE_CONNECTING we'll add the
+-             * socket back in as APR_POLLIN.
+-             */
+-                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);
+-                }
+         }
+     } while (lasttime < stoptime && done < requests);
+     

--Multipart_Wed_Apr__1_16:45:54_2009-1--



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?7m7i2424wd.wl%kuriyama>