]> git.ipfire.org Git - thirdparty/tornado.git/commitdiff
define and use errno_from_exception abstraction 996/head
authorDoug Goldstein <cardoe@cardoe.com>
Fri, 28 Feb 2014 14:48:26 +0000 (08:48 -0600)
committerDoug Goldstein <cardoe@cardoe.com>
Sat, 1 Mar 2014 20:22:20 +0000 (14:22 -0600)
If an OSError or IOError are instantiated without an errno value, e.g.
e = OSError(). The existing code would give an IndexError: tuple index
out of range. However there have been cases that the errno attribute
wasn't populated so instead of switching to it this introduces a helper
function to ensure we get the errno value through whatever means
possible.

tornado/ioloop.py
tornado/iostream.py
tornado/netutil.py
tornado/process.py
tornado/tcpserver.py
tornado/util.py

index 77fb46591a521fc864bf740436ba9e9e1a37305e..80496e1933fe19d5c38f1afbe5c0ac6e5ced7c73 100644 (file)
@@ -45,6 +45,7 @@ from tornado.concurrent import TracebackFuture, is_future
 from tornado.log import app_log, gen_log
 from tornado import stack_context
 from tornado.util import Configurable
+from tornado.util import errno_from_exception
 
 try:
     import signal
@@ -724,9 +725,7 @@ class PollIOLoop(IOLoop):
                     # two ways EINTR might be signaled:
                     # * e.errno == errno.EINTR
                     # * e.args is like (errno.EINTR, 'Interrupted system call')
-                    if (getattr(e, 'errno', None) == errno.EINTR or
-                        (isinstance(getattr(e, 'args', None), tuple) and
-                         len(e.args) == 2 and e.args[0] == errno.EINTR)):
+                    if errno_from_exception(e) == errno.EINTR:
                         continue
                     else:
                         raise
@@ -746,7 +745,7 @@ class PollIOLoop(IOLoop):
                         fd_obj, handler_func = self._handlers[fd]
                         handler_func(fd_obj, events)
                     except (OSError, IOError) as e:
-                        if e.args[0] == errno.EPIPE:
+                        if errno_from_exception(e) == errno.EPIPE:
                             # Happens when the client closes the connection
                             pass
                         else:
index faf657a4c6e44a830b621f7897bff17b8d480212..40e75a5344dfcd118e6b85e42057ada72c54d98b 100644 (file)
@@ -40,7 +40,7 @@ from tornado import ioloop
 from tornado.log import gen_log, app_log
 from tornado.netutil import ssl_wrap_socket, ssl_match_hostname, SSLCertificateError
 from tornado import stack_context
-from tornado.util import bytes_type
+from tornado.util import bytes_type, errno_from_exception
 
 try:
     from tornado.platform.posix import _set_nonblocking
@@ -766,8 +766,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] != errno.EINPROGRESS and
-                    e.args[0] not in _ERRNO_WOULDBLOCK):
+            if (errno_from_exception(e) != errno.EINPROGRESS and
+                    errno_from_exception(e) not in _ERRNO_WOULDBLOCK):
                 gen_log.warning("Connect error on fd %s: %s",
                                 self.socket.fileno(), e)
                 self.close(exc_info=True)
@@ -1026,9 +1026,9 @@ class PipeIOStream(BaseIOStream):
         try:
             chunk = os.read(self.fd, self.read_chunk_size)
         except (IOError, OSError) as e:
-            if e.args[0] in _ERRNO_WOULDBLOCK:
+            if errno_from_exception(e) in _ERRNO_WOULDBLOCK:
                 return None
-            elif e.args[0] == errno.EBADF:
+            elif errno_from_exception(e) == errno.EBADF:
                 # If the writing half of a pipe is closed, select will
                 # report it as readable but reads will fail with EBADF.
                 self.close(exc_info=True)
index a4699138eeb6345d1e2a68bfc8a2235ba339b984..171873e66e4f27f40767a0c4bbcd3a692b62b378 100644 (file)
@@ -27,7 +27,7 @@ import stat
 from tornado.concurrent import dummy_executor, run_on_executor
 from tornado.ioloop import IOLoop
 from tornado.platform.auto import set_close_exec
-from tornado.util import u, Configurable
+from tornado.util import u, Configurable, errno_from_exception
 
 if hasattr(ssl, 'match_hostname') and hasattr(ssl, 'CertificateError'):  # python 3.2+
     ssl_match_hostname = ssl.match_hostname
