Skip to content

Commit

Permalink
replace allocate_tcp_port() with synchronous form
Browse files Browse the repository at this point in the history
  • Loading branch information
warner committed Sep 11, 2015
1 parent 257cf4b commit a85d9dc
Show file tree
Hide file tree
Showing 2 changed files with 23 additions and 22 deletions.
18 changes: 8 additions & 10 deletions foolscap/test/test_util.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,16 +112,14 @@ def test_format(self):

class AllocatePort(unittest.TestCase):
def test_allocate(self):
d = util.allocate_tcp_port()
def _check(port):
self.failUnless(isinstance(port, int))
self.failUnless(1 <= port <= 65535, port)
# the allocation function should release the port before it
# returns, so it should be possible to listen on it immediately
desc = "tcp:%d:interface=127.0.0.1" % port
ep = endpoints.serverFromString(reactor, desc)
return ep.listen(protocol.Factory())
d.addCallback(_check)
p = util.allocate_tcp_port()
self.failUnless(isinstance(p, int))
self.failUnless(1 <= p <= 65535, p)
# the allocation function should release the port before it
# returns, so it should be possible to listen on it immediately
desc = "tcp:%d:interface=127.0.0.1" % p
ep = endpoints.serverFromString(reactor, desc)
d = ep.listen(protocol.Factory())
def _free(port):
return port.stopListening()
d.addCallback(_free)
Expand Down
27 changes: 15 additions & 12 deletions foolscap/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@
import socket
import time
from twisted.internet import defer, reactor, protocol
from twisted.internet.endpoints import serverFromString

from twisted.python.runtime import platformType

class AsyncAND(defer.Deferred):
"""Like DeferredList, but results are discarded and failures handled
Expand Down Expand Up @@ -117,14 +116,18 @@ def isSubstring(small, big):
assert type(small) is str and type(big) is str
return small in big

@defer.inlineCallbacks
def allocate_tcp_port():
"""
Returns a Deferred that fires with an available TCP port on localhost.
"""

endpoint = serverFromString(reactor, "tcp:0:interface=127.0.0.1")
port = yield endpoint.listen(protocol.Factory())
address = port.getHost()
yield port.stopListening()
defer.returnValue(address.port)
"""Return an (integer) available TCP port on localhost. This briefly
listens on the port in question, then closes it right away."""
# We want to bind() the socket but not listen(). Twisted (in
# tcp.Port.createInternetSocket) would do several other things:
# non-blocking, close-on-exec, and SO_REUSEADDR. We don't need
# non-blocking because we never listen on it, and we don't need
# close-on-exec because we close it right away. So just add SO_REUSEADDR.
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
if platformType == "posix" and sys.platform != "cygwin":
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind(("127.0.0.1", 0))
port = s.getsockname()[1]
s.close()
return port

0 comments on commit a85d9dc

Please sign in to comment.