]> git.ipfire.org Git - thirdparty/tornado.git/commitdiff
tcpclient,netutil: Set FD_CLOEXEC on all sockets created by Tornado 2064/head
authorBen Darnell <ben@bendarnell.com>
Mon, 29 May 2017 00:10:01 +0000 (20:10 -0400)
committerBen Darnell <ben@bendarnell.com>
Mon, 29 May 2017 13:47:50 +0000 (09:47 -0400)
PR #1984 was based on the mistaken belief that we were already
doing this (and in python 3.4+, it's true, thanks to PEP 446). This
fixes a regression introduced in Tornado 4.5 in which autoreload would
leak file descriptors and leave client connections hanging.

Fixes #2057

tornado/netutil.py
tornado/platform/common.py
tornado/tcpclient.py

index 97f84f13b3ffc65f614383c41d8fece7dd50d109..31bbe8036454a18d4ba39d127c4c2f93e43102d3 100644 (file)
@@ -270,6 +270,7 @@ def add_accept_handler(sock, callback):
                 if errno_from_exception(e) == errno.ECONNABORTED:
                     continue
                 raise
+            set_close_exec(connection.fileno())
             callback(connection, address)
     IOLoop.current().add_handler(sock, accept_handler, IOLoop.READ)
 
index a73f8db7fbac40834662126b874aa1fa79093d2e..b597748d1f6d8e7f04d74689e737c3328194fba7 100644 (file)
@@ -32,10 +32,12 @@ class Waker(interface.Waker):
     and Jython.
     """
     def __init__(self):
+        from .auto import set_close_exec
         # Based on Zope select_trigger.py:
         # https://github.com/zopefoundation/Zope/blob/master/src/ZServer/medusa/thread/select_trigger.py
 
         self.writer = socket.socket()
+        set_close_exec(self.writer.fileno())
         # Disable buffering -- pulling the trigger sends 1 byte,
         # and we want that sent immediately, to wake up ASAP.
         self.writer.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
@@ -54,6 +56,7 @@ class Waker(interface.Waker):
             # http://mail.zope.org/pipermail/zope/2005-July/160433.html
             # for hideous details.
             a = socket.socket()
+            set_close_exec(a.fileno())
             a.bind(("127.0.0.1", 0))
             a.listen(1)
             connect_address = a.getsockname()  # assigned (host, port) pair
@@ -78,6 +81,7 @@ class Waker(interface.Waker):
                 a.close()
 
         self.reader, addr = a.accept()
+        set_close_exec(self.reader.fileno())
         self.reader.setblocking(0)
         self.writer.setblocking(0)
         a.close()
index ec51a6134edcb4ca41d74e0ced31a561a2b1381a..f8e0d019cadeaf752df1bd3b502301f505f654ad 100644 (file)
@@ -26,6 +26,7 @@ from tornado.ioloop import IOLoop
 from tornado.iostream import IOStream
 from tornado import gen
 from tornado.netutil import Resolver
+from tornado.platform.auto import set_close_exec
 
 _INITIAL_CONNECT_TIMEOUT = 0.3
 
@@ -201,6 +202,7 @@ class TCPClient(object):
             # - 127.0.0.1 for IPv4
             # - ::1 for IPv6
         socket_obj = socket.socket(af)
+        set_close_exec(socket_obj.fileno())
         if source_port_bind or source_ip_bind:
             # If the user requires binding also to a specific IP/port.
             try: