Index: Doc/library/socket.rst =================================================================== --- Doc/library/socket.rst (revision 76854) +++ 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 76854) +++ Lib/test/test_socket.py (working copy) @@ -15,6 +15,7 @@ import array from weakref import proxy import signal +import fcntl HOST = test_support.HOST MSG = 'Michael Gilfix was here\n' @@ -1319,6 +1320,58 @@ self.cli.close() +class CloexecLinuxConstantTest(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) + + +class NonblockLinuxConstantTest(unittest.TestCase): + 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.assertTrue(s.type & socket.SOCK_NONBLOCK) + self.assertEqual(s.gettimeout(), 0.0) + s.setblocking(1) + self.assertFalse(s.type & socket.SOCK_NONBLOCK) + self.assertEqual(s.gettimeout(), None) + s.setblocking(0) + self.assertTrue(s.type & socket.SOCK_NONBLOCK) + self.assertEqual(s.gettimeout(), 0.0) + s.settimeout(None) + self.assertFalse(s.type & socket.SOCK_NONBLOCK) + self.assertEqual(s.gettimeout(), None) + s.settimeout(2.0) + self.assertTrue(s.type & socket.SOCK_NONBLOCK) + self.assertEqual(s.gettimeout(), 2.0) + s.setblocking(1) + self.assertFalse(s.type & socket.SOCK_NONBLOCK) + self.assertEqual(s.gettimeout(), None) + # defaulttimeout + t = socket.getdefaulttimeout() + socket.setdefaulttimeout(0.0) + s = socket.socket() + self.assertTrue(s.type & socket.SOCK_NONBLOCK) + self.assertEqual(s.gettimeout(), 0.0) + socket.setdefaulttimeout(None) + s = socket.socket() + self.assertFalse(s.type & socket.SOCK_NONBLOCK) + self.assertEqual(s.gettimeout(), None) + socket.setdefaulttimeout(2.0) + s = socket.socket() + self.assertTrue(s.type & socket.SOCK_NONBLOCK) + self.assertEqual(s.gettimeout(), 2.0) + socket.setdefaulttimeout(None) + s = socket.socket() + self.assertFalse(s.type & socket.SOCK_NONBLOCK) + self.assertEqual(s.gettimeout(), None) + socket.setdefaulttimeout(t) + + def test_main(): tests = [GeneralModuleTests, BasicTCPTest, TCPCloserTest, TCPTimeoutTest, TestExceptions, BufferIOTest, BasicTCPTest2] @@ -1341,6 +1394,10 @@ tests.append(BasicSocketPairTest) if sys.platform == 'linux2': tests.append(TestLinuxAbstractNamespace) + if hasattr(socket, "SOCK_CLOEXEC"): + tests.append(CloexecLinuxConstantTest) + if hasattr(socket, "SOCK_NONBLOCK"): + tests.append(NonblockLinuxConstantTest) if isTipcAvailable(): tests.append(TIPCTest) tests.append(TIPCThreadableTest) Index: Modules/socketmodule.c =================================================================== --- Modules/socketmodule.c (revision 76854) +++ 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,20 @@ 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 +4719,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);