diff options
| author | Victor Stinner <vstinner@redhat.com> | 2015-12-16 17:53:14 +0100 |
|---|---|---|
| committer | Victor Stinner <vstinner@redhat.com> | 2015-12-17 10:32:23 +0100 |
| commit | 58a55efad1578487f2bc8f6d3b46176f752a8489 (patch) | |
| tree | 0827a97c52f18b90145c284e4e6f1edbc5b960b1 | |
| parent | 3ae710e70ecb3683f83b9829011de01b5d3e0bf4 (diff) | |
| download | eventlet-recvintoandstuff.tar.gz | |
gh-274: Handle blocking I/O errors in GreenSocketrecvintoandstuff
Fix recv_into(), recvfrom(), recvfrom_into() and sendto() methods of
GreenSocket to handle blocking I/O errors (ex: BlockingIOError on
Python 3). Even if the trampoline was called, the socket method can
still fails with an I/O errors for various reasons (see manual pages
of the C functions for examples).
Ref: https://github.com/eventlet/eventlet/issues/274
| -rw-r--r-- | eventlet/greenio/base.py | 47 |
1 files changed, 21 insertions, 26 deletions
diff --git a/eventlet/greenio/base.py b/eventlet/greenio/base.py index 18799af..b5a22dc 100644 --- a/eventlet/greenio/base.py +++ b/eventlet/greenio/base.py @@ -304,13 +304,13 @@ class GreenSocket(object): "makefile instead", DeprecationWarning, stacklevel=2) return self.makefile(*args, **kw) - def recv(self, buflen, flags=0): + def _recv_loop(self, recv_meth, *args): fd = self.fd if self.act_non_blocking: - return fd.recv(buflen, flags) + return recv_meth(*args) while True: try: - return fd.recv(buflen, flags) + return recv_meth(*args) except socket.error as e: if get_errno(e) in SOCKET_BLOCKING: pass @@ -328,35 +328,28 @@ class GreenSocket(object): # Perhaps we should return '' instead? raise EOFError() - def recvfrom(self, *args): - if not self.act_non_blocking: - self._trampoline(self.fd, read=True, timeout=self.gettimeout(), - timeout_exc=socket.timeout("timed out")) - return self.fd.recvfrom(*args) + def recv(self, bufsize, flags=0): + return self._recv_loop(self.fd.recv, bufsize, flags) - def recvfrom_into(self, *args): - if not self.act_non_blocking: - self._trampoline(self.fd, read=True, timeout=self.gettimeout(), - timeout_exc=socket.timeout("timed out")) - return self.fd.recvfrom_into(*args) + def recvfrom(self, bufsize, flags=0): + return self._recv_loop(self.fd.recvfrom, bufsize, flags) - def recv_into(self, *args): - if not self.act_non_blocking: - self._trampoline(self.fd, read=True, timeout=self.gettimeout(), - timeout_exc=socket.timeout("timed out")) - return self.fd.recv_into(*args) + def recv_into(self, buffer, nbytes=0, flags=0): + return self._recv_loop(self.fd.recv_into, buffer, nbytes, flags) - def send(self, data, flags=0): - fd = self.fd + def recvfrom_into(self, buffer, nbytes=0, flags=0): + return self._recv_loop(self.fd.recvfrom_into, buffer, nbytes, flags) + + def _send_loop(self, send_method, data, *args): if self.act_non_blocking: - return fd.send(data, flags) + return send_method(data, *args) # blocking socket behavior - sends all, blocks if the buffer is full total_sent = 0 len_data = len(data) while 1: try: - total_sent += fd.send(data[total_sent:], flags) + total_sent += send_method(data[total_sent:], *args) except socket.error as e: eno = get_errno(e) if eno == errno.ENOTCONN or eno not in SOCKET_BLOCKING: @@ -373,16 +366,18 @@ class GreenSocket(object): return total_sent + def send(self, data, flags=0): + return self._send_loop(self.fd.send, data, flags) + + def sendto(self, data, address, flags=0): + return self._send_loop(self.fd.sendto, data, address, flags) + def sendall(self, data, flags=0): tail = self.send(data, flags) len_data = len(data) while tail < len_data: tail += self.send(data[tail:], flags) - def sendto(self, *args): - self._trampoline(self.fd, write=True) - return self.fd.sendto(*args) - def setblocking(self, flag): if flag: self.act_non_blocking = False |
