[Python-checkins] r85480 - in python/branches/py3k: Doc/library/socket.rst Lib/test/test_asyncore.py Lib/test/test_socket.py Misc/ACKS Misc/NEWS Modules/socketmodule.c configure configure.in pyconfig.h.in

antoine.pitrou python-checkins at python.org
Thu Oct 14 17:05:38 CEST 2010


Author: antoine.pitrou
Date: Thu Oct 14 17:05:38 2010
New Revision: 85480

Log:
Issue #7523: Add SOCK_CLOEXEC and SOCK_NONBLOCK to the socket module,
where supported by the system.  Patch by Nikita Vetoshkin.



Modified:
   python/branches/py3k/Doc/library/socket.rst
   python/branches/py3k/Lib/test/test_asyncore.py
   python/branches/py3k/Lib/test/test_socket.py
   python/branches/py3k/Misc/ACKS
   python/branches/py3k/Misc/NEWS
   python/branches/py3k/Modules/socketmodule.c
   python/branches/py3k/configure
   python/branches/py3k/configure.in
   python/branches/py3k/pyconfig.h.in

Modified: python/branches/py3k/Doc/library/socket.rst
==============================================================================
--- python/branches/py3k/Doc/library/socket.rst	(original)
+++ python/branches/py3k/Doc/library/socket.rst	Thu Oct 14 17:05:38 2010
@@ -157,6 +157,21 @@
    :func:`socket`. (Only :const:`SOCK_STREAM` and :const:`SOCK_DGRAM` appear to be
    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 <http://udrepper.livejournal.com/20407.html>`_
+      for a more thorough explanation.
+
+   Availability: Linux >= 2.6.27.
+
+   .. versionadded:: 3.2
 
 .. data:: SO_*
           SOMAXCONN

Modified: python/branches/py3k/Lib/test/test_asyncore.py
==============================================================================
--- python/branches/py3k/Lib/test/test_asyncore.py	(original)
+++ python/branches/py3k/Lib/test/test_asyncore.py	Thu Oct 14 17:05:38 2010
@@ -692,7 +692,8 @@
         s = asyncore.dispatcher()
         s.create_socket(socket.AF_INET, socket.SOCK_STREAM)
         self.assertEqual(s.socket.family, socket.AF_INET)
-        self.assertEqual(s.socket.type, socket.SOCK_STREAM)
+        SOCK_NONBLOCK = getattr(socket, 'SOCK_NONBLOCK', 0)
+        self.assertEqual(s.socket.type, socket.SOCK_STREAM | SOCK_NONBLOCK)
 
     def test_bind(self):
         s1 = asyncore.dispatcher()

Modified: python/branches/py3k/Lib/test/test_socket.py
==============================================================================
--- python/branches/py3k/Lib/test/test_socket.py	(original)
+++ python/branches/py3k/Lib/test/test_socket.py	Thu Oct 14 17:05:38 2010
@@ -17,6 +17,10 @@
 from weakref import proxy
 import signal
 import math
+try:
+    import fcntl
+except ImportError:
+    fcntl = False
 
 def try_address(host, port=0, family=socket.AF_INET):
     """Try to bind a socket on the given host:port and return True
@@ -902,6 +906,26 @@
     def _testSetBlocking(self):
         pass
 
+    if hasattr(socket, "SOCK_NONBLOCK"):
+        def testInitNonBlocking(self):
+            # reinit server socket
+            self.serv.close()
+            self.serv = socket.socket(socket.AF_INET, socket.SOCK_STREAM |
+                                                  socket.SOCK_NONBLOCK)
+            self.port = support.bind_port(self.serv)
+            self.serv.listen(1)
+            # actual testing
+            start = time.time()
+            try:
+                self.serv.accept()
+            except socket.error:
+                pass
+            end = time.time()
+            self.assertTrue((end - start) < 1.0, "Error creating with non-blocking mode.")
+
+        def _testInitNonBlocking(self):
+            pass
+
     def testAccept(self):
         # Testing non-blocking accept
         self.serv.setblocking(0)
@@ -1801,6 +1825,56 @@
         self.assertTrue(sock._closed)
         self.assertRaises(socket.error, sock.sendall, b'foo')
 
+ at unittest.skipUnless(hasattr(socket, "SOCK_CLOEXEC"),
+                     "SOCK_CLOEXEC not defined")
+ at 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)
+
+
+ at 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,
@@ -1820,6 +1894,8 @@
         NetworkConnectionAttributesTest,
         NetworkConnectionBehaviourTest,
         ContextManagersTest,
+        CloexecConstantTest,
+        NonblockConstantTest
     ])
     if hasattr(socket, "socketpair"):
         tests.append(BasicSocketPairTest)

Modified: python/branches/py3k/Misc/ACKS
==============================================================================
--- python/branches/py3k/Misc/ACKS	(original)
+++ python/branches/py3k/Misc/ACKS	Thu Oct 14 17:05:38 2010
@@ -846,6 +846,7 @@
 Frank Vercruesse
 Mike Verdone
 Jaap Vermeulen
+Nikita Vetoshkin
 Al Vezza
 Jacques A. Vidrine
 John Viega

Modified: python/branches/py3k/Misc/NEWS
==============================================================================
--- python/branches/py3k/Misc/NEWS	(original)
+++ python/branches/py3k/Misc/NEWS	Thu Oct 14 17:05:38 2010
@@ -21,12 +21,14 @@
 Library
 -------
 
-- Issue #Issue10063: file:// scheme will stop accessing remote hosts via ftp
+- Issue #7523: Add SOCK_CLOEXEC and SOCK_NONBLOCK to the socket module,
+  where supported by the system.  Patch by Nikita Vetoshkin.
+
+- Issue #10063: file:// scheme will stop accessing remote hosts via ftp
   protocol. file:// urls had fallback to access remote hosts via ftp. This was
   not correct, change is made to raise a URLError when a remote host is tried
   to access via file:// scheme.
 
-
 - Issue #1710703: Write structures for an empty ZIP archive when a ZipFile is
   created in modes 'a' or 'w' and then closed without adding any files. Raise
   BadZipfile (rather than IOError) when opening small non-ZIP files.

Modified: python/branches/py3k/Modules/socketmodule.c
==============================================================================
--- python/branches/py3k/Modules/socketmodule.c	(original)
+++ python/branches/py3k/Modules/socketmodule.c	Thu Oct 14 17:05:38 2010
@@ -615,6 +615,12 @@
 #ifndef MS_WINDOWS
     int delay_flag;
 #endif
+#ifdef SOCK_NONBLOCK
+    if (block)
+        s->sock_type &= (~SOCK_NONBLOCK);
+    else
+        s->sock_type |= SOCK_NONBLOCK;
+#endif
 
     Py_BEGIN_ALLOW_THREADS
 #ifndef MS_WINDOWS
@@ -764,12 +770,18 @@
     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);
+    }
 
 }
 
@@ -1645,7 +1657,9 @@
     PyObject *addr = NULL;
     PyObject *res = NULL;
     int timeout;
-
+#ifdef HAVE_ACCEPT4
+    int flags = 0;
+#endif
     if (!getsockaddrlen(s, &addrlen))
         return NULL;
     memset(&addrbuf, 0, addrlen);
@@ -1656,8 +1670,15 @@
     BEGIN_SELECT_LOOP(s)
     Py_BEGIN_ALLOW_THREADS
     timeout = internal_select_ex(s, 0, interval);
-    if (!timeout)
+    if (!timeout) {
+#ifdef HAVE_ACCEPT4
+        /* inherit socket flags and use accept4 call */
+        flags = s->sock_type & (SOCK_CLOEXEC | SOCK_NONBLOCK);
+        newfd = accept4(s->sock_fd, SAS2SA(&addrbuf), &addrlen, flags);
+#else
         newfd = accept(s->sock_fd, SAS2SA(&addrbuf), &addrlen);
+#endif /* HAVE_ACCEPT4  */
+    }
     Py_END_ALLOW_THREADS
 
     if (timeout == 1) {
@@ -4599,6 +4620,12 @@
 #if defined(SOCK_RDM)
     PyModule_AddIntConstant(m, "SOCK_RDM", SOCK_RDM);
 #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);

Modified: python/branches/py3k/configure
==============================================================================
--- python/branches/py3k/configure	(original)
+++ python/branches/py3k/configure	Thu Oct 14 17:05:38 2010
@@ -1,5 +1,5 @@
 #! /bin/sh
-# From configure.in Revision: 85349 .
+# From configure.in Revision: 85422 .
 # Guess values for system-dependent variables and create Makefiles.
 # Generated by GNU Autoconf 2.65 for python 3.2.
 #
@@ -9302,7 +9302,7 @@
 $as_echo "MACHDEP_OBJS" >&6; }
 
 # checks for library functions
-for ac_func in alarm setitimer getitimer bind_textdomain_codeset chown \
+for ac_func in alarm accept4 setitimer getitimer bind_textdomain_codeset chown \
  clock confstr ctermid execv fchmod fchown fork fpathconf ftime ftruncate \
  gai_strerror getgroups getlogin getloadavg getpeername getpgid getpid \
  getpriority getresuid getresgid getpwent getspnam getspent getsid getwd \

Modified: python/branches/py3k/configure.in
==============================================================================
--- python/branches/py3k/configure.in	(original)
+++ python/branches/py3k/configure.in	Thu Oct 14 17:05:38 2010
@@ -2550,7 +2550,7 @@
 AC_MSG_RESULT(MACHDEP_OBJS)
 
 # checks for library functions
-AC_CHECK_FUNCS(alarm setitimer getitimer bind_textdomain_codeset chown \
+AC_CHECK_FUNCS(alarm accept4 setitimer getitimer bind_textdomain_codeset chown \
  clock confstr ctermid execv fchmod fchown fork fpathconf ftime ftruncate \
  gai_strerror getgroups getlogin getloadavg getpeername getpgid getpid \
  getpriority getresuid getresgid getpwent getspnam getspent getsid getwd \

Modified: python/branches/py3k/pyconfig.h.in
==============================================================================
--- python/branches/py3k/pyconfig.h.in	(original)
+++ python/branches/py3k/pyconfig.h.in	Thu Oct 14 17:05:38 2010
@@ -40,6 +40,9 @@
    the case on Motorola V4 (R40V4.2) */
 #undef GETTIMEOFDAY_NO_TZ
 
+/* Define to 1 if you have the `accept4' function. */
+#undef HAVE_ACCEPT4
+
 /* Define to 1 if you have the `acosh' function. */
 #undef HAVE_ACOSH
 


More information about the Python-checkins mailing list