Geard: Handle connections closed while sending

If a connection is closed while sending a large amount of data,
the send() call may return EAGAIN, even though the socket is in
CLOSE_WAIT.  In that case, just continue queuing the data, and
let the main loop handle the disconnect (which it will detect
via the poll call followed by a null read).

Change-Id: Ib15eae81077b58d2f95fb0989ed1139c6d542f49
This commit is contained in:
James E. Blair 2016-07-15 14:56:42 -07:00
parent defb9722b8
commit 550873b76a
1 changed files with 26 additions and 22 deletions

View File

@ -2338,28 +2338,32 @@ class NonBlockingConnection(Connection):
def sendQueuedData(self):
"""Send previously queued data to the socket."""
while len(self.send_queue):
data = self.send_queue.pop(0)
r = 0
try:
r = self.conn.send(data)
except ssl.SSLError as e:
if e.errno == ssl.SSL_ERROR_WANT_READ:
raise RetryIOError()
elif e.errno == ssl.SSL_ERROR_WANT_WRITE:
raise RetryIOError()
else:
raise
except socket.error as e:
if e.errno == errno.EAGAIN:
self.log.debug("Write operation on %s would block"
% self)
else:
raise
finally:
data = data[r:]
if data:
self.send_queue.insert(0, data)
try:
while len(self.send_queue):
data = self.send_queue.pop(0)
r = 0
try:
r = self.conn.send(data)
except ssl.SSLError as e:
if e.errno == ssl.SSL_ERROR_WANT_READ:
raise RetryIOError()
elif e.errno == ssl.SSL_ERROR_WANT_WRITE:
raise RetryIOError()
else:
raise
except socket.error as e:
if e.errno == errno.EAGAIN:
self.log.debug("Write operation on %s would block"
% self)
raise RetryIOError()
else:
raise
finally:
data = data[r:]
if data:
self.send_queue.insert(0, data)
except RetryIOError:
pass
class ServerConnection(NonBlockingConnection):