Skip to content

Commit 252b52c

Browse files
committed
Fix hang when using eventlet and ssl
The eventlet read loop runs select before each recv call. This will fail because recv() on an ssl socket might read more data than requested from the underlying socket in order to have enough context for decryption. These extra bytes would be returned by the next recv on the ssl socket, but are not known to underlying socket so select will hang. It is my understanding that eventlet implements blocking IO by using poll under the hood and yielding, so the select should not be necessary at all
1 parent 2f359cd commit 252b52c

1 file changed

Lines changed: 10 additions & 18 deletions

File tree

cassandra/io/eventletreactor.py

Lines changed: 10 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,9 @@
1818

1919
from errno import EALREADY, EINPROGRESS, EWOULDBLOCK, EINVAL
2020
import eventlet
21-
from eventlet.green import select, socket
21+
from eventlet.green import socket
22+
import ssl
2223
from eventlet.queue import Queue
23-
from functools import partial
2424
import logging
2525
import os
2626
from threading import Event
@@ -37,7 +37,8 @@
3737
def is_timeout(err):
3838
return (
3939
err in (EINPROGRESS, EALREADY, EWOULDBLOCK) or
40-
(err == EINVAL and os.name in ('nt', 'ce'))
40+
(err == EINVAL and os.name in ('nt', 'ce')) or
41+
(isinstance(err, ssl.SSLError) and err.args[0] == 'timed out')
4142
)
4243

4344

@@ -138,26 +139,17 @@ def handle_write(self):
138139
return # Leave the write loop
139140

140141
def handle_read(self):
141-
run_select = partial(select.select, (self._socket,), (), ())
142142
while True:
143-
try:
144-
run_select()
145-
except Exception as exc:
146-
if not self.is_closed:
147-
log.debug("Exception during read select() for %s: %s",
148-
self, exc)
149-
self.defunct(exc)
150-
return
151-
152143
try:
153144
buf = self._socket.recv(self.in_buffer_size)
154145
self._iobuf.write(buf)
155146
except socket.error as err:
156-
if not is_timeout(err):
157-
log.debug("Exception during socket recv for %s: %s",
158-
self, err)
159-
self.defunct(err)
160-
return # leave the read loop
147+
if is_timeout(err):
148+
continue
149+
log.debug("Exception during socket recv for %s: %s",
150+
self, err)
151+
self.defunct(err)
152+
return # leave the read loop
161153

162154
if self._iobuf.tell():
163155
self.process_io_buffer()

0 commit comments

Comments
 (0)