Index: Doc/library/socket.rst =================================================================== --- Doc/library/socket.rst (revision 76913) +++ Doc/library/socket.rst (working copy) @@ -161,6 +161,23 @@ generally useful.) +.. data:: SOCK_CLOEXEC + SOCK_NONBLOCK + + These two constants, if defined, can be combined with the socket types and + allow you to set some flags atomically (thus avoiding possible race + conditions and the need for separate calls). + + .. seealso:: + + `Secure File Descriptor Handling `_ + for a more thorough explanation. + + Availability: Linux >= 2.6.27. + + .. versionadded:: 2.7 + + .. data:: SO_* SOMAXCONN MSG_* Index: Lib/test/test_socket.py =================================================================== --- Lib/test/test_socket.py (revision 76913) +++ Lib/test/test_socket.py (working copy) @@ -15,6 +15,10 @@ import array from weakref import proxy import signal +try: + import fcntl +except ImportError: + fcntl = False HOST = test_support.HOST MSG = 'Michael Gilfix was here\n' @@ -1319,6 +1323,57 @@ self.cli.close() +@unittest.skipUnless(hasattr(socket, "SOCK_CLOEXEC"), + "SOCK_CLOEXEC not defined") +@unittest.skipUnless(fcntl, "module fcntl not available") +class CloexecConstantTest(unittest.TestCase): + def test_SOCK_CLOEXEC(self): + s = socket.socket(socket.AF_INET, + socket.SOCK_STREAM | socket.SOCK_CLOEXEC) + self.assertTrue(s.type & socket.SOCK_CLOEXEC) + self.assertTrue(fcntl.fcntl(s, fcntl.F_GETFD) & fcntl.FD_CLOEXEC) + + +@unittest.skipUnless(hasattr(socket, "SOCK_NONBLOCK"), + "SOCK_NONBLOCK not defined") +class NonblockConstantTest(unittest.TestCase): + def checkNonblock(self, s, nonblock=True, timeout=0.0): + if nonblock: + self.assertTrue(s.type & socket.SOCK_NONBLOCK) + self.assertEqual(s.gettimeout(), timeout) + else: + self.assertFalse(s.type & socket.SOCK_NONBLOCK) + self.assertEqual(s.gettimeout(), None) + + def test_SOCK_NONBLOCK(self): + # a lot of it seems silly and redundant, but I wanted to test that + # changing back and forth worked ok + s = socket.socket(socket.AF_INET, + socket.SOCK_STREAM | socket.SOCK_NONBLOCK) + self.checkNonblock(s) + s.setblocking(1) + self.checkNonblock(s, False) + s.setblocking(0) + self.checkNonblock(s) + s.settimeout(None) + self.checkNonblock(s, False) + s.settimeout(2.0) + self.checkNonblock(s, timeout=2.0) + s.setblocking(1) + self.checkNonblock(s, False) + # defaulttimeout + t = socket.getdefaulttimeout() + socket.setdefaulttimeout(0.0) + self.checkNonblock(socket.socket()) + socket.setdefaulttimeout(None) + self.checkNonblock(socket.socket(), False) + socket.setdefaulttimeout(2.0) + self.checkNonblock(socket.socket(), timeout=2.0) + socket.setdefaulttimeout(None) + self.checkNonblock(socket.socket(), False) + socket.setdefaulttimeout(t) + + def test_main(): tests = [GeneralModuleTests, BasicTCPTest, TCPCloserTest, TCPTimeoutTest, TestExceptions, BufferIOTest, BasicTCPTest2] @@ -1336,6 +1391,8 @@ NetworkConnectionNoServer, NetworkConnectionAttributesTest, NetworkConnectionBehaviourTest, + CloexecConstantTest, + NonblockConstantTest, ]) if hasattr(socket, "socketpair"): tests.append(BasicSocketPairTest) Index: Modules/socketmodule.c =================================================================== --- Modules/socketmodule.c (revision 76913) +++ Modules/socketmodule.c (working copy) @@ -620,6 +620,13 @@ #endif #endif +#ifdef SOCK_NONBLOCK + if (block) + s->sock_type &= (~SOCK_NONBLOCK); + else + s->sock_type |= SOCK_NONBLOCK; +#endif + Py_BEGIN_ALLOW_THREADS #ifdef __BEOS__ block = !block; @@ -729,12 +736,19 @@ s->sock_family = family; s->sock_type = type; s->sock_proto = proto; - s->sock_timeout = defaulttimeout; s->errorhandler = &set_error; - if (defaulttimeout >= 0.0) - internal_setblocking(s, 0); +#ifdef SOCK_NONBLOCK + if (type & SOCK_NONBLOCK) + s->sock_timeout = 0.0; + else +#endif + { + s->sock_timeout = defaulttimeout; + if (defaulttimeout >= 0.0) + internal_setblocking(s, 0); + } #ifdef RISCOS if (taskwindow) @@ -4704,6 +4718,12 @@ PyModule_AddIntConstant(m, "SOCK_RDM", SOCK_RDM); #endif #endif +#ifdef SOCK_CLOEXEC + PyModule_AddIntConstant(m, "SOCK_CLOEXEC", SOCK_CLOEXEC); +#endif +#ifdef SOCK_NONBLOCK + PyModule_AddIntConstant(m, "SOCK_NONBLOCK", SOCK_NONBLOCK); +#endif #ifdef SO_DEBUG PyModule_AddIntConstant(m, "SO_DEBUG", SO_DEBUG);