]> granicus.if.org Git - libevent/commitdiff
Fix a 100%-CPU bug where an SSL connection would sometimes never stop trying to write
authorNick Mathewson <nickm@torproject.org>
Wed, 20 Oct 2010 17:41:02 +0000 (13:41 -0400)
committerNick Mathewson <nickm@torproject.org>
Wed, 20 Oct 2010 17:41:02 +0000 (13:41 -0400)
If an SSL connection becamse disabled or suspended before became open,
it could (under the right circumstances) wind up without ever getting
its write callback disabled.

The most correct fix is probably more subtle, and involves checking
all caseswhen a write callback is enabled or disabled.  This fix is
more blunt, and explicitly checks whether the callback should have
been disabled at the end of the callback to prevent infinite looping.

Diagnosed with help from Sebastian Hahn

bufferevent_openssl.c

index 529c1a87703e728ab990ff070e713da9d65f39ee..e48251c3c87423d7da7518ff211d1590016307ae 100644 (file)
@@ -732,6 +732,14 @@ consider_reading(struct bufferevent_openssl *bev_ssl)
                if (r <= 0)
                        break;
        }
+
+       if (!bev_ssl->underlying) {
+               /* Should be redundant, but let's avoid busy-looping */
+               if (bev_ssl->bev.read_suspended ||
+                   !(bev_ssl->bev.bev.enabled & EV_READ)) {
+                       event_del(&bev_ssl->bev.bev.ev_read);
+               }
+       }
 }
 
 static void
@@ -767,8 +775,15 @@ consider_writing(struct bufferevent_openssl *bev_ssl)
                        break;
        }
 
-       if (!bev_ssl->underlying && !evbuffer_get_length(output))
-               event_del(&bev_ssl->bev.bev.ev_write);
+       if (!bev_ssl->underlying) {
+               if (evbuffer_get_length(output) == 0) {
+                       event_del(&bev_ssl->bev.bev.ev_write);
+               } else if (bev_ssl->bev.write_suspended ||
+                   !(bev_ssl->bev.bev.enabled & EV_WRITE)) {
+                       /* Should be redundant, but let's avoid busy-looping */
+                       event_del(&bev_ssl->bev.bev.ev_write);
+               }
+       }
 }
 
 static void