summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Lib/ssl.py24
-rwxr-xr-xLib/test/regrtest.py1
-rw-r--r--Lib/test/test_multiprocessing.py82
-rw-r--r--Lib/test/test_ssl.py16
-rw-r--r--Misc/ACKS1
-rw-r--r--Misc/NEWS3
-rw-r--r--Modules/_multiprocessing/multiprocessing.c4
-rw-r--r--Modules/socketmodule.c4
8 files changed, 91 insertions, 44 deletions
diff --git a/Lib/ssl.py b/Lib/ssl.py
index 1b7416e2bb..914e749928 100644
--- a/Lib/ssl.py
+++ b/Lib/ssl.py
@@ -355,14 +355,6 @@ class SSLSocket(socket):
else:
return socket.sendto(self, data, flags_or_addr, addr)
- def sendmsg(self, *args, **kwargs):
- self._checkClosed()
- if self._sslobj:
- raise ValueError("sendmsg not allowed on instances of %s" %
- self.__class__)
- else:
- return socket.sendmsg(self, *args, **kwargs)
-
def sendall(self, data, flags=0):
self._checkClosed()
if self._sslobj:
@@ -421,22 +413,6 @@ class SSLSocket(socket):
else:
return socket.recvfrom_into(self, buffer, nbytes, flags)
- def recvmsg(self, *args, **kwargs):
- self._checkClosed()
- if self._sslobj:
- raise ValueError("recvmsg not allowed on instances of %s" %
- self.__class__)
- else:
- return socket.recvmsg(self, *args, **kwargs)
-
- def recvmsg_into(self, *args, **kwargs):
- self._checkClosed()
- if self._sslobj:
- raise ValueError("recvmsg_into not allowed on instances of %s" %
- self.__class__)
- else:
- return socket.recvmsg_into(self, *args, **kwargs)
-
def pending(self):
self._checkClosed()
if self._sslobj:
diff --git a/Lib/test/regrtest.py b/Lib/test/regrtest.py
index 214e430e05..ca63496bf8 100755
--- a/Lib/test/regrtest.py
+++ b/Lib/test/regrtest.py
@@ -577,7 +577,6 @@ def main(tests=None, testdir=None, verbose=0, quiet=False,
elif ok == FAILED:
bad.append(test)
elif ok == ENV_CHANGED:
- bad.append(test)
environment_changed.append(test)
elif ok == SKIPPED:
skipped.append(test)
diff --git a/Lib/test/test_multiprocessing.py b/Lib/test/test_multiprocessing.py
index 405fbd5256..7a7805d59f 100644
--- a/Lib/test/test_multiprocessing.py
+++ b/Lib/test/test_multiprocessing.py
@@ -35,7 +35,7 @@ import multiprocessing.managers
import multiprocessing.heap
import multiprocessing.pool
-from multiprocessing import util
+from multiprocessing import util, reduction
try:
from multiprocessing.sharedctypes import Value, copy
@@ -43,6 +43,11 @@ try:
except ImportError:
HAS_SHAREDCTYPES = False
+try:
+ import msvcrt
+except ImportError:
+ msvcrt = None
+
#
#
#
@@ -89,6 +94,11 @@ else:
timeout = None
return handle in _select([handle], [], [], timeout)[0]
+try:
+ MAXFD = os.sysconf("SC_OPEN_MAX")
+except:
+ MAXFD = 256
+
#
# Some tests require ctypes
#
@@ -1587,6 +1597,76 @@ class _TestConnection(BaseTestCase):
self.assertRaises(ValueError, a.send_bytes, msg, 4, -1)
+ @classmethod
+ def _is_fd_assigned(cls, fd):
+ try:
+ os.fstat(fd)
+ except OSError as e:
+ if e.errno == errno.EBADF:
+ return False
+ raise
+ else:
+ return True
+
+ @classmethod
+ def _writefd(cls, conn, data, create_dummy_fds=False):
+ if create_dummy_fds:
+ for i in range(0, 256):
+ if not cls._is_fd_assigned(i):
+ os.dup2(conn.fileno(), i)
+ fd = reduction.recv_handle(conn)
+ if msvcrt:
+ fd = msvcrt.open_osfhandle(fd, os.O_WRONLY)
+ os.write(fd, data)
+ os.close(fd)
+
+ def test_fd_transfer(self):
+ if self.TYPE != 'processes':
+ self.skipTest("only makes sense with processes")
+ conn, child_conn = self.Pipe(duplex=True)
+
+ p = self.Process(target=self._writefd, args=(child_conn, b"foo"))
+ p.start()
+ with open(test.support.TESTFN, "wb") as f:
+ fd = f.fileno()
+ if msvcrt:
+ fd = msvcrt.get_osfhandle(fd)
+ reduction.send_handle(conn, fd, p.pid)
+ p.join()
+ with open(test.support.TESTFN, "rb") as f:
+ self.assertEqual(f.read(), b"foo")
+
+ @unittest.skipIf(sys.platform == "win32",
+ "test semantics don't make sense on Windows")
+ @unittest.skipIf(MAXFD <= 256,
+ "largest assignable fd number is too small")
+ @unittest.skipUnless(hasattr(os, "dup2"),
+ "test needs os.dup2()")
+ def test_large_fd_transfer(self):
+ # With fd > 256 (issue #11657)
+ if self.TYPE != 'processes':
+ self.skipTest("only makes sense with processes")
+ conn, child_conn = self.Pipe(duplex=True)
+
+ p = self.Process(target=self._writefd, args=(child_conn, b"bar", True))
+ p.start()
+ with open(test.support.TESTFN, "wb") as f:
+ fd = f.fileno()
+ for newfd in range(256, MAXFD):
+ if not self._is_fd_assigned(newfd):
+ break
+ else:
+ self.fail("could not find an unassigned large file descriptor")
+ os.dup2(fd, newfd)
+ try:
+ reduction.send_handle(conn, newfd, p.pid)
+ finally:
+ os.close(newfd)
+ p.join()
+ with open(test.support.TESTFN, "rb") as f:
+ self.assertEqual(f.read(), b"bar")
+
+
class _TestListenerClient(BaseTestCase):
ALLOWED_TYPES = ('processes', 'threads')
diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py
index 1d26c11ed8..f3f0c54459 100644
--- a/Lib/test/test_ssl.py
+++ b/Lib/test/test_ssl.py
@@ -186,11 +186,8 @@ class BasicSocketTests(unittest.TestCase):
self.assertRaises(socket.error, ss.recv_into, bytearray(b'x'))
self.assertRaises(socket.error, ss.recvfrom, 1)
self.assertRaises(socket.error, ss.recvfrom_into, bytearray(b'x'), 1)
- self.assertRaises(socket.error, ss.recvmsg, 1)
- self.assertRaises(socket.error, ss.recvmsg_into, [bytearray(b'x')])
self.assertRaises(socket.error, ss.send, b'x')
self.assertRaises(socket.error, ss.sendto, b'x', ('0.0.0.0', 0))
- self.assertRaises(socket.error, ss.sendmsg, [b'x'])
def test_timeout(self):
# Issue #8524: when creating an SSL socket, the timeout of the
@@ -1523,30 +1520,17 @@ else:
count, addr = s.recvfrom_into(b)
return b[:count]
- def _recvmsg(*args, **kwargs):
- return s.recvmsg(*args, **kwargs)[0]
-
- def _recvmsg_into(bufsize, *args, **kwargs):
- b = bytearray(bufsize)
- return bytes(b[:s.recvmsg_into([b], *args, **kwargs)[0]])
-
- def _sendmsg(msg, *args, **kwargs):
- return s.sendmsg([msg])
-
# (name, method, whether to expect success, *args)
send_methods = [
('send', s.send, True, []),
('sendto', s.sendto, False, ["some.address"]),
- ('sendmsg', _sendmsg, False, []),
('sendall', s.sendall, True, []),
]
recv_methods = [
('recv', s.recv, True, []),
('recvfrom', s.recvfrom, False, ["some.address"]),
- ('recvmsg', _recvmsg, False, [100]),
('recv_into', _recv_into, True, []),
('recvfrom_into', _recvfrom_into, False, []),
- ('recvmsg_into', _recvmsg_into, False, [100]),
]
data_prefix = "PREFIX_"
diff --git a/Misc/ACKS b/Misc/ACKS
index 062a77ae9a..e7346082d7 100644
--- a/Misc/ACKS
+++ b/Misc/ACKS
@@ -748,6 +748,7 @@ Zach Pincus
Michael Piotrowski
Antoine Pitrou
Jean-François Piéronne
+Remi Pointel
Guilherme Polo
Michael Pomraning
Iustin Pop
diff --git a/Misc/NEWS b/Misc/NEWS
index b2d9e84b94..4b5a9a6d77 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -268,6 +268,9 @@ Core and Builtins
Library
-------
+- Issue #11657: Fix sending file descriptors over 255 over a multiprocessing
+ Pipe.
+
- Issue #12811: tabnanny.check() now promptly closes checked files. Patch by
Anthony Briggs.
diff --git a/Modules/_multiprocessing/multiprocessing.c b/Modules/_multiprocessing/multiprocessing.c
index 5d1cf5661a..1987b951f9 100644
--- a/Modules/_multiprocessing/multiprocessing.c
+++ b/Modules/_multiprocessing/multiprocessing.c
@@ -111,7 +111,7 @@ multiprocessing_sendfd(PyObject *self, PyObject *args)
cmsg->cmsg_type = SCM_RIGHTS;
cmsg->cmsg_len = CMSG_LEN(sizeof(int));
msg.msg_controllen = cmsg->cmsg_len;
- *CMSG_DATA(cmsg) = fd;
+ * (int *) CMSG_DATA(cmsg) = fd;
Py_BEGIN_ALLOW_THREADS
res = sendmsg(conn, &msg, 0);
@@ -154,7 +154,7 @@ multiprocessing_recvfd(PyObject *self, PyObject *args)
if (res < 0)
return PyErr_SetFromErrno(PyExc_OSError);
- fd = *CMSG_DATA(cmsg);
+ fd = * (int *) CMSG_DATA(cmsg);
return Py_BuildValue("i", fd);
}
diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c
index 81d1ce1070..5878ebb0d3 100644
--- a/Modules/socketmodule.c
+++ b/Modules/socketmodule.c
@@ -156,6 +156,10 @@ if_indextoname(index) -- return the corresponding interface name\n\
# undef HAVE_GETHOSTBYNAME_R_6_ARG
#endif
+#if defined(__OpenBSD__)
+# include <sys/uio.h>
+#endif
+
#ifndef WITH_THREAD
# undef HAVE_GETHOSTBYNAME_R
#endif