From 5587d7c071e5725d8aaf565b985441011cb1449f Mon Sep 17 00:00:00 2001 From: Yury Selivanov Date: Thu, 15 Sep 2016 15:45:07 -0400 Subject: [PATCH] Issue #28174: Handle when SO_REUSEPORT isn't properly supported (asyncio) Patch by Seth Michael Larson. --- Lib/asyncio/base_events.py | 25 ++++++++++++----------- Lib/test/test_asyncio/test_base_events.py | 11 ++++++++++ Misc/NEWS | 3 +++ 3 files changed, 27 insertions(+), 12 deletions(-) diff --git a/Lib/asyncio/base_events.py b/Lib/asyncio/base_events.py index 8d926dc901e..03935ea94ba 100644 --- a/Lib/asyncio/base_events.py +++ b/Lib/asyncio/base_events.py @@ -76,6 +76,17 @@ def _format_pipe(fd): return repr(fd) +def _set_reuseport(sock): + if not hasattr(socket, 'SO_REUSEPORT'): + raise ValueError('reuse_port not supported by socket module') + else: + try: + sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1) + except OSError: + raise ValueError('reuse_port not supported by socket module, ' + 'SO_REUSEPORT defined but not implemented.') + + # Linux's sock.type is a bitmask that can include extra info about socket. _SOCKET_TYPE_MASK = 0 if hasattr(socket, 'SOCK_NONBLOCK'): @@ -873,12 +884,7 @@ class BaseEventLoop(events.AbstractEventLoop): sock.setsockopt( socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) if reuse_port: - if not hasattr(socket, 'SO_REUSEPORT'): - raise ValueError( - 'reuse_port not supported by socket module') - else: - sock.setsockopt( - socket.SOL_SOCKET, socket.SO_REUSEPORT, 1) + _set_reuseport(sock) if allow_broadcast: sock.setsockopt( socket.SOL_SOCKET, socket.SO_BROADCAST, 1) @@ -1001,12 +1007,7 @@ class BaseEventLoop(events.AbstractEventLoop): sock.setsockopt( socket.SOL_SOCKET, socket.SO_REUSEADDR, True) if reuse_port: - if not hasattr(socket, 'SO_REUSEPORT'): - raise ValueError( - 'reuse_port not supported by socket module') - else: - sock.setsockopt( - socket.SOL_SOCKET, socket.SO_REUSEPORT, True) + _set_reuseport(sock) # Disable IPv4/IPv6 dual stack support (enabled by # default on Linux) which makes a single socket # listen on both address families. diff --git a/Lib/test/test_asyncio/test_base_events.py b/Lib/test/test_asyncio/test_base_events.py index 0efdc202df1..43ebdc8b2cb 100644 --- a/Lib/test/test_asyncio/test_base_events.py +++ b/Lib/test/test_asyncio/test_base_events.py @@ -1370,6 +1370,17 @@ class BaseEventLoopWithSelectorTests(test_utils.TestCase): self.assertRaises(ValueError, self.loop.run_until_complete, f) + @patch_socket + def test_create_server_soreuseport_only_defined(self, m_socket): + m_socket.getaddrinfo = socket.getaddrinfo + m_socket.socket.return_value = mock.Mock() + m_socket.SO_REUSEPORT = -1 + + f = self.loop.create_server( + MyProto, '0.0.0.0', 0, reuse_port=True) + + self.assertRaises(ValueError, self.loop.run_until_complete, f) + @patch_socket def test_create_server_cant_bind(self, m_socket): diff --git a/Misc/NEWS b/Misc/NEWS index 0ebf5408449..b63aafd96b6 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -266,6 +266,9 @@ Library - Issue #27906: Fix socket accept exhaustion during high TCP traffic. Patch by Kevin Conway. +- Issue #28174: Handle when SO_REUSEPORT isn't properly supported. + Patch by Seth Michael Larson. + IDLE ----