From a33d48d30594d24f792e62e2dccb5a9ee956b9d9 Mon Sep 17 00:00:00 2001 From: Ben Darnell Date: Sun, 7 Jul 2013 13:30:00 -0400 Subject: [PATCH] Unify lists of errnos used in IOStream. We generally want to treat aborted connections the same regardless of the specific errno, but some calls caught ECONNRESET and ECONNABORTED while others only caught ECONNRESET. Reported in #828. --- tornado/iostream.py | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/tornado/iostream.py b/tornado/iostream.py index 079012c9e..550e68da9 100644 --- a/tornado/iostream.py +++ b/tornado/iostream.py @@ -46,6 +46,14 @@ try: except ImportError: _set_nonblocking = None +# These errnos indicate that a non-blocking operation must be retried +# at a later time. On most platforms they're the same value, but on +# some they differ. +_ERRNO_WOULDBLOCK = (errno.EWOULDBLOCK, errno.EAGAIN) + +# These errnos indicate that a connection has been abruptly terminated. +# They should be caught and handled less noisily than other errors. +_ERRNO_CONNRESET = (errno.ECONNRESET, errno.ECONNABORTED, errno.EPIPE) class StreamClosedError(IOError): """Exception raised by `IOStream` methods when the stream is closed. @@ -447,7 +455,7 @@ class BaseIOStream(object): chunk = self.read_from_fd() except (socket.error, IOError, OSError) as e: # ssl.SSLError is a subclass of socket.error - if e.args[0] == errno.ECONNRESET: + if e.args[0] in _ERRNO_CONNRESET: # Treat ECONNRESET as a connection close rather than # an error to minimize log spam (the exception will # be available on self.error for apps that care). @@ -551,11 +559,11 @@ class BaseIOStream(object): _merge_prefix(self._write_buffer, num_bytes) self._write_buffer.popleft() except socket.error as e: - if e.args[0] in (errno.EWOULDBLOCK, errno.EAGAIN): + if e.args[0] in _ERRNO_WOULDBLOCK: self._write_buffer_frozen = True break else: - if e.args[0] not in (errno.EPIPE, errno.ECONNRESET): + if e.args[0] not in _ERRNO_CONNRESET: # Broken pipe errors are usually caused by connection # reset, and its better to not log EPIPE errors to # minimize log spam @@ -682,7 +690,7 @@ class IOStream(BaseIOStream): try: chunk = self.socket.recv(self.read_chunk_size) except socket.error as e: - if e.args[0] in (errno.EWOULDBLOCK, errno.EAGAIN): + if e.args[0] in _ERRNO_WOULDBLOCK: return None else: raise @@ -725,7 +733,8 @@ class IOStream(BaseIOStream): # returned immediately when attempting to connect to # localhost, so handle them the same way as an error # reported later in _handle_connect. - if e.args[0] not in (errno.EINPROGRESS, errno.EWOULDBLOCK): + if (e.args[0] != errno.EINPROGRESS and + e.args[0] not in _ERRNO_WOULDBLOCK): gen_log.warning("Connect error on fd %d: %s", self.socket.fileno(), e) self.close(exc_info=True) @@ -821,7 +830,7 @@ class SSLIOStream(IOStream): return self.close(exc_info=True) raise except socket.error as err: - if err.args[0] in (errno.ECONNABORTED, errno.ECONNRESET): + if err.args[0] in _ERRNO_CONNRESET: return self.close(exc_info=True) except AttributeError: # On Linux, if the connection was reset before the call to @@ -917,7 +926,7 @@ class SSLIOStream(IOStream): else: raise except socket.error as e: - if e.args[0] in (errno.EWOULDBLOCK, errno.EAGAIN): + if e.args[0] in _ERRNO_WOULDBLOCK: return None else: raise @@ -953,7 +962,7 @@ class PipeIOStream(BaseIOStream): try: chunk = os.read(self.fd, self.read_chunk_size) except (IOError, OSError) as e: - if e.args[0] in (errno.EWOULDBLOCK, errno.EAGAIN): + if e.args[0] in _ERRNO_WOULDBLOCK: return None elif e.args[0] == errno.EBADF: # If the writing half of a pipe is closed, select will -- 2.47.2