diff -r 0afa7b323abb Doc/library/socketserver.rst --- a/Doc/library/socketserver.rst Tue Jan 08 00:52:40 2013 +0100 +++ b/Doc/library/socketserver.rst Wed Jan 09 00:59:44 2013 +0100 @@ -212,6 +212,20 @@ The server classes support the following :const:`False`, and can be set in subclasses to change the policy. +.. attribute:: BaseServer.close_on_exec + + If its value is :const:`True`, the close-on-exec flag will be set on the + listening socket. The default value is :const:`True` if the :mod:`fcntl` + module is available, :const:`False` otherwise. + + :exc:`NotImplementedError` is raised by the constructor of the server if the + platform does not support close-on-exec flag. + + Setting the flag is only atomic if the operating supports + :data:`socket.SOCK_CLOEXEC`. + + .. versionadded:: 3.4 + .. attribute:: BaseServer.request_queue_size The size of the request queue. If it takes a long time to process a single diff -r 0afa7b323abb Lib/socketserver.py --- a/Lib/socketserver.py Tue Jan 08 00:52:40 2013 +0100 +++ b/Lib/socketserver.py Wed Jan 09 00:59:44 2013 +0100 @@ -138,6 +138,10 @@ try: import threading except ImportError: import dummy_threading as threading +try: + import fcntl +except ImportError: + fcntl = None __all__ = ["TCPServer","UDPServer","ForkingUDPServer","ForkingTCPServer", "ThreadingUDPServer","ThreadingTCPServer","BaseRequestHandler", @@ -194,6 +198,7 @@ class BaseServer: - address_family - socket_type - allow_reuse_address + - close_on_exec Instance variables: @@ -365,6 +370,23 @@ class BaseServer: traceback.print_exc() # XXX But this goes to stderr! print('-'*40) +def _set_cloexec(fd): + """ + Set FD_CLOEXEC (close-on-exec) flag on the specified file descriptor + """ + if fcntl is None: + raise NotImplementedError("close-on-exec flag is not supported on your platform") + if _set_cloexec.cloexec_works: + return + flags = fcntl.fcntl(fd, fcntl.F_GETFD) + if _set_cloexec.cloexec_works is None: + _set_cloexec.cloexec_works = bool(flags & fcntl.FD_CLOEXEC) + if _set_cloexec.cloexec_works: + # SOCK_CLOEXEC works + return + # SOCK_CLOEXEC doesn't work on Linux older than 2.6.27 + fcntl.fcntl(fd, fcntl.F_SETFD, flags | fcntl.FD_CLOEXEC) +_set_cloexec.cloexec_works = None if hasattr(socket, 'SOCK_CLOEXEC') else False class TCPServer(BaseServer): @@ -404,6 +426,7 @@ class TCPServer(BaseServer): - socket_type - request_queue_size (only for stream sockets) - allow_reuse_address + - close_on_exec Instance variables: @@ -421,11 +444,19 @@ class TCPServer(BaseServer): allow_reuse_address = False + close_on_exec = (fcntl is not None) + def __init__(self, server_address, RequestHandlerClass, bind_and_activate=True): """Constructor. May be extended, do not override.""" BaseServer.__init__(self, server_address, RequestHandlerClass) + socket_type = self.socket_type + if self.close_on_exec and hasattr(socket, 'SOCK_CLOEXEC'): + socket_type |= socket.SOCK_CLOEXEC self.socket = socket.socket(self.address_family, - self.socket_type) + socket_type) + if self.close_on_exec: + _set_cloexec(self.socket.fileno()) + if bind_and_activate: self.server_bind() self.server_activate() diff -r 0afa7b323abb Lib/test/test_socketserver.py --- a/Lib/test/test_socketserver.py Tue Jan 08 00:52:40 2013 +0100 +++ b/Lib/test/test_socketserver.py Wed Jan 09 00:59:44 2013 +0100 @@ -111,6 +111,10 @@ class SocketServerTest(unittest.TestCase if verbose: print("creating server") server = MyServer(addr, MyHandler) + if MyServer.close_on_exec: + import fcntl + flags = fcntl.fcntl(server.socket.fileno(), fcntl.F_GETFD) + self.assertTrue(flags & fcntl.FD_CLOEXEC) self.assertEqual(server.server_address, server.socket.getsockname()) return server diff -r 0afa7b323abb Lib/xmlrpc/server.py --- a/Lib/xmlrpc/server.py Tue Jan 08 00:52:40 2013 +0100 +++ b/Lib/xmlrpc/server.py Wed Jan 09 00:59:44 2013 +0100 @@ -114,10 +114,6 @@ import re import pydoc import inspect import traceback -try: - import fcntl -except ImportError: - fcntl = None def resolve_dotted_attribute(obj, attr, allow_dotted_names=True): """resolve_dotted_attribute(a, 'b.c.d') => a.b.c.d @@ -584,13 +580,6 @@ class SimpleXMLRPCServer(socketserver.TC SimpleXMLRPCDispatcher.__init__(self, allow_none, encoding, use_builtin_types) socketserver.TCPServer.__init__(self, addr, requestHandler, bind_and_activate) - # [Bug #1222790] If possible, set close-on-exec flag; if a - # method spawns a subprocess, the subprocess shouldn't have - # the listening socket open. - if fcntl is not None and hasattr(fcntl, 'FD_CLOEXEC'): - flags = fcntl.fcntl(self.fileno(), fcntl.F_GETFD) - flags |= fcntl.FD_CLOEXEC - fcntl.fcntl(self.fileno(), fcntl.F_SETFD, flags) class MultiPathXMLRPCServer(SimpleXMLRPCServer): """Multipath XML-RPC Server