2016-06-04 21:03:05 +00:00
|
|
|
# no unicode_literals untill twisted update
|
2017-11-13 19:34:17 +00:00
|
|
|
from twisted.application import service, internet
|
|
|
|
from twisted.internet import defer, task, reactor, endpoints
|
2016-03-02 00:59:46 +00:00
|
|
|
from twisted.python import log
|
2016-07-15 04:22:01 +00:00
|
|
|
from click.testing import CliRunner
|
|
|
|
import mock
|
|
|
|
from ..cli import cli
|
2016-05-24 23:22:37 +00:00
|
|
|
from ..transit import allocate_tcp_port
|
2016-04-21 02:04:01 +00:00
|
|
|
from ..server.server import RelayServer
|
2017-11-13 19:34:17 +00:00
|
|
|
from wormhole_transit_relay.transit_server import Transit
|
2015-09-27 00:59:39 +00:00
|
|
|
|
|
|
|
class ServerBase:
|
|
|
|
def setUp(self):
|
2016-05-26 22:37:24 +00:00
|
|
|
self._setup_relay(None)
|
|
|
|
|
2017-06-26 13:34:07 +00:00
|
|
|
def _setup_relay(self, error, advertise_version=None):
|
2015-09-27 00:59:39 +00:00
|
|
|
self.sp = service.MultiService()
|
|
|
|
self.sp.startService()
|
2016-06-18 06:20:18 +00:00
|
|
|
self.relayport = allocate_tcp_port()
|
2016-06-04 06:07:50 +00:00
|
|
|
# need to talk to twisted team about only using unicode in
|
|
|
|
# endpoints.serverFromString
|
2016-06-18 06:20:18 +00:00
|
|
|
s = RelayServer("tcp:%d:interface=127.0.0.1" % self.relayport,
|
2017-06-26 13:34:07 +00:00
|
|
|
advertise_version=advertise_version,
|
2016-05-26 22:37:24 +00:00
|
|
|
signal_error=error)
|
2016-04-16 02:18:33 +00:00
|
|
|
s.setServiceParent(self.sp)
|
2017-05-15 23:10:22 +00:00
|
|
|
self._relay_server = s
|
2016-04-19 00:57:14 +00:00
|
|
|
self._rendezvous = s._rendezvous
|
2016-06-18 06:20:18 +00:00
|
|
|
self.relayurl = u"ws://127.0.0.1:%d/v1" % self.relayport
|
|
|
|
self.rdv_ws_port = self.relayport
|
2016-04-19 00:57:27 +00:00
|
|
|
# ws://127.0.0.1:%d/wormhole-relay/ws
|
2017-11-13 19:34:17 +00:00
|
|
|
|
|
|
|
self.transitport = allocate_tcp_port()
|
|
|
|
ep = endpoints.serverFromString(reactor,
|
|
|
|
"tcp:%d:interface=127.0.0.1" %
|
|
|
|
self.transitport)
|
|
|
|
self._transit_server = f = Transit(blur_usage=None, log_file=None,
|
|
|
|
usage_db=None)
|
|
|
|
internet.StreamServerEndpointService(ep, f).setServiceParent(self.sp)
|
2016-06-18 06:20:18 +00:00
|
|
|
self.transit = u"tcp:127.0.0.1:%d" % self.transitport
|
2015-09-27 00:59:39 +00:00
|
|
|
|
|
|
|
def tearDown(self):
|
2016-03-02 00:59:46 +00:00
|
|
|
# Unit tests that spawn a (blocking) client in a thread might still
|
|
|
|
# have threads running at this point, if one is stuck waiting for a
|
|
|
|
# message from a companion which has exited with an error. Our
|
|
|
|
# relay's .stopService() drops all connections, which ought to
|
|
|
|
# encourage those threads to terminate soon. If they don't, print a
|
|
|
|
# warning to ease debugging.
|
2016-06-03 22:17:47 +00:00
|
|
|
|
|
|
|
# XXX FIXME there's something in _noclobber test that's not
|
|
|
|
# waiting for a close, I think -- was pretty relieably getting
|
|
|
|
# unclean-reactor, but adding a slight pause here stops it...
|
|
|
|
from twisted.internet import reactor
|
|
|
|
|
2016-03-02 00:59:46 +00:00
|
|
|
tp = reactor.getThreadPool()
|
|
|
|
if not tp.working:
|
2016-06-03 22:17:47 +00:00
|
|
|
d = defer.succeed(None)
|
|
|
|
d.addCallback(lambda _: self.sp.stopService())
|
|
|
|
d.addCallback(lambda _: task.deferLater(reactor, 0.1, lambda: None))
|
|
|
|
return d
|
2016-03-02 00:59:46 +00:00
|
|
|
return self.sp.stopService()
|
|
|
|
# disconnect all callers
|
|
|
|
d = defer.maybeDeferred(self.sp.stopService)
|
|
|
|
wait_d = defer.Deferred()
|
|
|
|
# wait a second, then check to see if it worked
|
|
|
|
reactor.callLater(1.0, wait_d.callback, None)
|
|
|
|
def _later(res):
|
|
|
|
if len(tp.working):
|
|
|
|
log.msg("wormhole.test.common.ServerBase.tearDown:"
|
|
|
|
" I was unable to convince all threads to exit.")
|
|
|
|
tp.dumpStats()
|
|
|
|
print("tearDown warning: threads are still active")
|
|
|
|
print("This test will probably hang until one of the"
|
|
|
|
" clients gives up of their own accord.")
|
|
|
|
else:
|
|
|
|
log.msg("wormhole.test.common.ServerBase.tearDown:"
|
|
|
|
" I convinced all threads to exit.")
|
|
|
|
return d
|
|
|
|
wait_d.addCallback(_later)
|
|
|
|
return wait_d
|
2016-07-15 04:22:01 +00:00
|
|
|
|
|
|
|
def config(*argv):
|
|
|
|
r = CliRunner()
|
|
|
|
with mock.patch("wormhole.cli.cli.go") as go:
|
|
|
|
res = r.invoke(cli.wormhole, argv, catch_exceptions=False)
|
|
|
|
if res.exit_code != 0:
|
|
|
|
print(res.exit_code)
|
|
|
|
print(res.output)
|
|
|
|
print(res)
|
|
|
|
assert 0
|
|
|
|
cfg = go.call_args[0][1]
|
|
|
|
return cfg
|
|
|
|
|
2017-04-06 17:44:04 +00:00
|
|
|
@defer.inlineCallbacks
|
|
|
|
def poll_until(predicate):
|
|
|
|
# return a Deferred that won't fire until the predicate is True
|
|
|
|
while not predicate():
|
|
|
|
d = defer.Deferred()
|
|
|
|
reactor.callLater(0.001, d.callback, None)
|
|
|
|
yield d
|
add w.when_key(), fix w.when_verified() to fire later
Previously, w.when_verified() was documented to fire only after a valid
encrypted message was received, but in fact it fired as soon as the shared
key was derived (before any encrypted messages are seen, so no actual
"verification" could occur yet).
This fixes that, and also adds a new w.when_key() API call which fires at the
earlier point. Having something which fires early is useful for the CLI
commands that want to print a pacifier message when the peer is responding
slowly. In particular it helps detect the case where 'wormhole send' has quit
early (after depositing the PAKE message on the server, but before the
receiver has started). In this case, the receiver will compute the shared
key, but then wait forever hoping for a VERSION that will never come. By
starting a timer when w.when_key() fires, and cancelling it when
w.when_verified() fires, we have a good place to tell the user that something
is taking longer than it should have.
This shifts responsibility for notifying Boss.got_verifier, out of Key and
into Receive, since Receive is what notices the first valid encrypted
message. It also shifts the Boss's ordering expectations: it now receives
B.happy() before B.got_verifier(), and consequently got_verifier ought to
arrive in the S2_happy state rather than S1_lonely.
2017-04-07 01:27:41 +00:00
|
|
|
|
|
|
|
@defer.inlineCallbacks
|
|
|
|
def pause_one_tick():
|
|
|
|
# return a Deferred that won't fire until at least the next reactor tick
|
|
|
|
d = defer.Deferred()
|
|
|
|
reactor.callLater(0.001, d.callback, None)
|
|
|
|
yield d
|