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 greenthread
from eventlet import support
from eventlet.green import socket
from eventlet.support import greenlets as greenlet
@ -26,6 +27,10 @@ class ReuseRandomPortWarning(Warning):
pass
class ReusePortUnavailableWarning(Warning):
pass
def listen(addr, family=socket.AF_INET, backlog=50, reuse_addr=True, reuse_port=None):
"""Convenience function for opening server sockets. This
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
if reuse_port and hasattr(socket, 'SO_REUSEPORT'):
# 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.listen(backlog)
return sock

View File

@ -6,6 +6,7 @@ from eventlet import convenience, debug
from eventlet.green import socket
from eventlet.support import six
import tests
import tests.mock
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()
assert len(w) == 1
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)