From ed4a8fc0952a4211bc8bc929c23e11bebdfe9aa3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Charles-Fran=C3=A7ois=20Natali?= Date: Wed, 8 Feb 2012 21:15:58 +0100 Subject: [PATCH] Issue #8184: multiprocessing: On Windows, don't set SO_REUSEADDR on Connection sockets, and set FILE_FLAG_FIRST_PIPE_INSTANCE on named pipes, to make sure two listeners can't bind to the same socket/pipe (or any existing socket/pipe). --- Lib/multiprocessing/connection.py | 11 ++++++++--- Lib/test/test_multiprocessing.py | 12 ++++++++++++ Misc/NEWS | 5 +++++ Modules/_multiprocessing/win32_functions.c | 1 + 4 files changed, 26 insertions(+), 3 deletions(-) diff --git a/Lib/multiprocessing/connection.py b/Lib/multiprocessing/connection.py index 615f55dd229..8807618ed36 100644 --- a/Lib/multiprocessing/connection.py +++ b/Lib/multiprocessing/connection.py @@ -544,7 +544,8 @@ else: obsize, ibsize = 0, BUFSIZE h1 = win32.CreateNamedPipe( - address, openmode | win32.FILE_FLAG_OVERLAPPED, + address, openmode | win32.FILE_FLAG_OVERLAPPED | + win32.FILE_FLAG_FIRST_PIPE_INSTANCE, win32.PIPE_TYPE_MESSAGE | win32.PIPE_READMODE_MESSAGE | win32.PIPE_WAIT, 1, obsize, ibsize, win32.NMPWAIT_WAIT_FOREVER, win32.NULL @@ -576,7 +577,10 @@ class SocketListener(object): def __init__(self, address, family, backlog=1): self._socket = socket.socket(getattr(socket, family)) try: - self._socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + # SO_REUSEADDR has different semantics on Windows (issue #2550). + if os.name == 'posix': + self._socket.setsockopt(socket.SOL_SOCKET, + socket.SO_REUSEADDR, 1) self._socket.bind(address) self._socket.listen(backlog) self._address = self._socket.getsockname() @@ -630,7 +634,8 @@ if sys.platform == 'win32': def __init__(self, address, backlog=None): self._address = address handle = win32.CreateNamedPipe( - address, win32.PIPE_ACCESS_DUPLEX, + address, win32.PIPE_ACCESS_DUPLEX | + win32.FILE_FLAG_FIRST_PIPE_INSTANCE, win32.PIPE_TYPE_MESSAGE | win32.PIPE_READMODE_MESSAGE | win32.PIPE_WAIT, win32.PIPE_UNLIMITED_INSTANCES, BUFSIZE, BUFSIZE, diff --git a/Lib/test/test_multiprocessing.py b/Lib/test/test_multiprocessing.py index e5beb97a0bc..f141bd4e483 100644 --- a/Lib/test/test_multiprocessing.py +++ b/Lib/test/test_multiprocessing.py @@ -1779,6 +1779,17 @@ class _TestConnection(BaseTestCase): self.assertRaises(RuntimeError, reduction.recv_handle, conn) p.join() +class _TestListener(BaseTestCase): + + ALLOWED_TYPES = ('processes') + + def test_multiple_bind(self): + for family in self.connection.families: + l = self.connection.Listener(family=family) + self.addCleanup(l.close) + self.assertRaises(OSError, self.connection.Listener, + l.address, family) + class _TestListenerClient(BaseTestCase): ALLOWED_TYPES = ('processes', 'threads') @@ -1799,6 +1810,7 @@ class _TestListenerClient(BaseTestCase): self.assertEqual(conn.recv(), 'hello') p.join() l.close() + # # Test of sending connection and socket objects between processes # diff --git a/Misc/NEWS b/Misc/NEWS index 63385556cbd..7367e1a57f3 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -472,6 +472,11 @@ Library - Issue #13846: Add time.monotonic(), monotonic clock. +- Issue #8184: multiprocessing: On Windows, don't set SO_REUSEADDR on + Connection sockets, and set FILE_FLAG_FIRST_PIPE_INSTANCE on named pipes, to + make sure two listeners can't bind to the same socket/pipe (or any existing + socket/pipe). + - Issue #10811: Fix recursive usage of cursors. Instead of crashing, raise a ProgrammingError now. diff --git a/Modules/_multiprocessing/win32_functions.c b/Modules/_multiprocessing/win32_functions.c index ddc496d9412..e1759971cbd 100644 --- a/Modules/_multiprocessing/win32_functions.c +++ b/Modules/_multiprocessing/win32_functions.c @@ -784,6 +784,7 @@ create_win32_namespace(void) WIN32_CONSTANT(F_DWORD, ERROR_PIPE_BUSY); WIN32_CONSTANT(F_DWORD, ERROR_PIPE_CONNECTED); WIN32_CONSTANT(F_DWORD, ERROR_SEM_TIMEOUT); + WIN32_CONSTANT(F_DWORD, FILE_FLAG_FIRST_PIPE_INSTANCE); WIN32_CONSTANT(F_DWORD, FILE_FLAG_OVERLAPPED); WIN32_CONSTANT(F_DWORD, GENERIC_READ); WIN32_CONSTANT(F_DWORD, GENERIC_WRITE);