mirror of
https://github.com/tahoe-lafs/tahoe-lafs.git
synced 2024-12-23 23:02:25 +00:00
Merge pull request #601 from tahoe-lafs/3026.more-eaddrinuse-fixes
Fix more test suite code that can spuriously trip over EADDRINUSE Fixes: ticket:3026
This commit is contained in:
commit
48a2b42ec1
0
newsfragments/3026.minor
Normal file
0
newsfragments/3026.minor
Normal file
@ -680,12 +680,8 @@ def create_control_tub():
|
||||
port or location
|
||||
"""
|
||||
control_tub = Tub()
|
||||
portnum = iputil.allocate_tcp_port()
|
||||
port = "tcp:%d:interface=127.0.0.1" % portnum
|
||||
location = "tcp:127.0.0.1:%d" % portnum
|
||||
control_tub.listenOn(port)
|
||||
control_tub.setLocation(location)
|
||||
log.msg("Control Tub location set to %s" % (location,))
|
||||
portnum = iputil.listenOnUnused(control_tub)
|
||||
log.msg("Control Tub location set to 127.0.0.1:%s" % (portnum,))
|
||||
return control_tub
|
||||
|
||||
|
||||
@ -767,12 +763,8 @@ class Node(service.MultiService):
|
||||
# to use "flogtool tail" against a remote server), but for now I
|
||||
# think we can live without it.
|
||||
self.log_tub = Tub()
|
||||
portnum = iputil.allocate_tcp_port()
|
||||
port = "tcp:%d:interface=127.0.0.1" % portnum
|
||||
location = "tcp:127.0.0.1:%d" % portnum
|
||||
self.log_tub.listenOn(port)
|
||||
self.log_tub.setLocation(location)
|
||||
self.log("Log Tub location set to %s" % (location,))
|
||||
portnum = iputil.listenOnUnused(self.log_tub)
|
||||
self.log("Log Tub location set to 127.0.0.1:%s" % (portnum,))
|
||||
self.log_tub.setServiceParent(self)
|
||||
|
||||
def startService(self):
|
||||
|
@ -2,7 +2,6 @@
|
||||
import os, re, itertools
|
||||
from base64 import b32decode
|
||||
import json
|
||||
from socket import socket, AF_INET
|
||||
from mock import Mock, patch
|
||||
|
||||
from testtools.matchers import (
|
||||
@ -12,9 +11,6 @@ from testtools.matchers import (
|
||||
from twisted.internet import defer, address
|
||||
from twisted.python import log
|
||||
from twisted.python.filepath import FilePath
|
||||
from twisted.python.reflect import requireModule
|
||||
from twisted.internet.endpoints import AdoptedStreamServerEndpoint
|
||||
from twisted.internet.interfaces import IReactorSocket
|
||||
|
||||
from foolscap.api import Tub, Referenceable, fireEventually, flushEventualQueue
|
||||
from twisted.application import service
|
||||
@ -35,7 +31,10 @@ from allmydata.client import (
|
||||
create_client,
|
||||
create_introducer_clients,
|
||||
)
|
||||
from allmydata.util import pollmixin, keyutil, idlib, fileutil, iputil, yamlutil
|
||||
from allmydata.util import pollmixin, keyutil, idlib, fileutil, yamlutil
|
||||
from allmydata.util.iputil import (
|
||||
listenOnUnused,
|
||||
)
|
||||
import allmydata.test.common_util as testutil
|
||||
from .common import (
|
||||
SyncTestCase,
|
||||
@ -43,8 +42,6 @@ from .common import (
|
||||
AsyncBrokenTestCase,
|
||||
)
|
||||
|
||||
fcntl = requireModule("fcntl")
|
||||
|
||||
class LoggingMultiService(service.MultiService):
|
||||
def log(self, msg, **kw):
|
||||
log.msg(msg, **kw)
|
||||
@ -373,64 +370,6 @@ class Server(AsyncTestCase):
|
||||
|
||||
NICKNAME = u"n\u00EDickname-%s" # LATIN SMALL LETTER I WITH ACUTE
|
||||
|
||||
def foolscapEndpointForPortNumber(portnum):
|
||||
"""
|
||||
Create an endpoint that can be passed to ``Tub.listen``.
|
||||
|
||||
:param portnum: Either an integer port number indicating which TCP/IPv4
|
||||
port number the endpoint should bind or ``None`` to automatically
|
||||
allocate such a port number.
|
||||
|
||||
:return: A two-tuple of the integer port number allocated and a
|
||||
Foolscap-compatible endpoint object.
|
||||
"""
|
||||
if portnum is None:
|
||||
# Bury this reactor import here to minimize the chances of it having
|
||||
# the effect of installing the default reactor.
|
||||
from twisted.internet import reactor
|
||||
if fcntl is not None and IReactorSocket.providedBy(reactor):
|
||||
# On POSIX we can take this very safe approach of binding the
|
||||
# actual socket to an address. Once the bind succeeds here, we're
|
||||
# no longer subject to any future EADDRINUSE problems.
|
||||
s = socket()
|
||||
try:
|
||||
s.bind(('', 0))
|
||||
portnum = s.getsockname()[1]
|
||||
s.listen(1)
|
||||
fd = os.dup(s.fileno())
|
||||
flags = fcntl.fcntl(fd, fcntl.F_GETFD)
|
||||
flags = flags | os.O_NONBLOCK | fcntl.FD_CLOEXEC
|
||||
fcntl.fcntl(fd, fcntl.F_SETFD, flags)
|
||||
return (
|
||||
portnum,
|
||||
AdoptedStreamServerEndpoint(reactor, fd, AF_INET),
|
||||
)
|
||||
finally:
|
||||
s.close()
|
||||
else:
|
||||
# Get a random port number and fall through. This is necessary on
|
||||
# Windows where Twisted doesn't offer IReactorSocket. This
|
||||
# approach is error prone for the reasons described on
|
||||
# https://tahoe-lafs.org/trac/tahoe-lafs/ticket/2787
|
||||
portnum = iputil.allocate_tcp_port()
|
||||
return (portnum, "tcp:%d" % (portnum,))
|
||||
|
||||
def listenOnUnused(tub, portnum=None):
|
||||
"""
|
||||
Start listening on an unused TCP port number with the given tub.
|
||||
|
||||
:param portnum: Either an integer port number indicating which TCP/IPv4
|
||||
port number the endpoint should bind or ``None`` to automatically
|
||||
allocate such a port number.
|
||||
|
||||
:return: An integer indicating the TCP port number on which the tub is now
|
||||
listening.
|
||||
"""
|
||||
portnum, endpoint = foolscapEndpointForPortNumber(portnum)
|
||||
tub.listenOn(endpoint)
|
||||
tub.setLocation("localhost:%d" % (portnum,))
|
||||
return portnum
|
||||
|
||||
class SystemTestMixin(ServiceMixin, pollmixin.PollMixin):
|
||||
|
||||
def create_tub(self, portnum=None):
|
||||
|
@ -1,14 +1,18 @@
|
||||
# from the Python Standard Library
|
||||
import os, re, socket, subprocess, errno
|
||||
|
||||
from sys import platform
|
||||
|
||||
# from Twisted
|
||||
from twisted.python.reflect import requireModule
|
||||
from twisted.internet import defer, threads, reactor
|
||||
from twisted.internet.protocol import DatagramProtocol
|
||||
from twisted.internet.error import CannotListenError
|
||||
from twisted.python.procutils import which
|
||||
from twisted.python import log
|
||||
from twisted.internet.endpoints import AdoptedStreamServerEndpoint
|
||||
from twisted.internet.interfaces import IReactorSocket
|
||||
|
||||
fcntl = requireModule("fcntl")
|
||||
|
||||
from foolscap.util import allocate_tcp_port # re-exported
|
||||
|
||||
@ -239,6 +243,67 @@ def _cygwin_hack_find_addresses():
|
||||
|
||||
return defer.succeed(addresses)
|
||||
|
||||
|
||||
def _foolscapEndpointForPortNumber(portnum):
|
||||
"""
|
||||
Create an endpoint that can be passed to ``Tub.listen``.
|
||||
|
||||
:param portnum: Either an integer port number indicating which TCP/IPv4
|
||||
port number the endpoint should bind or ``None`` to automatically
|
||||
allocate such a port number.
|
||||
|
||||
:return: A two-tuple of the integer port number allocated and a
|
||||
Foolscap-compatible endpoint object.
|
||||
"""
|
||||
if portnum is None:
|
||||
# Bury this reactor import here to minimize the chances of it having
|
||||
# the effect of installing the default reactor.
|
||||
from twisted.internet import reactor
|
||||
if fcntl is not None and IReactorSocket.providedBy(reactor):
|
||||
# On POSIX we can take this very safe approach of binding the
|
||||
# actual socket to an address. Once the bind succeeds here, we're
|
||||
# no longer subject to any future EADDRINUSE problems.
|
||||
s = socket.socket()
|
||||
try:
|
||||
s.bind(('', 0))
|
||||
portnum = s.getsockname()[1]
|
||||
s.listen(1)
|
||||
fd = os.dup(s.fileno())
|
||||
flags = fcntl.fcntl(fd, fcntl.F_GETFD)
|
||||
flags = flags | os.O_NONBLOCK | fcntl.FD_CLOEXEC
|
||||
fcntl.fcntl(fd, fcntl.F_SETFD, flags)
|
||||
return (
|
||||
portnum,
|
||||
AdoptedStreamServerEndpoint(reactor, fd, socket.AF_INET),
|
||||
)
|
||||
finally:
|
||||
s.close()
|
||||
else:
|
||||
# Get a random port number and fall through. This is necessary on
|
||||
# Windows where Twisted doesn't offer IReactorSocket. This
|
||||
# approach is error prone for the reasons described on
|
||||
# https://tahoe-lafs.org/trac/tahoe-lafs/ticket/2787
|
||||
portnum = allocate_tcp_port()
|
||||
return (portnum, "tcp:%d" % (portnum,))
|
||||
|
||||
|
||||
def listenOnUnused(tub, portnum=None):
|
||||
"""
|
||||
Start listening on an unused TCP port number with the given tub.
|
||||
|
||||
:param portnum: Either an integer port number indicating which TCP/IPv4
|
||||
port number the endpoint should bind or ``None`` to automatically
|
||||
allocate such a port number.
|
||||
|
||||
:return: An integer indicating the TCP port number on which the tub is now
|
||||
listening.
|
||||
"""
|
||||
portnum, endpoint = _foolscapEndpointForPortNumber(portnum)
|
||||
tub.listenOn(endpoint)
|
||||
tub.setLocation("localhost:%d" % (portnum,))
|
||||
return portnum
|
||||
|
||||
|
||||
__all__ = ["allocate_tcp_port",
|
||||
"increase_rlimits",
|
||||
"get_local_addresses_sync",
|
||||
|
Loading…
Reference in New Issue
Block a user