convenience: SO_REUSEPORT is not available on WSL platform (Linux on Windows)

https://github.com/eventlet/eventlet/issues/380
https://github.com/eventlet/eventlet/issues/418
This commit is contained in:
Sergey Shepelev
2017-05-31 16:50:41 +03:00
parent 0ec4df6cbe
commit 09e166bfbd
2 changed files with 46 additions and 1 deletions

View File

@@ -3,6 +3,7 @@ import warnings
from eventlet import greenpool from eventlet import greenpool
from eventlet import greenthread from eventlet import greenthread
from eventlet import support
from eventlet.green import socket from eventlet.green import socket
from eventlet.support import greenlets as greenlet from eventlet.support import greenlets as greenlet
@@ -26,6 +27,10 @@ class ReuseRandomPortWarning(Warning):
pass pass
class ReusePortUnavailableWarning(Warning):
pass
def listen(addr, family=socket.AF_INET, backlog=50, reuse_addr=True, reuse_port=None): def listen(addr, family=socket.AF_INET, backlog=50, reuse_addr=True, reuse_port=None):
"""Convenience function for opening server sockets. This """Convenience function for opening server sockets. This
socket can be used in :func:`~eventlet.serve` or a custom ``accept()`` loop. socket can be used in :func:`~eventlet.serve` or a custom ``accept()`` loop.
@@ -55,7 +60,20 @@ def listen(addr, family=socket.AF_INET, backlog=50, reuse_addr=True, reuse_port=
reuse_port = True reuse_port = True
if reuse_port and hasattr(socket, 'SO_REUSEPORT'): if reuse_port and hasattr(socket, 'SO_REUSEPORT'):
# NOTE(zhengwei): linux kernel >= 3.9 # NOTE(zhengwei): linux kernel >= 3.9
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1) try:
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
except OSError as ex:
if support.get_errno(ex) in (22, 92):
# A famous platform defines unsupported socket option.
# https://github.com/eventlet/eventlet/issues/380
# https://github.com/eventlet/eventlet/issues/418
warnings.warn(
'''socket.SO_REUSEPORT is defined but not supported.
On Windows: known bug, wontfix.
On other systems: please comment in the issue linked below.
More information: https://github.com/eventlet/eventlet/issues/380''',
ReusePortUnavailableWarning, stacklevel=3)
sock.bind(addr) sock.bind(addr)
sock.listen(backlog) sock.listen(backlog)
return sock return sock

View File

@@ -6,6 +6,7 @@ from eventlet import convenience, debug
from eventlet.green import socket from eventlet.green import socket
from eventlet.support import six from eventlet.support import six
import tests import tests
import tests.mock
certificate_file = os.path.join(os.path.dirname(__file__), 'test_server.crt') certificate_file = os.path.join(os.path.dirname(__file__), 'test_server.crt')
@@ -167,3 +168,29 @@ def test_reuse_random_port_warning():
eventlet.listen(('localhost', 0), reuse_port=True).close() eventlet.listen(('localhost', 0), reuse_port=True).close()
assert len(w) == 1 assert len(w) == 1
assert issubclass(w[0].category, convenience.ReuseRandomPortWarning) assert issubclass(w[0].category, convenience.ReuseRandomPortWarning)
@tests.skip_unless(hasattr(socket, 'SO_REUSEPORT'))
def test_reuseport_oserror():
# https://github.com/eventlet/eventlet/issues/380
# https://github.com/eventlet/eventlet/issues/418
err22 = OSError(22, 'Invalid argument')
sock1 = eventlet.listen(('localhost', 0))
addr = sock1.getsockname()
sock1.close()
original_socket_init = socket.socket.__init__
def patched(self, *a, **kw):
original_socket_init(self, *a, **kw)
self.setsockopt = tests.mock.Mock(side_effect=err22)
with warnings.catch_warnings(record=True) as w:
try:
socket.socket.__init__ = patched
eventlet.listen(addr, reuse_addr=False, reuse_port=True).close()
finally:
socket.socket.__init__ = original_socket_init
assert len(w) == 1
assert issubclass(w[0].category, convenience.ReusePortUnavailableWarning)