mirror of
https://github.com/tahoe-lafs/tahoe-lafs.git
synced 2025-04-13 13:53:07 +00:00
Merge pull request #501 from exarkun/1595.address-already-in-use-test_introducer-create_tub
Fix "Address already in use" errors from test_introducer on POSIX
This commit is contained in:
commit
b31b78e6cf
@ -2,11 +2,15 @@
|
||||
import os, re, itertools
|
||||
from base64 import b32decode
|
||||
import json
|
||||
from socket import socket, AF_INET
|
||||
|
||||
from twisted.trial import unittest
|
||||
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
|
||||
@ -23,6 +27,8 @@ from allmydata.client import create_client
|
||||
from allmydata.util import pollmixin, keyutil, idlib, fileutil, iputil, yamlutil
|
||||
import allmydata.test.common_util as testutil
|
||||
|
||||
fcntl = requireModule("fcntl")
|
||||
|
||||
class LoggingMultiService(service.MultiService):
|
||||
def log(self, msg, **kw):
|
||||
log.msg(msg, **kw)
|
||||
@ -314,6 +320,64 @@ class Server(unittest.TestCase):
|
||||
|
||||
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):
|
||||
@ -323,11 +387,7 @@ class SystemTestMixin(ServiceMixin, pollmixin.PollMixin):
|
||||
#tub.setOption("logRemoteFailures", True)
|
||||
tub.setOption("expose-remote-exception-types", False)
|
||||
tub.setServiceParent(self.parent)
|
||||
if portnum is None:
|
||||
portnum = iputil.allocate_tcp_port()
|
||||
tub.listenOn("tcp:%d" % portnum)
|
||||
self.central_portnum = portnum
|
||||
tub.setLocation("localhost:%d" % self.central_portnum)
|
||||
self.central_portnum = listenOnUnused(tub, portnum)
|
||||
|
||||
class Queue(SystemTestMixin, unittest.TestCase):
|
||||
def test_queue_until_connected(self):
|
||||
@ -414,10 +474,7 @@ class SystemTest(SystemTestMixin, unittest.TestCase):
|
||||
#tub.setOption("logRemoteFailures", True)
|
||||
tub.setOption("expose-remote-exception-types", False)
|
||||
tub.setServiceParent(self.parent)
|
||||
portnum = iputil.allocate_tcp_port()
|
||||
tub.listenOn("tcp:%d" % portnum)
|
||||
tub.setLocation("localhost:%d" % portnum)
|
||||
|
||||
listenOnUnused(tub)
|
||||
log.msg("creating client %d: %s" % (i, tub.getShortTubID()))
|
||||
c = IntroducerClient(tub, self.introducer_furl,
|
||||
NICKNAME % str(i),
|
||||
@ -895,10 +952,7 @@ class NonV1Server(SystemTestMixin, unittest.TestCase):
|
||||
tub = Tub()
|
||||
tub.setOption("expose-remote-exception-types", False)
|
||||
tub.setServiceParent(self.parent)
|
||||
portnum = iputil.allocate_tcp_port()
|
||||
tub.listenOn("tcp:%d" % portnum)
|
||||
tub.setLocation("localhost:%d" % portnum)
|
||||
|
||||
listenOnUnused(tub)
|
||||
c = IntroducerClient(tub, self.introducer_furl,
|
||||
u"nickname-client", "version", "oldest", {},
|
||||
fakeseq, FilePath(self.mktemp()))
|
||||
|
Loading…
x
Reference in New Issue
Block a user