@@ -84,7 +84,7 @@ def bind_sockets(port, address=None, family=socket.AF_UNSPEC, backlog=128, flags
         try:
             sock = socket.socket(af, socktype, proto)
         except socket.error as e:
-            if e.args[0] == errno.EAFNOSUPPORT:
+            if errno_from_exception(e) == errno.EAFNOSUPPORT:
                 continue
             raise
         set_close_exec(sock.fileno())
@@ -133,7 +133,7 @@ if hasattr(socket, 'AF_UNIX'):
         try:
             st = os.stat(file)
         except OSError as err:
-            if err.errno != errno.ENOENT:
+            if errno_from_exception(err) != errno.ENOENT:
                 raise
         else:
             if stat.S_ISSOCK(st.st_mode):
@@ -165,12 +165,12 @@ def add_accept_handler(sock, callback, io_loop=None):
             except socket.error as e:
                 # EWOULDBLOCK and EAGAIN indicate we have accepted every
                 # connection that is available.
-                if e.args[0] in (errno.EWOULDBLOCK, errno.EAGAIN):
+                if errno_from_exception(e) in (errno.EWOULDBLOCK, errno.EAGAIN):
                     return
                 # ECONNABORTED indicates that there was a connection
                 # but it was closed while still in the accept queue.
                 # (observed on FreeBSD).
-                if e.args[0] == errno.ECONNABORTED:
+                if errno_from_exception(e) == errno.ECONNABORTED:
                     continue
                 raise
             callback(connection, address)
index 942c5c3f62de8ed0fcbee70164184f0071069a31..74575d05aea07a654d972bd4cd5aee08ec81b3c0 100644 (file)
@@ -35,6 +35,7 @@ from tornado.iostream import PipeIOStream
 from tornado.log import gen_log
 from tornado.platform.auto import set_close_exec
 from tornado import stack_context
+from tornado.util import errno_from_exception
 
 try:
     long  # py2
@@ -136,7 +137,7 @@ def fork_processes(num_processes, max_restarts=100):
         try:
             pid, status = os.wait()
         except OSError as e:
-            if e.errno == errno.EINTR:
+            if errno_from_exception(e) == errno.EINTR:
                 continue
             raise
         if pid not in children:
@@ -283,7 +284,7 @@ class Subprocess(object):
         try:
             ret_pid, status = os.waitpid(pid, os.WNOHANG)
         except OSError as e:
-            if e.args[0] == errno.ECHILD:
+            if errno_from_exception(e) == errno.ECHILD:
                 return
         if ret_pid == 0:
             return
index c07737329c785e7876d0e0ead7a81425a365b79b..81d983ff535ef72406c2b98540a63d4c46159f78 100644 (file)
@@ -27,6 +27,7 @@ from tornado.ioloop import IOLoop
 from tornado.iostream import IOStream, SSLIOStream
 from tornado.netutil import bind_sockets, add_accept_handler, ssl_wrap_socket
 from tornado import process
+from tornado.util import errno_from_exception
 
 
 class TCPServer(object):
@@ -231,7 +232,7 @@ class TCPServer(object):
                 # SSLIOStream._do_ssl_handshake).
                 # To test this behavior, try nmap with the -sT flag.
                 # https://github.com/facebook/tornado/pull/750
-                if err.args[0] in (errno.ECONNABORTED, errno.EINVAL):
+                if errno_from_exception(err) in (errno.ECONNABORTED, errno.EINVAL):
                     return connection.close()
                 else:
                     raise
index cc53222296e782d63981e5dc93f05b52bee23749..9c34175954428260a2a835195e3c6700f93e7e59 100644 (file)
@@ -132,6 +132,24 @@ def exec_in(code, glob, loc=None):
 """)
 
 
+def errno_from_exception(e):
+    """Provides the errno from an Exception object.
+
+    There are cases that the errno attribute was not set so we pull
+    the errno out of the args but if someone instatiates an Exception
+    without any args you will get a tuple error. So this function
+    abstracts all that behavior to give you a safe way to get the
+    errno.
+    """
+
+    if hasattr(e, 'errno'):
+        return e.errno
+    elif e.args:
+        return e.args[0]
+    else:
+        return None
+
+
 class Configurable(object):
     """Base class for configurable interfaces.