2007-03-27 23:12:11 +00:00
|
|
|
|
2016-07-20 00:22:12 +00:00
|
|
|
import os, re, itertools
|
2009-06-24 19:40:38 +00:00
|
|
|
from base64 import b32decode
|
2017-01-19 22:39:53 +00:00
|
|
|
import json
|
2018-06-08 14:36:45 +00:00
|
|
|
from socket import socket, AF_INET
|
2018-09-11 03:39:50 +00:00
|
|
|
from mock import Mock, patch
|
2007-12-03 21:52:42 +00:00
|
|
|
|
2019-03-07 20:04:53 +00:00
|
|
|
from testtools.matchers import (
|
|
|
|
Is,
|
|
|
|
)
|
|
|
|
|
2007-03-27 23:12:11 +00:00
|
|
|
from twisted.trial import unittest
|
2012-04-23 22:02:22 +00:00
|
|
|
from twisted.internet import defer, address
|
2007-03-27 23:12:11 +00:00
|
|
|
from twisted.python import log
|
2016-05-10 20:19:35 +00:00
|
|
|
from twisted.python.filepath import FilePath
|
2018-06-08 17:15:19 +00:00
|
|
|
from twisted.python.reflect import requireModule
|
2018-06-08 14:36:45 +00:00
|
|
|
from twisted.internet.endpoints import AdoptedStreamServerEndpoint
|
2018-06-08 17:12:46 +00:00
|
|
|
from twisted.internet.interfaces import IReactorSocket
|
2007-03-27 23:12:11 +00:00
|
|
|
|
2009-05-22 00:38:23 +00:00
|
|
|
from foolscap.api import Tub, Referenceable, fireEventually, flushEventualQueue
|
2007-03-27 23:12:11 +00:00
|
|
|
from twisted.application import service
|
2008-11-22 03:07:27 +00:00
|
|
|
from allmydata.interfaces import InsufficientVersionError
|
2016-06-02 16:47:58 +00:00
|
|
|
from allmydata.introducer.client import IntroducerClient
|
2013-03-20 22:10:47 +00:00
|
|
|
from allmydata.introducer.server import IntroducerService, FurlFileConflictError
|
new introducer: signed extensible dictionary-based messages! refs #466
This introduces new client and server halves to the Introducer (renaming the
old one with a _V1 suffix). Both have fallbacks to accomodate talking to a
different version: the publishing client switches on whether the server's
.get_version() advertises V2 support, the server switches on which
subscription method was invoked by the subscribing client.
The V2 protocol sends a three-tuple of (serialized announcement dictionary,
signature, pubkey) for each announcement. The V2 server dispatches messages
to subscribers according to the service-name, and throws errors for invalid
signatures, but does not otherwise examine the messages. The V2 receiver's
subscription callback will receive a (serverid, ann_dict) pair. The
'serverid' will be equal to the pubkey if all of the following are true:
the originating client is V2, and was told a privkey to use
the announcement went through a V2 server
the signature is valid
If not, 'serverid' will be equal to the tubid portion of the announced FURL,
as was the case for V1 receivers.
Servers will create a keypair if one does not exist yet, stored in
private/server.privkey .
The signed announcement dictionary puts the server FURL in a key named
"anonymous-storage-FURL", which anticipates upcoming Accounting-related
changes in the server advertisements. It also provides a key named
"permutation-seed-base32" to tell clients what permutation seed to use. This
is computed at startup, using tubid if there are existing shares, otherwise
the pubkey, to retain share-order compatibility for existing servers.
2011-11-20 10:21:32 +00:00
|
|
|
from allmydata.introducer.common import get_tubid_string_from_ann, \
|
|
|
|
get_tubid_string, sign_to_foolscap, unsign_from_foolscap, \
|
|
|
|
UnknownKeyError
|
2018-09-11 03:39:50 +00:00
|
|
|
from allmydata.node import (
|
|
|
|
create_node_dir,
|
|
|
|
read_config,
|
|
|
|
)
|
2017-09-06 01:08:35 +00:00
|
|
|
# the "new way" to create introducer node instance
|
|
|
|
from allmydata.introducer.server import create_introducer
|
2012-04-23 22:02:22 +00:00
|
|
|
from allmydata.web import introweb
|
2018-09-11 03:39:50 +00:00
|
|
|
from allmydata.client import (
|
|
|
|
create_client,
|
|
|
|
create_introducer_clients,
|
|
|
|
)
|
2016-07-20 00:22:12 +00:00
|
|
|
from allmydata.util import pollmixin, keyutil, idlib, fileutil, iputil, yamlutil
|
2010-02-26 08:14:33 +00:00
|
|
|
import allmydata.test.common_util as testutil
|
2019-03-07 20:04:53 +00:00
|
|
|
from .common import (
|
|
|
|
SyncTestCase,
|
2019-03-07 23:56:25 +00:00
|
|
|
AsyncTestCase,
|
|
|
|
AsyncBrokenTestCase,
|
2019-03-07 20:04:53 +00:00
|
|
|
)
|
2007-03-27 23:12:11 +00:00
|
|
|
|
2018-06-08 17:15:19 +00:00
|
|
|
fcntl = requireModule("fcntl")
|
|
|
|
|
2007-03-27 23:12:11 +00:00
|
|
|
class LoggingMultiService(service.MultiService):
|
2007-11-20 01:23:18 +00:00
|
|
|
def log(self, msg, **kw):
|
|
|
|
log.msg(msg, **kw)
|
2007-03-27 23:12:11 +00:00
|
|
|
|
2019-03-07 20:04:53 +00:00
|
|
|
class Node(testutil.SignalMixin, testutil.ReallyEqualMixin, AsyncTestCase):
|
2017-09-06 01:08:35 +00:00
|
|
|
|
|
|
|
def test_backwards_compat_import(self):
|
|
|
|
# for old introducer .tac files
|
|
|
|
from allmydata.introducer import IntroducerNode
|
|
|
|
IntroducerNode # pyflakes
|
|
|
|
|
2018-01-28 06:13:50 +00:00
|
|
|
@defer.inlineCallbacks
|
2018-03-01 23:07:52 +00:00
|
|
|
def test_create(self):
|
2018-08-24 22:50:04 +00:00
|
|
|
"""
|
|
|
|
A brand new introducer creates its config dir
|
|
|
|
"""
|
2018-03-01 23:07:52 +00:00
|
|
|
basedir = "introducer.IntroducerNode.test_create"
|
2018-01-28 06:13:50 +00:00
|
|
|
yield create_introducer(basedir)
|
2018-03-01 23:07:52 +00:00
|
|
|
self.assertTrue(os.path.exists(basedir))
|
|
|
|
|
2018-09-11 03:39:50 +00:00
|
|
|
def test_introducer_clients_unloadable(self):
|
|
|
|
"""
|
2018-09-11 17:14:41 +00:00
|
|
|
Error if introducers.yaml exists but we can't read it
|
2018-09-11 03:39:50 +00:00
|
|
|
"""
|
2018-09-11 17:14:41 +00:00
|
|
|
basedir = u"introducer.IntroducerNode.test_introducer_clients_unloadable"
|
2018-09-11 03:39:50 +00:00
|
|
|
os.mkdir(basedir)
|
2018-09-11 17:14:41 +00:00
|
|
|
os.mkdir(os.path.join(basedir, u"private"))
|
|
|
|
yaml_fname = os.path.join(basedir, u"private", u"introducers.yaml")
|
|
|
|
with open(yaml_fname, 'w') as f:
|
|
|
|
f.write(u'---\n')
|
|
|
|
os.chmod(yaml_fname, 0o000)
|
|
|
|
self.addCleanup(lambda: os.chmod(yaml_fname, 0o700))
|
2018-09-11 03:39:50 +00:00
|
|
|
# just mocking the yaml failure, as "yamlutil.safe_load" only
|
2018-09-11 17:14:41 +00:00
|
|
|
# returns None on some platforms for unreadable files
|
2018-09-11 03:39:50 +00:00
|
|
|
|
|
|
|
with patch("allmydata.client.yamlutil") as p:
|
|
|
|
p.safe_load = Mock(return_value=None)
|
|
|
|
|
|
|
|
fake_tub = Mock()
|
|
|
|
config = read_config(basedir, "portnum")
|
|
|
|
|
2018-09-11 17:38:56 +00:00
|
|
|
with self.assertRaises(EnvironmentError):
|
2018-09-11 17:14:41 +00:00
|
|
|
create_introducer_clients(config, fake_tub)
|
2018-09-11 03:39:50 +00:00
|
|
|
|
2018-01-28 06:13:50 +00:00
|
|
|
@defer.inlineCallbacks
|
2013-03-20 22:10:47 +00:00
|
|
|
def test_furl(self):
|
|
|
|
basedir = "introducer.IntroducerNode.test_furl"
|
2018-02-27 22:00:31 +00:00
|
|
|
create_node_dir(basedir, "testing")
|
2013-03-20 22:10:47 +00:00
|
|
|
public_fn = os.path.join(basedir, "introducer.furl")
|
|
|
|
private_fn = os.path.join(basedir, "private", "introducer.furl")
|
2016-04-27 04:54:45 +00:00
|
|
|
|
2018-01-28 06:13:50 +00:00
|
|
|
q1 = yield create_introducer(basedir)
|
2016-04-27 04:54:45 +00:00
|
|
|
del q1
|
|
|
|
# new nodes create unguessable furls in private/introducer.furl
|
|
|
|
ifurl = fileutil.read(private_fn)
|
|
|
|
self.failUnless(ifurl)
|
|
|
|
ifurl = ifurl.strip()
|
|
|
|
self.failIf(ifurl.endswith("/introducer"), ifurl)
|
2013-03-20 22:10:47 +00:00
|
|
|
|
2016-04-27 04:54:45 +00:00
|
|
|
# old nodes created guessable furls in BASEDIR/introducer.furl
|
|
|
|
guessable = ifurl[:ifurl.rfind("/")] + "/introducer"
|
|
|
|
fileutil.write(public_fn, guessable+"\n", mode="w") # text
|
2013-03-20 22:10:47 +00:00
|
|
|
|
2016-04-27 04:54:45 +00:00
|
|
|
# if we see both files, throw an error
|
2018-01-28 06:13:50 +00:00
|
|
|
with self.assertRaises(FurlFileConflictError):
|
|
|
|
yield create_introducer(basedir)
|
2013-03-20 22:10:47 +00:00
|
|
|
|
2016-04-27 04:54:45 +00:00
|
|
|
# when we see only the public one, move it to private/ and use
|
|
|
|
# the existing furl instead of creating a new one
|
|
|
|
os.unlink(private_fn)
|
|
|
|
|
2018-01-28 06:13:50 +00:00
|
|
|
q2 = yield create_introducer(basedir)
|
2016-04-27 04:54:45 +00:00
|
|
|
del q2
|
|
|
|
self.failIf(os.path.exists(public_fn))
|
|
|
|
ifurl2 = fileutil.read(private_fn)
|
|
|
|
self.failUnless(ifurl2)
|
|
|
|
self.failUnlessEqual(ifurl2.strip(), guessable)
|
2007-12-03 21:52:42 +00:00
|
|
|
|
2018-01-28 06:13:50 +00:00
|
|
|
@defer.inlineCallbacks
|
2015-02-04 06:09:40 +00:00
|
|
|
def test_web_static(self):
|
|
|
|
basedir = u"introducer.Node.test_web_static"
|
2018-02-27 22:00:31 +00:00
|
|
|
create_node_dir(basedir, "testing")
|
2015-02-04 06:09:40 +00:00
|
|
|
fileutil.write(os.path.join(basedir, "tahoe.cfg"),
|
|
|
|
"[node]\n" +
|
|
|
|
"web.port = tcp:0:interface=127.0.0.1\n" +
|
|
|
|
"web.static = relative\n")
|
2018-01-28 06:13:50 +00:00
|
|
|
c = yield create_introducer(basedir)
|
2015-02-04 06:09:40 +00:00
|
|
|
w = c.getServiceNamed("webish")
|
|
|
|
abs_basedir = fileutil.abspath_expanduser_unicode(basedir)
|
|
|
|
expected = fileutil.abspath_expanduser_unicode(u"relative", abs_basedir)
|
|
|
|
self.failUnlessReallyEqual(w.staticdir, expected)
|
|
|
|
|
|
|
|
|
2019-03-07 19:04:17 +00:00
|
|
|
class ServiceMixin(object):
|
2007-03-27 23:12:11 +00:00
|
|
|
def setUp(self):
|
|
|
|
self.parent = LoggingMultiService()
|
|
|
|
self.parent.startService()
|
2019-03-07 19:04:17 +00:00
|
|
|
return super(ServiceMixin, self).setUp()
|
|
|
|
|
2007-03-27 23:12:11 +00:00
|
|
|
def tearDown(self):
|
|
|
|
log.msg("TestIntroducer.tearDown")
|
2019-03-07 23:34:59 +00:00
|
|
|
d = defer.maybeDeferred(super(ServiceMixin, self).tearDown)
|
2007-03-27 23:12:11 +00:00
|
|
|
d.addCallback(lambda res: self.parent.stopService())
|
2007-03-28 00:16:13 +00:00
|
|
|
d.addCallback(flushEventualQueue)
|
2007-03-27 23:12:11 +00:00
|
|
|
return d
|
|
|
|
|
2019-03-07 23:18:48 +00:00
|
|
|
class Introducer(ServiceMixin, AsyncTestCase):
|
2007-03-27 23:12:11 +00:00
|
|
|
def test_create(self):
|
2009-06-23 02:10:47 +00:00
|
|
|
ic = IntroducerClient(None, "introducer.furl", u"my_nickname",
|
2016-05-10 19:14:36 +00:00
|
|
|
"my_version", "oldest_version", {}, fakeseq,
|
|
|
|
FilePath(self.mktemp()))
|
2010-01-14 22:17:19 +00:00
|
|
|
self.failUnless(isinstance(ic, IntroducerClient))
|
2007-03-27 23:12:11 +00:00
|
|
|
|
|
|
|
def test_listen(self):
|
2007-12-03 21:52:42 +00:00
|
|
|
i = IntroducerService()
|
2007-03-27 23:12:11 +00:00
|
|
|
i.setServiceParent(self.parent)
|
|
|
|
|
new introducer: signed extensible dictionary-based messages! refs #466
This introduces new client and server halves to the Introducer (renaming the
old one with a _V1 suffix). Both have fallbacks to accomodate talking to a
different version: the publishing client switches on whether the server's
.get_version() advertises V2 support, the server switches on which
subscription method was invoked by the subscribing client.
The V2 protocol sends a three-tuple of (serialized announcement dictionary,
signature, pubkey) for each announcement. The V2 server dispatches messages
to subscribers according to the service-name, and throws errors for invalid
signatures, but does not otherwise examine the messages. The V2 receiver's
subscription callback will receive a (serverid, ann_dict) pair. The
'serverid' will be equal to the pubkey if all of the following are true:
the originating client is V2, and was told a privkey to use
the announcement went through a V2 server
the signature is valid
If not, 'serverid' will be equal to the tubid portion of the announced FURL,
as was the case for V1 receivers.
Servers will create a keypair if one does not exist yet, stored in
private/server.privkey .
The signed announcement dictionary puts the server FURL in a key named
"anonymous-storage-FURL", which anticipates upcoming Accounting-related
changes in the server advertisements. It also provides a key named
"permutation-seed-base32" to tell clients what permutation seed to use. This
is computed at startup, using tubid if there are existing shares, otherwise
the pubkey, to retain share-order compatibility for existing servers.
2011-11-20 10:21:32 +00:00
|
|
|
|
2013-03-19 00:40:56 +00:00
|
|
|
def fakeseq():
|
|
|
|
return 1, "nonce"
|
|
|
|
|
|
|
|
seqnum_counter = itertools.count(1)
|
|
|
|
def realseq():
|
|
|
|
return seqnum_counter.next(), str(os.randint(1,100000))
|
|
|
|
|
new introducer: signed extensible dictionary-based messages! refs #466
This introduces new client and server halves to the Introducer (renaming the
old one with a _V1 suffix). Both have fallbacks to accomodate talking to a
different version: the publishing client switches on whether the server's
.get_version() advertises V2 support, the server switches on which
subscription method was invoked by the subscribing client.
The V2 protocol sends a three-tuple of (serialized announcement dictionary,
signature, pubkey) for each announcement. The V2 server dispatches messages
to subscribers according to the service-name, and throws errors for invalid
signatures, but does not otherwise examine the messages. The V2 receiver's
subscription callback will receive a (serverid, ann_dict) pair. The
'serverid' will be equal to the pubkey if all of the following are true:
the originating client is V2, and was told a privkey to use
the announcement went through a V2 server
the signature is valid
If not, 'serverid' will be equal to the tubid portion of the announced FURL,
as was the case for V1 receivers.
Servers will create a keypair if one does not exist yet, stored in
private/server.privkey .
The signed announcement dictionary puts the server FURL in a key named
"anonymous-storage-FURL", which anticipates upcoming Accounting-related
changes in the server advertisements. It also provides a key named
"permutation-seed-base32" to tell clients what permutation seed to use. This
is computed at startup, using tubid if there are existing shares, otherwise
the pubkey, to retain share-order compatibility for existing servers.
2011-11-20 10:21:32 +00:00
|
|
|
def make_ann(furl):
|
|
|
|
ann = { "anonymous-storage-FURL": furl,
|
|
|
|
"permutation-seed-base32": get_tubid_string(furl) }
|
|
|
|
return ann
|
|
|
|
|
2012-06-11 02:10:22 +00:00
|
|
|
def make_ann_t(ic, furl, privkey, seqnum):
|
2016-05-11 01:33:56 +00:00
|
|
|
assert privkey
|
2013-03-19 00:40:56 +00:00
|
|
|
ann_d = ic.create_announcement_dict("storage", make_ann(furl))
|
|
|
|
ann_d["seqnum"] = seqnum
|
|
|
|
ann_d["nonce"] = "nonce"
|
|
|
|
ann_t = sign_to_foolscap(ann_d, privkey)
|
|
|
|
return ann_t
|
new introducer: signed extensible dictionary-based messages! refs #466
This introduces new client and server halves to the Introducer (renaming the
old one with a _V1 suffix). Both have fallbacks to accomodate talking to a
different version: the publishing client switches on whether the server's
.get_version() advertises V2 support, the server switches on which
subscription method was invoked by the subscribing client.
The V2 protocol sends a three-tuple of (serialized announcement dictionary,
signature, pubkey) for each announcement. The V2 server dispatches messages
to subscribers according to the service-name, and throws errors for invalid
signatures, but does not otherwise examine the messages. The V2 receiver's
subscription callback will receive a (serverid, ann_dict) pair. The
'serverid' will be equal to the pubkey if all of the following are true:
the originating client is V2, and was told a privkey to use
the announcement went through a V2 server
the signature is valid
If not, 'serverid' will be equal to the tubid portion of the announced FURL,
as was the case for V1 receivers.
Servers will create a keypair if one does not exist yet, stored in
private/server.privkey .
The signed announcement dictionary puts the server FURL in a key named
"anonymous-storage-FURL", which anticipates upcoming Accounting-related
changes in the server advertisements. It also provides a key named
"permutation-seed-base32" to tell clients what permutation seed to use. This
is computed at startup, using tubid if there are existing shares, otherwise
the pubkey, to retain share-order compatibility for existing servers.
2011-11-20 10:21:32 +00:00
|
|
|
|
2019-03-07 20:04:53 +00:00
|
|
|
class Client(AsyncTestCase):
|
new introducer: signed extensible dictionary-based messages! refs #466
This introduces new client and server halves to the Introducer (renaming the
old one with a _V1 suffix). Both have fallbacks to accomodate talking to a
different version: the publishing client switches on whether the server's
.get_version() advertises V2 support, the server switches on which
subscription method was invoked by the subscribing client.
The V2 protocol sends a three-tuple of (serialized announcement dictionary,
signature, pubkey) for each announcement. The V2 server dispatches messages
to subscribers according to the service-name, and throws errors for invalid
signatures, but does not otherwise examine the messages. The V2 receiver's
subscription callback will receive a (serverid, ann_dict) pair. The
'serverid' will be equal to the pubkey if all of the following are true:
the originating client is V2, and was told a privkey to use
the announcement went through a V2 server
the signature is valid
If not, 'serverid' will be equal to the tubid portion of the announced FURL,
as was the case for V1 receivers.
Servers will create a keypair if one does not exist yet, stored in
private/server.privkey .
The signed announcement dictionary puts the server FURL in a key named
"anonymous-storage-FURL", which anticipates upcoming Accounting-related
changes in the server advertisements. It also provides a key named
"permutation-seed-base32" to tell clients what permutation seed to use. This
is computed at startup, using tubid if there are existing shares, otherwise
the pubkey, to retain share-order compatibility for existing servers.
2011-11-20 10:21:32 +00:00
|
|
|
def test_duplicate_receive_v2(self):
|
|
|
|
ic1 = IntroducerClient(None,
|
|
|
|
"introducer.furl", u"my_nickname",
|
2016-05-10 20:19:35 +00:00
|
|
|
"ver23", "oldest_version", {}, fakeseq,
|
2016-05-10 19:14:36 +00:00
|
|
|
FilePath(self.mktemp()))
|
new introducer: signed extensible dictionary-based messages! refs #466
This introduces new client and server halves to the Introducer (renaming the
old one with a _V1 suffix). Both have fallbacks to accomodate talking to a
different version: the publishing client switches on whether the server's
.get_version() advertises V2 support, the server switches on which
subscription method was invoked by the subscribing client.
The V2 protocol sends a three-tuple of (serialized announcement dictionary,
signature, pubkey) for each announcement. The V2 server dispatches messages
to subscribers according to the service-name, and throws errors for invalid
signatures, but does not otherwise examine the messages. The V2 receiver's
subscription callback will receive a (serverid, ann_dict) pair. The
'serverid' will be equal to the pubkey if all of the following are true:
the originating client is V2, and was told a privkey to use
the announcement went through a V2 server
the signature is valid
If not, 'serverid' will be equal to the tubid portion of the announced FURL,
as was the case for V1 receivers.
Servers will create a keypair if one does not exist yet, stored in
private/server.privkey .
The signed announcement dictionary puts the server FURL in a key named
"anonymous-storage-FURL", which anticipates upcoming Accounting-related
changes in the server advertisements. It also provides a key named
"permutation-seed-base32" to tell clients what permutation seed to use. This
is computed at startup, using tubid if there are existing shares, otherwise
the pubkey, to retain share-order compatibility for existing servers.
2011-11-20 10:21:32 +00:00
|
|
|
# we use a second client just to create a different-looking
|
|
|
|
# announcement
|
|
|
|
ic2 = IntroducerClient(None,
|
|
|
|
"introducer.furl", u"my_nickname",
|
2016-05-10 20:19:35 +00:00
|
|
|
"ver24","oldest_version",{}, fakeseq,
|
2016-05-10 19:14:36 +00:00
|
|
|
FilePath(self.mktemp()))
|
new introducer: signed extensible dictionary-based messages! refs #466
This introduces new client and server halves to the Introducer (renaming the
old one with a _V1 suffix). Both have fallbacks to accomodate talking to a
different version: the publishing client switches on whether the server's
.get_version() advertises V2 support, the server switches on which
subscription method was invoked by the subscribing client.
The V2 protocol sends a three-tuple of (serialized announcement dictionary,
signature, pubkey) for each announcement. The V2 server dispatches messages
to subscribers according to the service-name, and throws errors for invalid
signatures, but does not otherwise examine the messages. The V2 receiver's
subscription callback will receive a (serverid, ann_dict) pair. The
'serverid' will be equal to the pubkey if all of the following are true:
the originating client is V2, and was told a privkey to use
the announcement went through a V2 server
the signature is valid
If not, 'serverid' will be equal to the tubid portion of the announced FURL,
as was the case for V1 receivers.
Servers will create a keypair if one does not exist yet, stored in
private/server.privkey .
The signed announcement dictionary puts the server FURL in a key named
"anonymous-storage-FURL", which anticipates upcoming Accounting-related
changes in the server advertisements. It also provides a key named
"permutation-seed-base32" to tell clients what permutation seed to use. This
is computed at startup, using tubid if there are existing shares, otherwise
the pubkey, to retain share-order compatibility for existing servers.
2011-11-20 10:21:32 +00:00
|
|
|
announcements = []
|
|
|
|
def _received(key_s, ann):
|
|
|
|
announcements.append( (key_s, ann) )
|
|
|
|
ic1.subscribe_to("storage", _received)
|
|
|
|
furl1 = "pb://62ubehyunnyhzs7r6vdonnm2hpi52w6y@127.0.0.1:36106/gydnp"
|
|
|
|
furl1a = "pb://62ubehyunnyhzs7r6vdonnm2hpi52w6y@127.0.0.1:7777/gydnp"
|
|
|
|
furl2 = "pb://ttwwooyunnyhzs7r6vdonnm2hpi52w6y@127.0.0.1:36106/ttwwoo"
|
|
|
|
|
|
|
|
privkey_s, pubkey_vs = keyutil.make_keypair()
|
|
|
|
privkey, _ignored = keyutil.parse_privkey(privkey_s)
|
|
|
|
pubkey_s = keyutil.remove_prefix(pubkey_vs, "pub-")
|
|
|
|
|
|
|
|
# ann1: ic1, furl1
|
|
|
|
# ann1a: ic1, furl1a (same SturdyRef, different connection hints)
|
|
|
|
# ann1b: ic2, furl1
|
|
|
|
# ann2: ic2, furl2
|
|
|
|
|
2012-06-11 02:10:22 +00:00
|
|
|
self.ann1 = make_ann_t(ic1, furl1, privkey, seqnum=10)
|
|
|
|
self.ann1old = make_ann_t(ic1, furl1, privkey, seqnum=9)
|
|
|
|
self.ann1noseqnum = make_ann_t(ic1, furl1, privkey, seqnum=None)
|
|
|
|
self.ann1b = make_ann_t(ic2, furl1, privkey, seqnum=11)
|
|
|
|
self.ann1a = make_ann_t(ic1, furl1a, privkey, seqnum=12)
|
|
|
|
self.ann2 = make_ann_t(ic2, furl2, privkey, seqnum=13)
|
new introducer: signed extensible dictionary-based messages! refs #466
This introduces new client and server halves to the Introducer (renaming the
old one with a _V1 suffix). Both have fallbacks to accomodate talking to a
different version: the publishing client switches on whether the server's
.get_version() advertises V2 support, the server switches on which
subscription method was invoked by the subscribing client.
The V2 protocol sends a three-tuple of (serialized announcement dictionary,
signature, pubkey) for each announcement. The V2 server dispatches messages
to subscribers according to the service-name, and throws errors for invalid
signatures, but does not otherwise examine the messages. The V2 receiver's
subscription callback will receive a (serverid, ann_dict) pair. The
'serverid' will be equal to the pubkey if all of the following are true:
the originating client is V2, and was told a privkey to use
the announcement went through a V2 server
the signature is valid
If not, 'serverid' will be equal to the tubid portion of the announced FURL,
as was the case for V1 receivers.
Servers will create a keypair if one does not exist yet, stored in
private/server.privkey .
The signed announcement dictionary puts the server FURL in a key named
"anonymous-storage-FURL", which anticipates upcoming Accounting-related
changes in the server advertisements. It also provides a key named
"permutation-seed-base32" to tell clients what permutation seed to use. This
is computed at startup, using tubid if there are existing shares, otherwise
the pubkey, to retain share-order compatibility for existing servers.
2011-11-20 10:21:32 +00:00
|
|
|
|
|
|
|
ic1.remote_announce_v2([self.ann1]) # queues eventual-send
|
|
|
|
d = fireEventually()
|
|
|
|
def _then1(ign):
|
|
|
|
self.failUnlessEqual(len(announcements), 1)
|
|
|
|
key_s,ann = announcements[0]
|
|
|
|
self.failUnlessEqual(key_s, pubkey_s)
|
|
|
|
self.failUnlessEqual(ann["anonymous-storage-FURL"], furl1)
|
|
|
|
self.failUnlessEqual(ann["my-version"], "ver23")
|
|
|
|
d.addCallback(_then1)
|
|
|
|
|
|
|
|
# now send a duplicate announcement. This should not fire the
|
|
|
|
# subscriber
|
|
|
|
d.addCallback(lambda ign: ic1.remote_announce_v2([self.ann1]))
|
|
|
|
d.addCallback(fireEventually)
|
|
|
|
def _then2(ign):
|
|
|
|
self.failUnlessEqual(len(announcements), 1)
|
|
|
|
d.addCallback(_then2)
|
|
|
|
|
2012-06-11 02:10:22 +00:00
|
|
|
# an older announcement shouldn't fire the subscriber either
|
|
|
|
d.addCallback(lambda ign: ic1.remote_announce_v2([self.ann1old]))
|
|
|
|
d.addCallback(fireEventually)
|
|
|
|
def _then2a(ign):
|
|
|
|
self.failUnlessEqual(len(announcements), 1)
|
|
|
|
d.addCallback(_then2a)
|
|
|
|
|
|
|
|
# announcement with no seqnum cannot replace one with-seqnum
|
|
|
|
d.addCallback(lambda ign: ic1.remote_announce_v2([self.ann1noseqnum]))
|
|
|
|
d.addCallback(fireEventually)
|
|
|
|
def _then2b(ign):
|
|
|
|
self.failUnlessEqual(len(announcements), 1)
|
|
|
|
d.addCallback(_then2b)
|
|
|
|
|
new introducer: signed extensible dictionary-based messages! refs #466
This introduces new client and server halves to the Introducer (renaming the
old one with a _V1 suffix). Both have fallbacks to accomodate talking to a
different version: the publishing client switches on whether the server's
.get_version() advertises V2 support, the server switches on which
subscription method was invoked by the subscribing client.
The V2 protocol sends a three-tuple of (serialized announcement dictionary,
signature, pubkey) for each announcement. The V2 server dispatches messages
to subscribers according to the service-name, and throws errors for invalid
signatures, but does not otherwise examine the messages. The V2 receiver's
subscription callback will receive a (serverid, ann_dict) pair. The
'serverid' will be equal to the pubkey if all of the following are true:
the originating client is V2, and was told a privkey to use
the announcement went through a V2 server
the signature is valid
If not, 'serverid' will be equal to the tubid portion of the announced FURL,
as was the case for V1 receivers.
Servers will create a keypair if one does not exist yet, stored in
private/server.privkey .
The signed announcement dictionary puts the server FURL in a key named
"anonymous-storage-FURL", which anticipates upcoming Accounting-related
changes in the server advertisements. It also provides a key named
"permutation-seed-base32" to tell clients what permutation seed to use. This
is computed at startup, using tubid if there are existing shares, otherwise
the pubkey, to retain share-order compatibility for existing servers.
2011-11-20 10:21:32 +00:00
|
|
|
# and a replacement announcement: same FURL, new other stuff. The
|
|
|
|
# subscriber *should* be fired.
|
|
|
|
d.addCallback(lambda ign: ic1.remote_announce_v2([self.ann1b]))
|
|
|
|
d.addCallback(fireEventually)
|
|
|
|
def _then3(ign):
|
|
|
|
self.failUnlessEqual(len(announcements), 2)
|
|
|
|
key_s,ann = announcements[-1]
|
|
|
|
self.failUnlessEqual(key_s, pubkey_s)
|
|
|
|
self.failUnlessEqual(ann["anonymous-storage-FURL"], furl1)
|
|
|
|
self.failUnlessEqual(ann["my-version"], "ver24")
|
|
|
|
d.addCallback(_then3)
|
|
|
|
|
|
|
|
# and a replacement announcement with a different FURL (it uses
|
|
|
|
# different connection hints)
|
|
|
|
d.addCallback(lambda ign: ic1.remote_announce_v2([self.ann1a]))
|
|
|
|
d.addCallback(fireEventually)
|
|
|
|
def _then4(ign):
|
|
|
|
self.failUnlessEqual(len(announcements), 3)
|
|
|
|
key_s,ann = announcements[-1]
|
|
|
|
self.failUnlessEqual(key_s, pubkey_s)
|
|
|
|
self.failUnlessEqual(ann["anonymous-storage-FURL"], furl1a)
|
|
|
|
self.failUnlessEqual(ann["my-version"], "ver23")
|
|
|
|
d.addCallback(_then4)
|
|
|
|
|
|
|
|
# now add a new subscription, which should be called with the
|
|
|
|
# backlog. The introducer only records one announcement per index, so
|
|
|
|
# the backlog will only have the latest message.
|
|
|
|
announcements2 = []
|
|
|
|
def _received2(key_s, ann):
|
|
|
|
announcements2.append( (key_s, ann) )
|
|
|
|
d.addCallback(lambda ign: ic1.subscribe_to("storage", _received2))
|
|
|
|
d.addCallback(fireEventually)
|
|
|
|
def _then5(ign):
|
|
|
|
self.failUnlessEqual(len(announcements2), 1)
|
|
|
|
key_s,ann = announcements2[-1]
|
|
|
|
self.failUnlessEqual(key_s, pubkey_s)
|
|
|
|
self.failUnlessEqual(ann["anonymous-storage-FURL"], furl1a)
|
|
|
|
self.failUnlessEqual(ann["my-version"], "ver23")
|
|
|
|
d.addCallback(_then5)
|
|
|
|
return d
|
|
|
|
|
2019-03-07 20:04:53 +00:00
|
|
|
class Server(AsyncTestCase):
|
2012-06-11 02:10:22 +00:00
|
|
|
def test_duplicate(self):
|
|
|
|
i = IntroducerService()
|
|
|
|
ic1 = IntroducerClient(None,
|
|
|
|
"introducer.furl", u"my_nickname",
|
2016-05-10 20:19:35 +00:00
|
|
|
"ver23", "oldest_version", {}, realseq,
|
2016-05-10 19:14:36 +00:00
|
|
|
FilePath(self.mktemp()))
|
2012-06-11 02:10:22 +00:00
|
|
|
furl1 = "pb://62ubehyunnyhzs7r6vdonnm2hpi52w6y@127.0.0.1:36106/gydnp"
|
|
|
|
|
|
|
|
privkey_s, _ = keyutil.make_keypair()
|
|
|
|
privkey, _ = keyutil.parse_privkey(privkey_s)
|
|
|
|
|
|
|
|
ann1 = make_ann_t(ic1, furl1, privkey, seqnum=10)
|
|
|
|
ann1_old = make_ann_t(ic1, furl1, privkey, seqnum=9)
|
|
|
|
ann1_new = make_ann_t(ic1, furl1, privkey, seqnum=11)
|
|
|
|
ann1_noseqnum = make_ann_t(ic1, furl1, privkey, seqnum=None)
|
2013-03-19 00:40:56 +00:00
|
|
|
ann1_badseqnum = make_ann_t(ic1, furl1, privkey, seqnum="not an int")
|
2012-06-11 02:10:22 +00:00
|
|
|
|
|
|
|
i.remote_publish_v2(ann1, None)
|
|
|
|
all = i.get_announcements()
|
|
|
|
self.failUnlessEqual(len(all), 1)
|
|
|
|
self.failUnlessEqual(all[0].announcement["seqnum"], 10)
|
|
|
|
self.failUnlessEqual(i._debug_counts["inbound_message"], 1)
|
|
|
|
self.failUnlessEqual(i._debug_counts["inbound_duplicate"], 0)
|
|
|
|
self.failUnlessEqual(i._debug_counts["inbound_no_seqnum"], 0)
|
|
|
|
self.failUnlessEqual(i._debug_counts["inbound_old_replay"], 0)
|
|
|
|
self.failUnlessEqual(i._debug_counts["inbound_update"], 0)
|
|
|
|
|
|
|
|
i.remote_publish_v2(ann1, None)
|
|
|
|
all = i.get_announcements()
|
|
|
|
self.failUnlessEqual(len(all), 1)
|
|
|
|
self.failUnlessEqual(all[0].announcement["seqnum"], 10)
|
|
|
|
self.failUnlessEqual(i._debug_counts["inbound_message"], 2)
|
|
|
|
self.failUnlessEqual(i._debug_counts["inbound_duplicate"], 1)
|
|
|
|
self.failUnlessEqual(i._debug_counts["inbound_no_seqnum"], 0)
|
|
|
|
self.failUnlessEqual(i._debug_counts["inbound_old_replay"], 0)
|
|
|
|
self.failUnlessEqual(i._debug_counts["inbound_update"], 0)
|
|
|
|
|
|
|
|
i.remote_publish_v2(ann1_old, None)
|
|
|
|
all = i.get_announcements()
|
|
|
|
self.failUnlessEqual(len(all), 1)
|
|
|
|
self.failUnlessEqual(all[0].announcement["seqnum"], 10)
|
|
|
|
self.failUnlessEqual(i._debug_counts["inbound_message"], 3)
|
|
|
|
self.failUnlessEqual(i._debug_counts["inbound_duplicate"], 1)
|
|
|
|
self.failUnlessEqual(i._debug_counts["inbound_no_seqnum"], 0)
|
|
|
|
self.failUnlessEqual(i._debug_counts["inbound_old_replay"], 1)
|
|
|
|
self.failUnlessEqual(i._debug_counts["inbound_update"], 0)
|
|
|
|
|
|
|
|
i.remote_publish_v2(ann1_new, None)
|
|
|
|
all = i.get_announcements()
|
|
|
|
self.failUnlessEqual(len(all), 1)
|
|
|
|
self.failUnlessEqual(all[0].announcement["seqnum"], 11)
|
|
|
|
self.failUnlessEqual(i._debug_counts["inbound_message"], 4)
|
|
|
|
self.failUnlessEqual(i._debug_counts["inbound_duplicate"], 1)
|
|
|
|
self.failUnlessEqual(i._debug_counts["inbound_no_seqnum"], 0)
|
|
|
|
self.failUnlessEqual(i._debug_counts["inbound_old_replay"], 1)
|
|
|
|
self.failUnlessEqual(i._debug_counts["inbound_update"], 1)
|
|
|
|
|
|
|
|
i.remote_publish_v2(ann1_noseqnum, None)
|
|
|
|
all = i.get_announcements()
|
|
|
|
self.failUnlessEqual(len(all), 1)
|
|
|
|
self.failUnlessEqual(all[0].announcement["seqnum"], 11)
|
|
|
|
self.failUnlessEqual(i._debug_counts["inbound_message"], 5)
|
|
|
|
self.failUnlessEqual(i._debug_counts["inbound_duplicate"], 1)
|
|
|
|
self.failUnlessEqual(i._debug_counts["inbound_no_seqnum"], 1)
|
|
|
|
self.failUnlessEqual(i._debug_counts["inbound_old_replay"], 1)
|
|
|
|
self.failUnlessEqual(i._debug_counts["inbound_update"], 1)
|
|
|
|
|
2013-03-19 00:40:56 +00:00
|
|
|
i.remote_publish_v2(ann1_badseqnum, None)
|
|
|
|
all = i.get_announcements()
|
|
|
|
self.failUnlessEqual(len(all), 1)
|
|
|
|
self.failUnlessEqual(all[0].announcement["seqnum"], 11)
|
|
|
|
self.failUnlessEqual(i._debug_counts["inbound_message"], 6)
|
|
|
|
self.failUnlessEqual(i._debug_counts["inbound_duplicate"], 1)
|
|
|
|
self.failUnlessEqual(i._debug_counts["inbound_no_seqnum"], 2)
|
|
|
|
self.failUnlessEqual(i._debug_counts["inbound_old_replay"], 1)
|
|
|
|
self.failUnlessEqual(i._debug_counts["inbound_update"], 1)
|
|
|
|
|
2012-06-11 02:10:22 +00:00
|
|
|
|
2012-04-23 22:02:22 +00:00
|
|
|
NICKNAME = u"n\u00EDickname-%s" # LATIN SMALL LETTER I WITH ACUTE
|
new introducer: signed extensible dictionary-based messages! refs #466
This introduces new client and server halves to the Introducer (renaming the
old one with a _V1 suffix). Both have fallbacks to accomodate talking to a
different version: the publishing client switches on whether the server's
.get_version() advertises V2 support, the server switches on which
subscription method was invoked by the subscribing client.
The V2 protocol sends a three-tuple of (serialized announcement dictionary,
signature, pubkey) for each announcement. The V2 server dispatches messages
to subscribers according to the service-name, and throws errors for invalid
signatures, but does not otherwise examine the messages. The V2 receiver's
subscription callback will receive a (serverid, ann_dict) pair. The
'serverid' will be equal to the pubkey if all of the following are true:
the originating client is V2, and was told a privkey to use
the announcement went through a V2 server
the signature is valid
If not, 'serverid' will be equal to the tubid portion of the announced FURL,
as was the case for V1 receivers.
Servers will create a keypair if one does not exist yet, stored in
private/server.privkey .
The signed announcement dictionary puts the server FURL in a key named
"anonymous-storage-FURL", which anticipates upcoming Accounting-related
changes in the server advertisements. It also provides a key named
"permutation-seed-base32" to tell clients what permutation seed to use. This
is computed at startup, using tubid if there are existing shares, otherwise
the pubkey, to retain share-order compatibility for existing servers.
2011-11-20 10:21:32 +00:00
|
|
|
|
2018-05-23 14:45:15 +00:00
|
|
|
def foolscapEndpointForPortNumber(portnum):
|
2018-05-23 14:59:42 +00:00
|
|
|
"""
|
|
|
|
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.
|
|
|
|
"""
|
2018-05-23 14:45:15 +00:00
|
|
|
if portnum is None:
|
2018-06-08 17:13:26 +00:00
|
|
|
# Bury this reactor import here to minimize the chances of it having
|
|
|
|
# the effect of installing the default reactor.
|
2018-05-23 14:45:15 +00:00
|
|
|
from twisted.internet import reactor
|
2018-06-08 17:15:19 +00:00
|
|
|
if fcntl is not None and IReactorSocket.providedBy(reactor):
|
2018-05-23 14:59:42 +00:00
|
|
|
# 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.
|
2018-05-23 14:45:15 +00:00
|
|
|
s = socket()
|
2018-05-23 14:50:54 +00:00
|
|
|
try:
|
|
|
|
s.bind(('', 0))
|
|
|
|
portnum = s.getsockname()[1]
|
2018-05-23 14:56:26 +00:00
|
|
|
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)
|
2018-05-23 14:50:54 +00:00
|
|
|
return (
|
|
|
|
portnum,
|
2018-05-23 14:56:26 +00:00
|
|
|
AdoptedStreamServerEndpoint(reactor, fd, AF_INET),
|
2018-05-23 14:50:54 +00:00
|
|
|
)
|
|
|
|
finally:
|
|
|
|
s.close()
|
2018-05-23 14:45:15 +00:00
|
|
|
else:
|
2018-05-23 14:59:42 +00:00
|
|
|
# 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
|
2018-05-23 14:45:15 +00:00
|
|
|
portnum = iputil.allocate_tcp_port()
|
|
|
|
return (portnum, "tcp:%d" % (portnum,))
|
|
|
|
|
2018-06-08 15:21:25 +00:00
|
|
|
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
|
2018-05-23 14:45:15 +00:00
|
|
|
|
2008-10-29 04:15:48 +00:00
|
|
|
class SystemTestMixin(ServiceMixin, pollmixin.PollMixin):
|
2008-04-23 22:05:39 +00:00
|
|
|
|
2016-04-28 05:33:38 +00:00
|
|
|
def create_tub(self, portnum=None):
|
2009-06-23 02:10:47 +00:00
|
|
|
tubfile = os.path.join(self.basedir, "tub.pem")
|
|
|
|
self.central_tub = tub = Tub(certFile=tubfile)
|
2007-03-27 23:12:11 +00:00
|
|
|
#tub.setOption("logLocalFailures", True)
|
|
|
|
#tub.setOption("logRemoteFailures", True)
|
2009-05-22 00:46:32 +00:00
|
|
|
tub.setOption("expose-remote-exception-types", False)
|
2007-03-27 23:12:11 +00:00
|
|
|
tub.setServiceParent(self.parent)
|
2018-06-08 15:21:25 +00:00
|
|
|
self.central_portnum = listenOnUnused(tub, portnum)
|
2007-03-27 23:12:11 +00:00
|
|
|
|
2019-03-07 20:04:53 +00:00
|
|
|
class Queue(SystemTestMixin, AsyncTestCase):
|
new introducer: signed extensible dictionary-based messages! refs #466
This introduces new client and server halves to the Introducer (renaming the
old one with a _V1 suffix). Both have fallbacks to accomodate talking to a
different version: the publishing client switches on whether the server's
.get_version() advertises V2 support, the server switches on which
subscription method was invoked by the subscribing client.
The V2 protocol sends a three-tuple of (serialized announcement dictionary,
signature, pubkey) for each announcement. The V2 server dispatches messages
to subscribers according to the service-name, and throws errors for invalid
signatures, but does not otherwise examine the messages. The V2 receiver's
subscription callback will receive a (serverid, ann_dict) pair. The
'serverid' will be equal to the pubkey if all of the following are true:
the originating client is V2, and was told a privkey to use
the announcement went through a V2 server
the signature is valid
If not, 'serverid' will be equal to the tubid portion of the announced FURL,
as was the case for V1 receivers.
Servers will create a keypair if one does not exist yet, stored in
private/server.privkey .
The signed announcement dictionary puts the server FURL in a key named
"anonymous-storage-FURL", which anticipates upcoming Accounting-related
changes in the server advertisements. It also provides a key named
"permutation-seed-base32" to tell clients what permutation seed to use. This
is computed at startup, using tubid if there are existing shares, otherwise
the pubkey, to retain share-order compatibility for existing servers.
2011-11-20 10:21:32 +00:00
|
|
|
def test_queue_until_connected(self):
|
|
|
|
self.basedir = "introducer/QueueUntilConnected/queued"
|
2009-06-23 02:10:47 +00:00
|
|
|
os.makedirs(self.basedir)
|
new introducer: signed extensible dictionary-based messages! refs #466
This introduces new client and server halves to the Introducer (renaming the
old one with a _V1 suffix). Both have fallbacks to accomodate talking to a
different version: the publishing client switches on whether the server's
.get_version() advertises V2 support, the server switches on which
subscription method was invoked by the subscribing client.
The V2 protocol sends a three-tuple of (serialized announcement dictionary,
signature, pubkey) for each announcement. The V2 server dispatches messages
to subscribers according to the service-name, and throws errors for invalid
signatures, but does not otherwise examine the messages. The V2 receiver's
subscription callback will receive a (serverid, ann_dict) pair. The
'serverid' will be equal to the pubkey if all of the following are true:
the originating client is V2, and was told a privkey to use
the announcement went through a V2 server
the signature is valid
If not, 'serverid' will be equal to the tubid portion of the announced FURL,
as was the case for V1 receivers.
Servers will create a keypair if one does not exist yet, stored in
private/server.privkey .
The signed announcement dictionary puts the server FURL in a key named
"anonymous-storage-FURL", which anticipates upcoming Accounting-related
changes in the server advertisements. It also provides a key named
"permutation-seed-base32" to tell clients what permutation seed to use. This
is computed at startup, using tubid if there are existing shares, otherwise
the pubkey, to retain share-order compatibility for existing servers.
2011-11-20 10:21:32 +00:00
|
|
|
self.create_tub()
|
|
|
|
introducer = IntroducerService()
|
|
|
|
introducer.setServiceParent(self.parent)
|
|
|
|
iff = os.path.join(self.basedir, "introducer.furl")
|
|
|
|
ifurl = self.central_tub.registerReference(introducer, furlFile=iff)
|
|
|
|
tub2 = Tub()
|
|
|
|
tub2.setServiceParent(self.parent)
|
|
|
|
c = IntroducerClient(tub2, ifurl,
|
2016-05-10 20:19:35 +00:00
|
|
|
u"nickname", "version", "oldest", {}, fakeseq,
|
2016-05-10 19:14:36 +00:00
|
|
|
FilePath(self.mktemp()))
|
new introducer: signed extensible dictionary-based messages! refs #466
This introduces new client and server halves to the Introducer (renaming the
old one with a _V1 suffix). Both have fallbacks to accomodate talking to a
different version: the publishing client switches on whether the server's
.get_version() advertises V2 support, the server switches on which
subscription method was invoked by the subscribing client.
The V2 protocol sends a three-tuple of (serialized announcement dictionary,
signature, pubkey) for each announcement. The V2 server dispatches messages
to subscribers according to the service-name, and throws errors for invalid
signatures, but does not otherwise examine the messages. The V2 receiver's
subscription callback will receive a (serverid, ann_dict) pair. The
'serverid' will be equal to the pubkey if all of the following are true:
the originating client is V2, and was told a privkey to use
the announcement went through a V2 server
the signature is valid
If not, 'serverid' will be equal to the tubid portion of the announced FURL,
as was the case for V1 receivers.
Servers will create a keypair if one does not exist yet, stored in
private/server.privkey .
The signed announcement dictionary puts the server FURL in a key named
"anonymous-storage-FURL", which anticipates upcoming Accounting-related
changes in the server advertisements. It also provides a key named
"permutation-seed-base32" to tell clients what permutation seed to use. This
is computed at startup, using tubid if there are existing shares, otherwise
the pubkey, to retain share-order compatibility for existing servers.
2011-11-20 10:21:32 +00:00
|
|
|
furl1 = "pb://onug64tu@127.0.0.1:123/short" # base32("short")
|
|
|
|
sk_s, vk_s = keyutil.make_keypair()
|
|
|
|
sk, _ignored = keyutil.parse_privkey(sk_s)
|
|
|
|
|
|
|
|
d = introducer.disownServiceParent()
|
|
|
|
def _offline(ign):
|
|
|
|
# now that the introducer server is offline, create a client and
|
|
|
|
# publish some messages
|
|
|
|
c.setServiceParent(self.parent) # this starts the reconnector
|
|
|
|
c.publish("storage", make_ann(furl1), sk)
|
|
|
|
|
|
|
|
introducer.setServiceParent(self.parent) # restart the server
|
|
|
|
# now wait for the messages to be delivered
|
|
|
|
def _got_announcement():
|
|
|
|
return bool(introducer.get_announcements())
|
|
|
|
return self.poll(_got_announcement)
|
|
|
|
d.addCallback(_offline)
|
|
|
|
def _done(ign):
|
2012-04-23 22:02:22 +00:00
|
|
|
v = introducer.get_announcements()[0]
|
|
|
|
furl = v.announcement["anonymous-storage-FURL"]
|
|
|
|
self.failUnlessEqual(furl, furl1)
|
new introducer: signed extensible dictionary-based messages! refs #466
This introduces new client and server halves to the Introducer (renaming the
old one with a _V1 suffix). Both have fallbacks to accomodate talking to a
different version: the publishing client switches on whether the server's
.get_version() advertises V2 support, the server switches on which
subscription method was invoked by the subscribing client.
The V2 protocol sends a three-tuple of (serialized announcement dictionary,
signature, pubkey) for each announcement. The V2 server dispatches messages
to subscribers according to the service-name, and throws errors for invalid
signatures, but does not otherwise examine the messages. The V2 receiver's
subscription callback will receive a (serverid, ann_dict) pair. The
'serverid' will be equal to the pubkey if all of the following are true:
the originating client is V2, and was told a privkey to use
the announcement went through a V2 server
the signature is valid
If not, 'serverid' will be equal to the tubid portion of the announced FURL,
as was the case for V1 receivers.
Servers will create a keypair if one does not exist yet, stored in
private/server.privkey .
The signed announcement dictionary puts the server FURL in a key named
"anonymous-storage-FURL", which anticipates upcoming Accounting-related
changes in the server advertisements. It also provides a key named
"permutation-seed-base32" to tell clients what permutation seed to use. This
is computed at startup, using tubid if there are existing shares, otherwise
the pubkey, to retain share-order compatibility for existing servers.
2011-11-20 10:21:32 +00:00
|
|
|
d.addCallback(_done)
|
|
|
|
|
|
|
|
# now let the ack get back
|
|
|
|
def _wait_until_idle(ign):
|
|
|
|
def _idle():
|
|
|
|
if c._debug_outstanding:
|
|
|
|
return False
|
|
|
|
if introducer._debug_outstanding:
|
|
|
|
return False
|
|
|
|
return True
|
|
|
|
return self.poll(_idle)
|
|
|
|
d.addCallback(_wait_until_idle)
|
|
|
|
return d
|
2008-06-18 23:58:34 +00:00
|
|
|
|
new introducer: signed extensible dictionary-based messages! refs #466
This introduces new client and server halves to the Introducer (renaming the
old one with a _V1 suffix). Both have fallbacks to accomodate talking to a
different version: the publishing client switches on whether the server's
.get_version() advertises V2 support, the server switches on which
subscription method was invoked by the subscribing client.
The V2 protocol sends a three-tuple of (serialized announcement dictionary,
signature, pubkey) for each announcement. The V2 server dispatches messages
to subscribers according to the service-name, and throws errors for invalid
signatures, but does not otherwise examine the messages. The V2 receiver's
subscription callback will receive a (serverid, ann_dict) pair. The
'serverid' will be equal to the pubkey if all of the following are true:
the originating client is V2, and was told a privkey to use
the announcement went through a V2 server
the signature is valid
If not, 'serverid' will be equal to the tubid portion of the announced FURL,
as was the case for V1 receivers.
Servers will create a keypair if one does not exist yet, stored in
private/server.privkey .
The signed announcement dictionary puts the server FURL in a key named
"anonymous-storage-FURL", which anticipates upcoming Accounting-related
changes in the server advertisements. It also provides a key named
"permutation-seed-base32" to tell clients what permutation seed to use. This
is computed at startup, using tubid if there are existing shares, otherwise
the pubkey, to retain share-order compatibility for existing servers.
2011-11-20 10:21:32 +00:00
|
|
|
|
2019-03-07 20:04:53 +00:00
|
|
|
class SystemTest(SystemTestMixin, AsyncTestCase):
|
new introducer: signed extensible dictionary-based messages! refs #466
This introduces new client and server halves to the Introducer (renaming the
old one with a _V1 suffix). Both have fallbacks to accomodate talking to a
different version: the publishing client switches on whether the server's
.get_version() advertises V2 support, the server switches on which
subscription method was invoked by the subscribing client.
The V2 protocol sends a three-tuple of (serialized announcement dictionary,
signature, pubkey) for each announcement. The V2 server dispatches messages
to subscribers according to the service-name, and throws errors for invalid
signatures, but does not otherwise examine the messages. The V2 receiver's
subscription callback will receive a (serverid, ann_dict) pair. The
'serverid' will be equal to the pubkey if all of the following are true:
the originating client is V2, and was told a privkey to use
the announcement went through a V2 server
the signature is valid
If not, 'serverid' will be equal to the tubid portion of the announced FURL,
as was the case for V1 receivers.
Servers will create a keypair if one does not exist yet, stored in
private/server.privkey .
The signed announcement dictionary puts the server FURL in a key named
"anonymous-storage-FURL", which anticipates upcoming Accounting-related
changes in the server advertisements. It also provides a key named
"permutation-seed-base32" to tell clients what permutation seed to use. This
is computed at startup, using tubid if there are existing shares, otherwise
the pubkey, to retain share-order compatibility for existing servers.
2011-11-20 10:21:32 +00:00
|
|
|
|
2016-06-02 16:47:58 +00:00
|
|
|
def do_system_test(self):
|
2009-06-23 02:10:47 +00:00
|
|
|
self.create_tub()
|
2016-06-02 16:47:58 +00:00
|
|
|
introducer = IntroducerService()
|
2009-06-23 02:10:47 +00:00
|
|
|
introducer.setServiceParent(self.parent)
|
|
|
|
iff = os.path.join(self.basedir, "introducer.furl")
|
|
|
|
tub = self.central_tub
|
|
|
|
ifurl = self.central_tub.registerReference(introducer, furlFile=iff)
|
|
|
|
self.introducer_furl = ifurl
|
2008-06-18 23:58:34 +00:00
|
|
|
|
new introducer: signed extensible dictionary-based messages! refs #466
This introduces new client and server halves to the Introducer (renaming the
old one with a _V1 suffix). Both have fallbacks to accomodate talking to a
different version: the publishing client switches on whether the server's
.get_version() advertises V2 support, the server switches on which
subscription method was invoked by the subscribing client.
The V2 protocol sends a three-tuple of (serialized announcement dictionary,
signature, pubkey) for each announcement. The V2 server dispatches messages
to subscribers according to the service-name, and throws errors for invalid
signatures, but does not otherwise examine the messages. The V2 receiver's
subscription callback will receive a (serverid, ann_dict) pair. The
'serverid' will be equal to the pubkey if all of the following are true:
the originating client is V2, and was told a privkey to use
the announcement went through a V2 server
the signature is valid
If not, 'serverid' will be equal to the tubid portion of the announced FURL,
as was the case for V1 receivers.
Servers will create a keypair if one does not exist yet, stored in
private/server.privkey .
The signed announcement dictionary puts the server FURL in a key named
"anonymous-storage-FURL", which anticipates upcoming Accounting-related
changes in the server advertisements. It also provides a key named
"permutation-seed-base32" to tell clients what permutation seed to use. This
is computed at startup, using tubid if there are existing shares, otherwise
the pubkey, to retain share-order compatibility for existing servers.
2011-11-20 10:21:32 +00:00
|
|
|
# we have 5 clients who publish themselves as storage servers, and a
|
|
|
|
# sixth which does which not. All 6 clients subscriber to hear about
|
|
|
|
# storage. When the connections are fully established, all six nodes
|
2008-02-02 02:48:38 +00:00
|
|
|
# should have 5 connections each.
|
new introducer: signed extensible dictionary-based messages! refs #466
This introduces new client and server halves to the Introducer (renaming the
old one with a _V1 suffix). Both have fallbacks to accomodate talking to a
different version: the publishing client switches on whether the server's
.get_version() advertises V2 support, the server switches on which
subscription method was invoked by the subscribing client.
The V2 protocol sends a three-tuple of (serialized announcement dictionary,
signature, pubkey) for each announcement. The V2 server dispatches messages
to subscribers according to the service-name, and throws errors for invalid
signatures, but does not otherwise examine the messages. The V2 receiver's
subscription callback will receive a (serverid, ann_dict) pair. The
'serverid' will be equal to the pubkey if all of the following are true:
the originating client is V2, and was told a privkey to use
the announcement went through a V2 server
the signature is valid
If not, 'serverid' will be equal to the tubid portion of the announced FURL,
as was the case for V1 receivers.
Servers will create a keypair if one does not exist yet, stored in
private/server.privkey .
The signed announcement dictionary puts the server FURL in a key named
"anonymous-storage-FURL", which anticipates upcoming Accounting-related
changes in the server advertisements. It also provides a key named
"permutation-seed-base32" to tell clients what permutation seed to use. This
is computed at startup, using tubid if there are existing shares, otherwise
the pubkey, to retain share-order compatibility for existing servers.
2011-11-20 10:21:32 +00:00
|
|
|
NUM_STORAGE = 5
|
|
|
|
NUM_CLIENTS = 6
|
2007-03-27 23:12:11 +00:00
|
|
|
|
|
|
|
clients = []
|
|
|
|
tubs = {}
|
2009-06-23 02:10:47 +00:00
|
|
|
received_announcements = {}
|
|
|
|
subscribing_clients = []
|
|
|
|
publishing_clients = []
|
2012-04-24 05:37:28 +00:00
|
|
|
printable_serverids = {}
|
test_introducer.SystemTest: fix race condition
SystemTest has a couple of different phases, separated by a poller which
waits for everything to be idle (all messages delivered, none in flight). It
does this by watching some internal "_debug_outstanding" counters in the
server and in each client, and waiting for them to hit zero.
Just before the last phase, we replace the server with a new one (to make
sure clients re-send their messages properly). Unfortunately, the polling
function closed over the variable holding the original server, and didn't see
the replacement. It kept polling the old server, and failed to notice the
outstanding messages for the new server. The last phase of the test (check3)
was started too early, which failed (since some messages had not yet been
delivered), and then exploded in a flurry of dirty-reactor errors (because
some messages were delivered after test shutdown).
This replaces the closed-over-variable with a "self.the_introducer", which
seems to fix the race.
One additional place to look at in the future: the client
announcement-receive path (remote_announce) uses an eventually(). If the
message has been received and the eventual-send posted (but not yet executed)
when the poller sees it, the poller might erroneously conclude that the
client is idle and cause the same problem as above. To fix this, the poller
(probably all pollers) could be enhanced to do a flushEventualQueue before
querying the are-we-done-yet predicate function.
2012-03-31 00:29:06 +00:00
|
|
|
self.the_introducer = introducer
|
new introducer: signed extensible dictionary-based messages! refs #466
This introduces new client and server halves to the Introducer (renaming the
old one with a _V1 suffix). Both have fallbacks to accomodate talking to a
different version: the publishing client switches on whether the server's
.get_version() advertises V2 support, the server switches on which
subscription method was invoked by the subscribing client.
The V2 protocol sends a three-tuple of (serialized announcement dictionary,
signature, pubkey) for each announcement. The V2 server dispatches messages
to subscribers according to the service-name, and throws errors for invalid
signatures, but does not otherwise examine the messages. The V2 receiver's
subscription callback will receive a (serverid, ann_dict) pair. The
'serverid' will be equal to the pubkey if all of the following are true:
the originating client is V2, and was told a privkey to use
the announcement went through a V2 server
the signature is valid
If not, 'serverid' will be equal to the tubid portion of the announced FURL,
as was the case for V1 receivers.
Servers will create a keypair if one does not exist yet, stored in
private/server.privkey .
The signed announcement dictionary puts the server FURL in a key named
"anonymous-storage-FURL", which anticipates upcoming Accounting-related
changes in the server advertisements. It also provides a key named
"permutation-seed-base32" to tell clients what permutation seed to use. This
is computed at startup, using tubid if there are existing shares, otherwise
the pubkey, to retain share-order compatibility for existing servers.
2011-11-20 10:21:32 +00:00
|
|
|
privkeys = {}
|
2016-05-11 01:33:56 +00:00
|
|
|
pubkeys = {}
|
new introducer: signed extensible dictionary-based messages! refs #466
This introduces new client and server halves to the Introducer (renaming the
old one with a _V1 suffix). Both have fallbacks to accomodate talking to a
different version: the publishing client switches on whether the server's
.get_version() advertises V2 support, the server switches on which
subscription method was invoked by the subscribing client.
The V2 protocol sends a three-tuple of (serialized announcement dictionary,
signature, pubkey) for each announcement. The V2 server dispatches messages
to subscribers according to the service-name, and throws errors for invalid
signatures, but does not otherwise examine the messages. The V2 receiver's
subscription callback will receive a (serverid, ann_dict) pair. The
'serverid' will be equal to the pubkey if all of the following are true:
the originating client is V2, and was told a privkey to use
the announcement went through a V2 server
the signature is valid
If not, 'serverid' will be equal to the tubid portion of the announced FURL,
as was the case for V1 receivers.
Servers will create a keypair if one does not exist yet, stored in
private/server.privkey .
The signed announcement dictionary puts the server FURL in a key named
"anonymous-storage-FURL", which anticipates upcoming Accounting-related
changes in the server advertisements. It also provides a key named
"permutation-seed-base32" to tell clients what permutation seed to use. This
is computed at startup, using tubid if there are existing shares, otherwise
the pubkey, to retain share-order compatibility for existing servers.
2011-11-20 10:21:32 +00:00
|
|
|
expected_announcements = [0 for c in range(NUM_CLIENTS)]
|
2009-06-23 02:10:47 +00:00
|
|
|
|
new introducer: signed extensible dictionary-based messages! refs #466
This introduces new client and server halves to the Introducer (renaming the
old one with a _V1 suffix). Both have fallbacks to accomodate talking to a
different version: the publishing client switches on whether the server's
.get_version() advertises V2 support, the server switches on which
subscription method was invoked by the subscribing client.
The V2 protocol sends a three-tuple of (serialized announcement dictionary,
signature, pubkey) for each announcement. The V2 server dispatches messages
to subscribers according to the service-name, and throws errors for invalid
signatures, but does not otherwise examine the messages. The V2 receiver's
subscription callback will receive a (serverid, ann_dict) pair. The
'serverid' will be equal to the pubkey if all of the following are true:
the originating client is V2, and was told a privkey to use
the announcement went through a V2 server
the signature is valid
If not, 'serverid' will be equal to the tubid portion of the announced FURL,
as was the case for V1 receivers.
Servers will create a keypair if one does not exist yet, stored in
private/server.privkey .
The signed announcement dictionary puts the server FURL in a key named
"anonymous-storage-FURL", which anticipates upcoming Accounting-related
changes in the server advertisements. It also provides a key named
"permutation-seed-base32" to tell clients what permutation seed to use. This
is computed at startup, using tubid if there are existing shares, otherwise
the pubkey, to retain share-order compatibility for existing servers.
2011-11-20 10:21:32 +00:00
|
|
|
for i in range(NUM_CLIENTS):
|
2007-03-27 23:12:11 +00:00
|
|
|
tub = Tub()
|
|
|
|
#tub.setOption("logLocalFailures", True)
|
|
|
|
#tub.setOption("logRemoteFailures", True)
|
2009-05-22 00:46:32 +00:00
|
|
|
tub.setOption("expose-remote-exception-types", False)
|
2007-03-27 23:12:11 +00:00
|
|
|
tub.setServiceParent(self.parent)
|
2018-06-08 15:21:25 +00:00
|
|
|
listenOnUnused(tub)
|
2008-02-02 02:48:38 +00:00
|
|
|
log.msg("creating client %d: %s" % (i, tub.getShortTubID()))
|
2016-06-02 16:47:58 +00:00
|
|
|
c = IntroducerClient(tub, self.introducer_furl,
|
|
|
|
NICKNAME % str(i),
|
|
|
|
"version", "oldest",
|
|
|
|
{"component": "component-v1"}, fakeseq,
|
|
|
|
FilePath(self.mktemp()))
|
2010-01-14 22:15:29 +00:00
|
|
|
received_announcements[c] = {}
|
2016-06-30 05:58:14 +00:00
|
|
|
def got(key_s_or_tubid, ann, announcements):
|
|
|
|
index = key_s_or_tubid or get_tubid_string_from_ann(ann)
|
new introducer: signed extensible dictionary-based messages! refs #466
This introduces new client and server halves to the Introducer (renaming the
old one with a _V1 suffix). Both have fallbacks to accomodate talking to a
different version: the publishing client switches on whether the server's
.get_version() advertises V2 support, the server switches on which
subscription method was invoked by the subscribing client.
The V2 protocol sends a three-tuple of (serialized announcement dictionary,
signature, pubkey) for each announcement. The V2 server dispatches messages
to subscribers according to the service-name, and throws errors for invalid
signatures, but does not otherwise examine the messages. The V2 receiver's
subscription callback will receive a (serverid, ann_dict) pair. The
'serverid' will be equal to the pubkey if all of the following are true:
the originating client is V2, and was told a privkey to use
the announcement went through a V2 server
the signature is valid
If not, 'serverid' will be equal to the tubid portion of the announced FURL,
as was the case for V1 receivers.
Servers will create a keypair if one does not exist yet, stored in
private/server.privkey .
The signed announcement dictionary puts the server FURL in a key named
"anonymous-storage-FURL", which anticipates upcoming Accounting-related
changes in the server advertisements. It also provides a key named
"permutation-seed-base32" to tell clients what permutation seed to use. This
is computed at startup, using tubid if there are existing shares, otherwise
the pubkey, to retain share-order compatibility for existing servers.
2011-11-20 10:21:32 +00:00
|
|
|
announcements[index] = ann
|
2016-06-30 05:58:14 +00:00
|
|
|
c.subscribe_to("storage", got, received_announcements[c])
|
2009-06-23 02:10:47 +00:00
|
|
|
subscribing_clients.append(c)
|
new introducer: signed extensible dictionary-based messages! refs #466
This introduces new client and server halves to the Introducer (renaming the
old one with a _V1 suffix). Both have fallbacks to accomodate talking to a
different version: the publishing client switches on whether the server's
.get_version() advertises V2 support, the server switches on which
subscription method was invoked by the subscribing client.
The V2 protocol sends a three-tuple of (serialized announcement dictionary,
signature, pubkey) for each announcement. The V2 server dispatches messages
to subscribers according to the service-name, and throws errors for invalid
signatures, but does not otherwise examine the messages. The V2 receiver's
subscription callback will receive a (serverid, ann_dict) pair. The
'serverid' will be equal to the pubkey if all of the following are true:
the originating client is V2, and was told a privkey to use
the announcement went through a V2 server
the signature is valid
If not, 'serverid' will be equal to the tubid portion of the announced FURL,
as was the case for V1 receivers.
Servers will create a keypair if one does not exist yet, stored in
private/server.privkey .
The signed announcement dictionary puts the server FURL in a key named
"anonymous-storage-FURL", which anticipates upcoming Accounting-related
changes in the server advertisements. It also provides a key named
"permutation-seed-base32" to tell clients what permutation seed to use. This
is computed at startup, using tubid if there are existing shares, otherwise
the pubkey, to retain share-order compatibility for existing servers.
2011-11-20 10:21:32 +00:00
|
|
|
expected_announcements[i] += 1 # all expect a 'storage' announcement
|
|
|
|
|
|
|
|
node_furl = tub.registerReference(Referenceable())
|
2016-05-11 01:33:56 +00:00
|
|
|
privkey_s, pubkey_s = keyutil.make_keypair()
|
|
|
|
privkey, _ignored = keyutil.parse_privkey(privkey_s)
|
|
|
|
privkeys[i] = privkey
|
|
|
|
pubkeys[i] = pubkey_s
|
|
|
|
|
new introducer: signed extensible dictionary-based messages! refs #466
This introduces new client and server halves to the Introducer (renaming the
old one with a _V1 suffix). Both have fallbacks to accomodate talking to a
different version: the publishing client switches on whether the server's
.get_version() advertises V2 support, the server switches on which
subscription method was invoked by the subscribing client.
The V2 protocol sends a three-tuple of (serialized announcement dictionary,
signature, pubkey) for each announcement. The V2 server dispatches messages
to subscribers according to the service-name, and throws errors for invalid
signatures, but does not otherwise examine the messages. The V2 receiver's
subscription callback will receive a (serverid, ann_dict) pair. The
'serverid' will be equal to the pubkey if all of the following are true:
the originating client is V2, and was told a privkey to use
the announcement went through a V2 server
the signature is valid
If not, 'serverid' will be equal to the tubid portion of the announced FURL,
as was the case for V1 receivers.
Servers will create a keypair if one does not exist yet, stored in
private/server.privkey .
The signed announcement dictionary puts the server FURL in a key named
"anonymous-storage-FURL", which anticipates upcoming Accounting-related
changes in the server advertisements. It also provides a key named
"permutation-seed-base32" to tell clients what permutation seed to use. This
is computed at startup, using tubid if there are existing shares, otherwise
the pubkey, to retain share-order compatibility for existing servers.
2011-11-20 10:21:32 +00:00
|
|
|
if i < NUM_STORAGE:
|
2016-05-11 01:33:56 +00:00
|
|
|
# sign all announcements
|
|
|
|
c.publish("storage", make_ann(node_furl), privkey)
|
|
|
|
assert pubkey_s.startswith("pub-")
|
|
|
|
printable_serverids[i] = pubkey_s[len("pub-"):]
|
2009-06-23 02:10:47 +00:00
|
|
|
publishing_clients.append(c)
|
new introducer: signed extensible dictionary-based messages! refs #466
This introduces new client and server halves to the Introducer (renaming the
old one with a _V1 suffix). Both have fallbacks to accomodate talking to a
different version: the publishing client switches on whether the server's
.get_version() advertises V2 support, the server switches on which
subscription method was invoked by the subscribing client.
The V2 protocol sends a three-tuple of (serialized announcement dictionary,
signature, pubkey) for each announcement. The V2 server dispatches messages
to subscribers according to the service-name, and throws errors for invalid
signatures, but does not otherwise examine the messages. The V2 receiver's
subscription callback will receive a (serverid, ann_dict) pair. The
'serverid' will be equal to the pubkey if all of the following are true:
the originating client is V2, and was told a privkey to use
the announcement went through a V2 server
the signature is valid
If not, 'serverid' will be equal to the tubid portion of the announced FURL,
as was the case for V1 receivers.
Servers will create a keypair if one does not exist yet, stored in
private/server.privkey .
The signed announcement dictionary puts the server FURL in a key named
"anonymous-storage-FURL", which anticipates upcoming Accounting-related
changes in the server advertisements. It also provides a key named
"permutation-seed-base32" to tell clients what permutation seed to use. This
is computed at startup, using tubid if there are existing shares, otherwise
the pubkey, to retain share-order compatibility for existing servers.
2011-11-20 10:21:32 +00:00
|
|
|
else:
|
|
|
|
# the last one does not publish anything
|
|
|
|
pass
|
|
|
|
|
|
|
|
if i == 2:
|
|
|
|
# also publish something that nobody cares about
|
|
|
|
boring_furl = tub.registerReference(Referenceable())
|
2016-05-11 01:33:56 +00:00
|
|
|
c.publish("boring", make_ann(boring_furl), privkey)
|
2008-02-05 20:05:13 +00:00
|
|
|
|
2007-03-27 23:12:11 +00:00
|
|
|
c.setServiceParent(self.parent)
|
|
|
|
clients.append(c)
|
|
|
|
tubs[c] = tub
|
|
|
|
|
new introducer: signed extensible dictionary-based messages! refs #466
This introduces new client and server halves to the Introducer (renaming the
old one with a _V1 suffix). Both have fallbacks to accomodate talking to a
different version: the publishing client switches on whether the server's
.get_version() advertises V2 support, the server switches on which
subscription method was invoked by the subscribing client.
The V2 protocol sends a three-tuple of (serialized announcement dictionary,
signature, pubkey) for each announcement. The V2 server dispatches messages
to subscribers according to the service-name, and throws errors for invalid
signatures, but does not otherwise examine the messages. The V2 receiver's
subscription callback will receive a (serverid, ann_dict) pair. The
'serverid' will be equal to the pubkey if all of the following are true:
the originating client is V2, and was told a privkey to use
the announcement went through a V2 server
the signature is valid
If not, 'serverid' will be equal to the tubid portion of the announced FURL,
as was the case for V1 receivers.
Servers will create a keypair if one does not exist yet, stored in
private/server.privkey .
The signed announcement dictionary puts the server FURL in a key named
"anonymous-storage-FURL", which anticipates upcoming Accounting-related
changes in the server advertisements. It also provides a key named
"permutation-seed-base32" to tell clients what permutation seed to use. This
is computed at startup, using tubid if there are existing shares, otherwise
the pubkey, to retain share-order compatibility for existing servers.
2011-11-20 10:21:32 +00:00
|
|
|
|
|
|
|
def _wait_for_connected(ign):
|
|
|
|
def _connected():
|
|
|
|
for c in clients:
|
|
|
|
if not c.connected_to_introducer():
|
|
|
|
return False
|
|
|
|
return True
|
|
|
|
return self.poll(_connected)
|
|
|
|
|
|
|
|
# we watch the clients to determine when the system has settled down.
|
|
|
|
# Then we can look inside the server to assert things about its
|
|
|
|
# state.
|
|
|
|
|
|
|
|
def _wait_for_expected_announcements(ign):
|
|
|
|
def _got_expected_announcements():
|
|
|
|
for i,c in enumerate(subscribing_clients):
|
|
|
|
if len(received_announcements[c]) < expected_announcements[i]:
|
|
|
|
return False
|
|
|
|
return True
|
|
|
|
return self.poll(_got_expected_announcements)
|
|
|
|
|
|
|
|
# before shutting down any Tub, we'd like to know that there are no
|
|
|
|
# messages outstanding
|
|
|
|
|
|
|
|
def _wait_until_idle(ign):
|
|
|
|
def _idle():
|
|
|
|
for c in subscribing_clients + publishing_clients:
|
|
|
|
if c._debug_outstanding:
|
|
|
|
return False
|
test_introducer.SystemTest: fix race condition
SystemTest has a couple of different phases, separated by a poller which
waits for everything to be idle (all messages delivered, none in flight). It
does this by watching some internal "_debug_outstanding" counters in the
server and in each client, and waiting for them to hit zero.
Just before the last phase, we replace the server with a new one (to make
sure clients re-send their messages properly). Unfortunately, the polling
function closed over the variable holding the original server, and didn't see
the replacement. It kept polling the old server, and failed to notice the
outstanding messages for the new server. The last phase of the test (check3)
was started too early, which failed (since some messages had not yet been
delivered), and then exploded in a flurry of dirty-reactor errors (because
some messages were delivered after test shutdown).
This replaces the closed-over-variable with a "self.the_introducer", which
seems to fix the race.
One additional place to look at in the future: the client
announcement-receive path (remote_announce) uses an eventually(). If the
message has been received and the eventual-send posted (but not yet executed)
when the poller sees it, the poller might erroneously conclude that the
client is idle and cause the same problem as above. To fix this, the poller
(probably all pollers) could be enhanced to do a flushEventualQueue before
querying the are-we-done-yet predicate function.
2012-03-31 00:29:06 +00:00
|
|
|
if self.the_introducer._debug_outstanding:
|
2008-02-05 20:05:13 +00:00
|
|
|
return False
|
new introducer: signed extensible dictionary-based messages! refs #466
This introduces new client and server halves to the Introducer (renaming the
old one with a _V1 suffix). Both have fallbacks to accomodate talking to a
different version: the publishing client switches on whether the server's
.get_version() advertises V2 support, the server switches on which
subscription method was invoked by the subscribing client.
The V2 protocol sends a three-tuple of (serialized announcement dictionary,
signature, pubkey) for each announcement. The V2 server dispatches messages
to subscribers according to the service-name, and throws errors for invalid
signatures, but does not otherwise examine the messages. The V2 receiver's
subscription callback will receive a (serverid, ann_dict) pair. The
'serverid' will be equal to the pubkey if all of the following are true:
the originating client is V2, and was told a privkey to use
the announcement went through a V2 server
the signature is valid
If not, 'serverid' will be equal to the tubid portion of the announced FURL,
as was the case for V1 receivers.
Servers will create a keypair if one does not exist yet, stored in
private/server.privkey .
The signed announcement dictionary puts the server FURL in a key named
"anonymous-storage-FURL", which anticipates upcoming Accounting-related
changes in the server advertisements. It also provides a key named
"permutation-seed-base32" to tell clients what permutation seed to use. This
is computed at startup, using tubid if there are existing shares, otherwise
the pubkey, to retain share-order compatibility for existing servers.
2011-11-20 10:21:32 +00:00
|
|
|
return True
|
|
|
|
return self.poll(_idle)
|
|
|
|
|
|
|
|
d = defer.succeed(None)
|
|
|
|
d.addCallback(_wait_for_connected)
|
|
|
|
d.addCallback(_wait_for_expected_announcements)
|
|
|
|
d.addCallback(_wait_until_idle)
|
2007-03-27 23:12:11 +00:00
|
|
|
|
2007-09-19 18:50:13 +00:00
|
|
|
def _check1(res):
|
|
|
|
log.msg("doing _check1")
|
test_introducer.SystemTest: fix race condition
SystemTest has a couple of different phases, separated by a poller which
waits for everything to be idle (all messages delivered, none in flight). It
does this by watching some internal "_debug_outstanding" counters in the
server and in each client, and waiting for them to hit zero.
Just before the last phase, we replace the server with a new one (to make
sure clients re-send their messages properly). Unfortunately, the polling
function closed over the variable holding the original server, and didn't see
the replacement. It kept polling the old server, and failed to notice the
outstanding messages for the new server. The last phase of the test (check3)
was started too early, which failed (since some messages had not yet been
delivered), and then exploded in a flurry of dirty-reactor errors (because
some messages were delivered after test shutdown).
This replaces the closed-over-variable with a "self.the_introducer", which
seems to fix the race.
One additional place to look at in the future: the client
announcement-receive path (remote_announce) uses an eventually(). If the
message has been received and the eventual-send posted (but not yet executed)
when the poller sees it, the poller might erroneously conclude that the
client is idle and cause the same problem as above. To fix this, the poller
(probably all pollers) could be enhanced to do a flushEventualQueue before
querying the are-we-done-yet predicate function.
2012-03-31 00:29:06 +00:00
|
|
|
dc = self.the_introducer._debug_counts
|
2016-06-02 16:47:58 +00:00
|
|
|
# each storage server publishes a record. There is also one
|
2016-06-30 05:58:14 +00:00
|
|
|
# "boring"
|
|
|
|
self.failUnlessEqual(dc["inbound_message"], NUM_STORAGE+1)
|
2016-06-02 16:47:58 +00:00
|
|
|
self.failUnlessEqual(dc["inbound_duplicate"], 0)
|
2009-06-23 02:10:47 +00:00
|
|
|
self.failUnlessEqual(dc["inbound_update"], 0)
|
new introducer: signed extensible dictionary-based messages! refs #466
This introduces new client and server halves to the Introducer (renaming the
old one with a _V1 suffix). Both have fallbacks to accomodate talking to a
different version: the publishing client switches on whether the server's
.get_version() advertises V2 support, the server switches on which
subscription method was invoked by the subscribing client.
The V2 protocol sends a three-tuple of (serialized announcement dictionary,
signature, pubkey) for each announcement. The V2 server dispatches messages
to subscribers according to the service-name, and throws errors for invalid
signatures, but does not otherwise examine the messages. The V2 receiver's
subscription callback will receive a (serverid, ann_dict) pair. The
'serverid' will be equal to the pubkey if all of the following are true:
the originating client is V2, and was told a privkey to use
the announcement went through a V2 server
the signature is valid
If not, 'serverid' will be equal to the tubid portion of the announced FURL,
as was the case for V1 receivers.
Servers will create a keypair if one does not exist yet, stored in
private/server.privkey .
The signed announcement dictionary puts the server FURL in a key named
"anonymous-storage-FURL", which anticipates upcoming Accounting-related
changes in the server advertisements. It also provides a key named
"permutation-seed-base32" to tell clients what permutation seed to use. This
is computed at startup, using tubid if there are existing shares, otherwise
the pubkey, to retain share-order compatibility for existing servers.
2011-11-20 10:21:32 +00:00
|
|
|
self.failUnlessEqual(dc["inbound_subscribe"], NUM_CLIENTS)
|
|
|
|
# the number of outbound messages is tricky.. I think it depends
|
|
|
|
# upon a race between the publish and the subscribe messages.
|
|
|
|
self.failUnless(dc["outbound_message"] > 0)
|
|
|
|
# each client subscribes to "storage", and each server publishes
|
|
|
|
self.failUnlessEqual(dc["outbound_announcements"],
|
2016-06-30 05:58:14 +00:00
|
|
|
NUM_STORAGE*NUM_CLIENTS)
|
2009-06-23 02:10:47 +00:00
|
|
|
|
|
|
|
for c in subscribing_clients:
|
|
|
|
cdc = c._debug_counts
|
|
|
|
self.failUnless(cdc["inbound_message"])
|
|
|
|
self.failUnlessEqual(cdc["inbound_announcement"],
|
2016-06-30 05:58:14 +00:00
|
|
|
NUM_STORAGE)
|
2009-06-23 02:10:47 +00:00
|
|
|
self.failUnlessEqual(cdc["wrong_service"], 0)
|
|
|
|
self.failUnlessEqual(cdc["duplicate_announcement"], 0)
|
|
|
|
self.failUnlessEqual(cdc["update"], 0)
|
|
|
|
self.failUnlessEqual(cdc["new_announcement"],
|
2016-06-30 05:58:14 +00:00
|
|
|
NUM_STORAGE)
|
2009-06-23 02:10:47 +00:00
|
|
|
anns = received_announcements[c]
|
2016-06-30 05:58:14 +00:00
|
|
|
self.failUnlessEqual(len(anns), NUM_STORAGE)
|
|
|
|
|
2016-05-11 01:33:56 +00:00
|
|
|
serverid0 = printable_serverids[0]
|
|
|
|
ann = anns[serverid0]
|
2016-06-30 05:58:14 +00:00
|
|
|
nick = ann["nickname"]
|
|
|
|
self.failUnlessEqual(type(nick), unicode)
|
|
|
|
self.failUnlessEqual(nick, NICKNAME % "0")
|
|
|
|
for c in publishing_clients:
|
|
|
|
cdc = c._debug_counts
|
|
|
|
expected = 1
|
|
|
|
if c in [clients[2], # boring
|
|
|
|
]:
|
|
|
|
expected = 2
|
|
|
|
self.failUnlessEqual(cdc["outbound_message"], expected)
|
2012-04-23 22:02:22 +00:00
|
|
|
# now check the web status, make sure it renders without error
|
|
|
|
ir = introweb.IntroducerRoot(self.parent)
|
|
|
|
self.parent.nodeid = "NODEID"
|
|
|
|
text = ir.renderSynchronously().decode("utf-8")
|
2019-03-07 23:56:37 +00:00
|
|
|
self.assertIn(NICKNAME % "0", text) # a v2 client
|
|
|
|
self.assertIn(NICKNAME % "1", text) # another v2 client
|
2016-06-30 05:58:14 +00:00
|
|
|
for i in range(NUM_STORAGE):
|
2019-03-07 23:56:37 +00:00
|
|
|
self.assertIn(printable_serverids[i], text,
|
2016-06-30 05:58:14 +00:00
|
|
|
(i,printable_serverids[i],text))
|
2012-04-24 05:37:28 +00:00
|
|
|
# make sure there isn't a double-base32ed string too
|
2019-03-07 23:56:37 +00:00
|
|
|
self.assertNotIn(idlib.nodeid_b2a(printable_serverids[i]), text,
|
2012-04-24 05:37:28 +00:00
|
|
|
(i,printable_serverids[i],text))
|
new introducer: signed extensible dictionary-based messages! refs #466
This introduces new client and server halves to the Introducer (renaming the
old one with a _V1 suffix). Both have fallbacks to accomodate talking to a
different version: the publishing client switches on whether the server's
.get_version() advertises V2 support, the server switches on which
subscription method was invoked by the subscribing client.
The V2 protocol sends a three-tuple of (serialized announcement dictionary,
signature, pubkey) for each announcement. The V2 server dispatches messages
to subscribers according to the service-name, and throws errors for invalid
signatures, but does not otherwise examine the messages. The V2 receiver's
subscription callback will receive a (serverid, ann_dict) pair. The
'serverid' will be equal to the pubkey if all of the following are true:
the originating client is V2, and was told a privkey to use
the announcement went through a V2 server
the signature is valid
If not, 'serverid' will be equal to the tubid portion of the announced FURL,
as was the case for V1 receivers.
Servers will create a keypair if one does not exist yet, stored in
private/server.privkey .
The signed announcement dictionary puts the server FURL in a key named
"anonymous-storage-FURL", which anticipates upcoming Accounting-related
changes in the server advertisements. It also provides a key named
"permutation-seed-base32" to tell clients what permutation seed to use. This
is computed at startup, using tubid if there are existing shares, otherwise
the pubkey, to retain share-order compatibility for existing servers.
2011-11-20 10:21:32 +00:00
|
|
|
log.msg("_check1 done")
|
2007-09-19 18:50:13 +00:00
|
|
|
d.addCallback(_check1)
|
2008-02-05 20:05:13 +00:00
|
|
|
|
2009-06-23 02:10:47 +00:00
|
|
|
# force an introducer reconnect, by shutting down the Tub it's using
|
|
|
|
# and starting a new Tub (with the old introducer). Everybody should
|
|
|
|
# reconnect and republish, but the introducer should ignore the
|
|
|
|
# republishes as duplicates. However, because the server doesn't know
|
|
|
|
# what each client does and does not know, it will send them a copy
|
|
|
|
# of the current announcement table anyway.
|
|
|
|
|
|
|
|
d.addCallback(lambda _ign: log.msg("shutting down introducer's Tub"))
|
|
|
|
d.addCallback(lambda _ign: self.central_tub.disownServiceParent())
|
|
|
|
|
new introducer: signed extensible dictionary-based messages! refs #466
This introduces new client and server halves to the Introducer (renaming the
old one with a _V1 suffix). Both have fallbacks to accomodate talking to a
different version: the publishing client switches on whether the server's
.get_version() advertises V2 support, the server switches on which
subscription method was invoked by the subscribing client.
The V2 protocol sends a three-tuple of (serialized announcement dictionary,
signature, pubkey) for each announcement. The V2 server dispatches messages
to subscribers according to the service-name, and throws errors for invalid
signatures, but does not otherwise examine the messages. The V2 receiver's
subscription callback will receive a (serverid, ann_dict) pair. The
'serverid' will be equal to the pubkey if all of the following are true:
the originating client is V2, and was told a privkey to use
the announcement went through a V2 server
the signature is valid
If not, 'serverid' will be equal to the tubid portion of the announced FURL,
as was the case for V1 receivers.
Servers will create a keypair if one does not exist yet, stored in
private/server.privkey .
The signed announcement dictionary puts the server FURL in a key named
"anonymous-storage-FURL", which anticipates upcoming Accounting-related
changes in the server advertisements. It also provides a key named
"permutation-seed-base32" to tell clients what permutation seed to use. This
is computed at startup, using tubid if there are existing shares, otherwise
the pubkey, to retain share-order compatibility for existing servers.
2011-11-20 10:21:32 +00:00
|
|
|
def _wait_for_introducer_loss(ign):
|
|
|
|
def _introducer_lost():
|
|
|
|
for c in clients:
|
|
|
|
if c.connected_to_introducer():
|
|
|
|
return False
|
|
|
|
return True
|
|
|
|
return self.poll(_introducer_lost)
|
|
|
|
d.addCallback(_wait_for_introducer_loss)
|
2009-06-23 02:10:47 +00:00
|
|
|
|
|
|
|
def _restart_introducer_tub(_ign):
|
|
|
|
log.msg("restarting introducer's Tub")
|
new introducer: signed extensible dictionary-based messages! refs #466
This introduces new client and server halves to the Introducer (renaming the
old one with a _V1 suffix). Both have fallbacks to accomodate talking to a
different version: the publishing client switches on whether the server's
.get_version() advertises V2 support, the server switches on which
subscription method was invoked by the subscribing client.
The V2 protocol sends a three-tuple of (serialized announcement dictionary,
signature, pubkey) for each announcement. The V2 server dispatches messages
to subscribers according to the service-name, and throws errors for invalid
signatures, but does not otherwise examine the messages. The V2 receiver's
subscription callback will receive a (serverid, ann_dict) pair. The
'serverid' will be equal to the pubkey if all of the following are true:
the originating client is V2, and was told a privkey to use
the announcement went through a V2 server
the signature is valid
If not, 'serverid' will be equal to the tubid portion of the announced FURL,
as was the case for V1 receivers.
Servers will create a keypair if one does not exist yet, stored in
private/server.privkey .
The signed announcement dictionary puts the server FURL in a key named
"anonymous-storage-FURL", which anticipates upcoming Accounting-related
changes in the server advertisements. It also provides a key named
"permutation-seed-base32" to tell clients what permutation seed to use. This
is computed at startup, using tubid if there are existing shares, otherwise
the pubkey, to retain share-order compatibility for existing servers.
2011-11-20 10:21:32 +00:00
|
|
|
# reset counters
|
|
|
|
for i in range(NUM_CLIENTS):
|
|
|
|
c = subscribing_clients[i]
|
|
|
|
for k in c._debug_counts:
|
|
|
|
c._debug_counts[k] = 0
|
test_introducer.SystemTest: fix race condition
SystemTest has a couple of different phases, separated by a poller which
waits for everything to be idle (all messages delivered, none in flight). It
does this by watching some internal "_debug_outstanding" counters in the
server and in each client, and waiting for them to hit zero.
Just before the last phase, we replace the server with a new one (to make
sure clients re-send their messages properly). Unfortunately, the polling
function closed over the variable holding the original server, and didn't see
the replacement. It kept polling the old server, and failed to notice the
outstanding messages for the new server. The last phase of the test (check3)
was started too early, which failed (since some messages had not yet been
delivered), and then exploded in a flurry of dirty-reactor errors (because
some messages were delivered after test shutdown).
This replaces the closed-over-variable with a "self.the_introducer", which
seems to fix the race.
One additional place to look at in the future: the client
announcement-receive path (remote_announce) uses an eventually(). If the
message has been received and the eventual-send posted (but not yet executed)
when the poller sees it, the poller might erroneously conclude that the
client is idle and cause the same problem as above. To fix this, the poller
(probably all pollers) could be enhanced to do a flushEventualQueue before
querying the are-we-done-yet predicate function.
2012-03-31 00:29:06 +00:00
|
|
|
for k in self.the_introducer._debug_counts:
|
|
|
|
self.the_introducer._debug_counts[k] = 0
|
new introducer: signed extensible dictionary-based messages! refs #466
This introduces new client and server halves to the Introducer (renaming the
old one with a _V1 suffix). Both have fallbacks to accomodate talking to a
different version: the publishing client switches on whether the server's
.get_version() advertises V2 support, the server switches on which
subscription method was invoked by the subscribing client.
The V2 protocol sends a three-tuple of (serialized announcement dictionary,
signature, pubkey) for each announcement. The V2 server dispatches messages
to subscribers according to the service-name, and throws errors for invalid
signatures, but does not otherwise examine the messages. The V2 receiver's
subscription callback will receive a (serverid, ann_dict) pair. The
'serverid' will be equal to the pubkey if all of the following are true:
the originating client is V2, and was told a privkey to use
the announcement went through a V2 server
the signature is valid
If not, 'serverid' will be equal to the tubid portion of the announced FURL,
as was the case for V1 receivers.
Servers will create a keypair if one does not exist yet, stored in
private/server.privkey .
The signed announcement dictionary puts the server FURL in a key named
"anonymous-storage-FURL", which anticipates upcoming Accounting-related
changes in the server advertisements. It also provides a key named
"permutation-seed-base32" to tell clients what permutation seed to use. This
is computed at startup, using tubid if there are existing shares, otherwise
the pubkey, to retain share-order compatibility for existing servers.
2011-11-20 10:21:32 +00:00
|
|
|
expected_announcements[i] += 1 # new 'storage' for everyone
|
2009-06-23 02:10:47 +00:00
|
|
|
self.create_tub(self.central_portnum)
|
test_introducer.SystemTest: fix race condition
SystemTest has a couple of different phases, separated by a poller which
waits for everything to be idle (all messages delivered, none in flight). It
does this by watching some internal "_debug_outstanding" counters in the
server and in each client, and waiting for them to hit zero.
Just before the last phase, we replace the server with a new one (to make
sure clients re-send their messages properly). Unfortunately, the polling
function closed over the variable holding the original server, and didn't see
the replacement. It kept polling the old server, and failed to notice the
outstanding messages for the new server. The last phase of the test (check3)
was started too early, which failed (since some messages had not yet been
delivered), and then exploded in a flurry of dirty-reactor errors (because
some messages were delivered after test shutdown).
This replaces the closed-over-variable with a "self.the_introducer", which
seems to fix the race.
One additional place to look at in the future: the client
announcement-receive path (remote_announce) uses an eventually(). If the
message has been received and the eventual-send posted (but not yet executed)
when the poller sees it, the poller might erroneously conclude that the
client is idle and cause the same problem as above. To fix this, the poller
(probably all pollers) could be enhanced to do a flushEventualQueue before
querying the are-we-done-yet predicate function.
2012-03-31 00:29:06 +00:00
|
|
|
newfurl = self.central_tub.registerReference(self.the_introducer,
|
2009-06-23 02:10:47 +00:00
|
|
|
furlFile=iff)
|
|
|
|
assert newfurl == self.introducer_furl
|
|
|
|
d.addCallback(_restart_introducer_tub)
|
|
|
|
|
new introducer: signed extensible dictionary-based messages! refs #466
This introduces new client and server halves to the Introducer (renaming the
old one with a _V1 suffix). Both have fallbacks to accomodate talking to a
different version: the publishing client switches on whether the server's
.get_version() advertises V2 support, the server switches on which
subscription method was invoked by the subscribing client.
The V2 protocol sends a three-tuple of (serialized announcement dictionary,
signature, pubkey) for each announcement. The V2 server dispatches messages
to subscribers according to the service-name, and throws errors for invalid
signatures, but does not otherwise examine the messages. The V2 receiver's
subscription callback will receive a (serverid, ann_dict) pair. The
'serverid' will be equal to the pubkey if all of the following are true:
the originating client is V2, and was told a privkey to use
the announcement went through a V2 server
the signature is valid
If not, 'serverid' will be equal to the tubid portion of the announced FURL,
as was the case for V1 receivers.
Servers will create a keypair if one does not exist yet, stored in
private/server.privkey .
The signed announcement dictionary puts the server FURL in a key named
"anonymous-storage-FURL", which anticipates upcoming Accounting-related
changes in the server advertisements. It also provides a key named
"permutation-seed-base32" to tell clients what permutation seed to use. This
is computed at startup, using tubid if there are existing shares, otherwise
the pubkey, to retain share-order compatibility for existing servers.
2011-11-20 10:21:32 +00:00
|
|
|
d.addCallback(_wait_for_connected)
|
|
|
|
d.addCallback(_wait_for_expected_announcements)
|
|
|
|
d.addCallback(_wait_until_idle)
|
|
|
|
d.addCallback(lambda _ign: log.msg(" reconnected"))
|
2009-06-23 02:10:47 +00:00
|
|
|
|
new introducer: signed extensible dictionary-based messages! refs #466
This introduces new client and server halves to the Introducer (renaming the
old one with a _V1 suffix). Both have fallbacks to accomodate talking to a
different version: the publishing client switches on whether the server's
.get_version() advertises V2 support, the server switches on which
subscription method was invoked by the subscribing client.
The V2 protocol sends a three-tuple of (serialized announcement dictionary,
signature, pubkey) for each announcement. The V2 server dispatches messages
to subscribers according to the service-name, and throws errors for invalid
signatures, but does not otherwise examine the messages. The V2 receiver's
subscription callback will receive a (serverid, ann_dict) pair. The
'serverid' will be equal to the pubkey if all of the following are true:
the originating client is V2, and was told a privkey to use
the announcement went through a V2 server
the signature is valid
If not, 'serverid' will be equal to the tubid portion of the announced FURL,
as was the case for V1 receivers.
Servers will create a keypair if one does not exist yet, stored in
private/server.privkey .
The signed announcement dictionary puts the server FURL in a key named
"anonymous-storage-FURL", which anticipates upcoming Accounting-related
changes in the server advertisements. It also provides a key named
"permutation-seed-base32" to tell clients what permutation seed to use. This
is computed at startup, using tubid if there are existing shares, otherwise
the pubkey, to retain share-order compatibility for existing servers.
2011-11-20 10:21:32 +00:00
|
|
|
# TODO: publish something while the introducer is offline, then
|
|
|
|
# confirm it gets delivered when the connection is reestablished
|
2007-09-19 18:50:13 +00:00
|
|
|
def _check2(res):
|
|
|
|
log.msg("doing _check2")
|
2009-06-23 02:10:47 +00:00
|
|
|
# assert that the introducer sent out new messages, one per
|
|
|
|
# subscriber
|
test_introducer.SystemTest: fix race condition
SystemTest has a couple of different phases, separated by a poller which
waits for everything to be idle (all messages delivered, none in flight). It
does this by watching some internal "_debug_outstanding" counters in the
server and in each client, and waiting for them to hit zero.
Just before the last phase, we replace the server with a new one (to make
sure clients re-send their messages properly). Unfortunately, the polling
function closed over the variable holding the original server, and didn't see
the replacement. It kept polling the old server, and failed to notice the
outstanding messages for the new server. The last phase of the test (check3)
was started too early, which failed (since some messages had not yet been
delivered), and then exploded in a flurry of dirty-reactor errors (because
some messages were delivered after test shutdown).
This replaces the closed-over-variable with a "self.the_introducer", which
seems to fix the race.
One additional place to look at in the future: the client
announcement-receive path (remote_announce) uses an eventually(). If the
message has been received and the eventual-send posted (but not yet executed)
when the poller sees it, the poller might erroneously conclude that the
client is idle and cause the same problem as above. To fix this, the poller
(probably all pollers) could be enhanced to do a flushEventualQueue before
querying the are-we-done-yet predicate function.
2012-03-31 00:29:06 +00:00
|
|
|
dc = self.the_introducer._debug_counts
|
new introducer: signed extensible dictionary-based messages! refs #466
This introduces new client and server halves to the Introducer (renaming the
old one with a _V1 suffix). Both have fallbacks to accomodate talking to a
different version: the publishing client switches on whether the server's
.get_version() advertises V2 support, the server switches on which
subscription method was invoked by the subscribing client.
The V2 protocol sends a three-tuple of (serialized announcement dictionary,
signature, pubkey) for each announcement. The V2 server dispatches messages
to subscribers according to the service-name, and throws errors for invalid
signatures, but does not otherwise examine the messages. The V2 receiver's
subscription callback will receive a (serverid, ann_dict) pair. The
'serverid' will be equal to the pubkey if all of the following are true:
the originating client is V2, and was told a privkey to use
the announcement went through a V2 server
the signature is valid
If not, 'serverid' will be equal to the tubid portion of the announced FURL,
as was the case for V1 receivers.
Servers will create a keypair if one does not exist yet, stored in
private/server.privkey .
The signed announcement dictionary puts the server FURL in a key named
"anonymous-storage-FURL", which anticipates upcoming Accounting-related
changes in the server advertisements. It also provides a key named
"permutation-seed-base32" to tell clients what permutation seed to use. This
is computed at startup, using tubid if there are existing shares, otherwise
the pubkey, to retain share-order compatibility for existing servers.
2011-11-20 10:21:32 +00:00
|
|
|
self.failUnlessEqual(dc["outbound_announcements"],
|
2016-06-30 05:58:14 +00:00
|
|
|
NUM_STORAGE*NUM_CLIENTS)
|
new introducer: signed extensible dictionary-based messages! refs #466
This introduces new client and server halves to the Introducer (renaming the
old one with a _V1 suffix). Both have fallbacks to accomodate talking to a
different version: the publishing client switches on whether the server's
.get_version() advertises V2 support, the server switches on which
subscription method was invoked by the subscribing client.
The V2 protocol sends a three-tuple of (serialized announcement dictionary,
signature, pubkey) for each announcement. The V2 server dispatches messages
to subscribers according to the service-name, and throws errors for invalid
signatures, but does not otherwise examine the messages. The V2 receiver's
subscription callback will receive a (serverid, ann_dict) pair. The
'serverid' will be equal to the pubkey if all of the following are true:
the originating client is V2, and was told a privkey to use
the announcement went through a V2 server
the signature is valid
If not, 'serverid' will be equal to the tubid portion of the announced FURL,
as was the case for V1 receivers.
Servers will create a keypair if one does not exist yet, stored in
private/server.privkey .
The signed announcement dictionary puts the server FURL in a key named
"anonymous-storage-FURL", which anticipates upcoming Accounting-related
changes in the server advertisements. It also provides a key named
"permutation-seed-base32" to tell clients what permutation seed to use. This
is computed at startup, using tubid if there are existing shares, otherwise
the pubkey, to retain share-order compatibility for existing servers.
2011-11-20 10:21:32 +00:00
|
|
|
self.failUnless(dc["outbound_message"] > 0)
|
|
|
|
self.failUnlessEqual(dc["inbound_subscribe"], NUM_CLIENTS)
|
2009-06-23 02:10:47 +00:00
|
|
|
for c in subscribing_clients:
|
|
|
|
cdc = c._debug_counts
|
new introducer: signed extensible dictionary-based messages! refs #466
This introduces new client and server halves to the Introducer (renaming the
old one with a _V1 suffix). Both have fallbacks to accomodate talking to a
different version: the publishing client switches on whether the server's
.get_version() advertises V2 support, the server switches on which
subscription method was invoked by the subscribing client.
The V2 protocol sends a three-tuple of (serialized announcement dictionary,
signature, pubkey) for each announcement. The V2 server dispatches messages
to subscribers according to the service-name, and throws errors for invalid
signatures, but does not otherwise examine the messages. The V2 receiver's
subscription callback will receive a (serverid, ann_dict) pair. The
'serverid' will be equal to the pubkey if all of the following are true:
the originating client is V2, and was told a privkey to use
the announcement went through a V2 server
the signature is valid
If not, 'serverid' will be equal to the tubid portion of the announced FURL,
as was the case for V1 receivers.
Servers will create a keypair if one does not exist yet, stored in
private/server.privkey .
The signed announcement dictionary puts the server FURL in a key named
"anonymous-storage-FURL", which anticipates upcoming Accounting-related
changes in the server advertisements. It also provides a key named
"permutation-seed-base32" to tell clients what permutation seed to use. This
is computed at startup, using tubid if there are existing shares, otherwise
the pubkey, to retain share-order compatibility for existing servers.
2011-11-20 10:21:32 +00:00
|
|
|
self.failUnlessEqual(cdc["inbound_message"], 1)
|
2016-06-30 05:58:14 +00:00
|
|
|
self.failUnlessEqual(cdc["inbound_announcement"], NUM_STORAGE)
|
new introducer: signed extensible dictionary-based messages! refs #466
This introduces new client and server halves to the Introducer (renaming the
old one with a _V1 suffix). Both have fallbacks to accomodate talking to a
different version: the publishing client switches on whether the server's
.get_version() advertises V2 support, the server switches on which
subscription method was invoked by the subscribing client.
The V2 protocol sends a three-tuple of (serialized announcement dictionary,
signature, pubkey) for each announcement. The V2 server dispatches messages
to subscribers according to the service-name, and throws errors for invalid
signatures, but does not otherwise examine the messages. The V2 receiver's
subscription callback will receive a (serverid, ann_dict) pair. The
'serverid' will be equal to the pubkey if all of the following are true:
the originating client is V2, and was told a privkey to use
the announcement went through a V2 server
the signature is valid
If not, 'serverid' will be equal to the tubid portion of the announced FURL,
as was the case for V1 receivers.
Servers will create a keypair if one does not exist yet, stored in
private/server.privkey .
The signed announcement dictionary puts the server FURL in a key named
"anonymous-storage-FURL", which anticipates upcoming Accounting-related
changes in the server advertisements. It also provides a key named
"permutation-seed-base32" to tell clients what permutation seed to use. This
is computed at startup, using tubid if there are existing shares, otherwise
the pubkey, to retain share-order compatibility for existing servers.
2011-11-20 10:21:32 +00:00
|
|
|
self.failUnlessEqual(cdc["new_announcement"], 0)
|
|
|
|
self.failUnlessEqual(cdc["wrong_service"], 0)
|
2016-06-30 05:58:14 +00:00
|
|
|
self.failUnlessEqual(cdc["duplicate_announcement"], NUM_STORAGE)
|
2007-09-19 18:50:13 +00:00
|
|
|
d.addCallback(_check2)
|
2008-02-05 20:05:13 +00:00
|
|
|
|
2009-06-23 02:10:47 +00:00
|
|
|
# Then force an introducer restart, by shutting down the Tub,
|
|
|
|
# destroying the old introducer, and starting a new Tub+Introducer.
|
|
|
|
# Everybody should reconnect and republish, and the (new) introducer
|
|
|
|
# will distribute the new announcements, but the clients should
|
|
|
|
# ignore the republishes as duplicates.
|
|
|
|
|
|
|
|
d.addCallback(lambda _ign: log.msg("shutting down introducer"))
|
|
|
|
d.addCallback(lambda _ign: self.central_tub.disownServiceParent())
|
new introducer: signed extensible dictionary-based messages! refs #466
This introduces new client and server halves to the Introducer (renaming the
old one with a _V1 suffix). Both have fallbacks to accomodate talking to a
different version: the publishing client switches on whether the server's
.get_version() advertises V2 support, the server switches on which
subscription method was invoked by the subscribing client.
The V2 protocol sends a three-tuple of (serialized announcement dictionary,
signature, pubkey) for each announcement. The V2 server dispatches messages
to subscribers according to the service-name, and throws errors for invalid
signatures, but does not otherwise examine the messages. The V2 receiver's
subscription callback will receive a (serverid, ann_dict) pair. The
'serverid' will be equal to the pubkey if all of the following are true:
the originating client is V2, and was told a privkey to use
the announcement went through a V2 server
the signature is valid
If not, 'serverid' will be equal to the tubid portion of the announced FURL,
as was the case for V1 receivers.
Servers will create a keypair if one does not exist yet, stored in
private/server.privkey .
The signed announcement dictionary puts the server FURL in a key named
"anonymous-storage-FURL", which anticipates upcoming Accounting-related
changes in the server advertisements. It also provides a key named
"permutation-seed-base32" to tell clients what permutation seed to use. This
is computed at startup, using tubid if there are existing shares, otherwise
the pubkey, to retain share-order compatibility for existing servers.
2011-11-20 10:21:32 +00:00
|
|
|
d.addCallback(_wait_for_introducer_loss)
|
|
|
|
d.addCallback(lambda _ign: log.msg("introducer lost"))
|
2009-06-23 02:10:47 +00:00
|
|
|
|
|
|
|
def _restart_introducer(_ign):
|
|
|
|
log.msg("restarting introducer")
|
|
|
|
self.create_tub(self.central_portnum)
|
new introducer: signed extensible dictionary-based messages! refs #466
This introduces new client and server halves to the Introducer (renaming the
old one with a _V1 suffix). Both have fallbacks to accomodate talking to a
different version: the publishing client switches on whether the server's
.get_version() advertises V2 support, the server switches on which
subscription method was invoked by the subscribing client.
The V2 protocol sends a three-tuple of (serialized announcement dictionary,
signature, pubkey) for each announcement. The V2 server dispatches messages
to subscribers according to the service-name, and throws errors for invalid
signatures, but does not otherwise examine the messages. The V2 receiver's
subscription callback will receive a (serverid, ann_dict) pair. The
'serverid' will be equal to the pubkey if all of the following are true:
the originating client is V2, and was told a privkey to use
the announcement went through a V2 server
the signature is valid
If not, 'serverid' will be equal to the tubid portion of the announced FURL,
as was the case for V1 receivers.
Servers will create a keypair if one does not exist yet, stored in
private/server.privkey .
The signed announcement dictionary puts the server FURL in a key named
"anonymous-storage-FURL", which anticipates upcoming Accounting-related
changes in the server advertisements. It also provides a key named
"permutation-seed-base32" to tell clients what permutation seed to use. This
is computed at startup, using tubid if there are existing shares, otherwise
the pubkey, to retain share-order compatibility for existing servers.
2011-11-20 10:21:32 +00:00
|
|
|
# reset counters
|
|
|
|
for i in range(NUM_CLIENTS):
|
|
|
|
c = subscribing_clients[i]
|
|
|
|
for k in c._debug_counts:
|
|
|
|
c._debug_counts[k] = 0
|
|
|
|
expected_announcements[i] += 1 # new 'storage' for everyone
|
2016-06-02 16:47:58 +00:00
|
|
|
introducer = IntroducerService()
|
test_introducer.SystemTest: fix race condition
SystemTest has a couple of different phases, separated by a poller which
waits for everything to be idle (all messages delivered, none in flight). It
does this by watching some internal "_debug_outstanding" counters in the
server and in each client, and waiting for them to hit zero.
Just before the last phase, we replace the server with a new one (to make
sure clients re-send their messages properly). Unfortunately, the polling
function closed over the variable holding the original server, and didn't see
the replacement. It kept polling the old server, and failed to notice the
outstanding messages for the new server. The last phase of the test (check3)
was started too early, which failed (since some messages had not yet been
delivered), and then exploded in a flurry of dirty-reactor errors (because
some messages were delivered after test shutdown).
This replaces the closed-over-variable with a "self.the_introducer", which
seems to fix the race.
One additional place to look at in the future: the client
announcement-receive path (remote_announce) uses an eventually(). If the
message has been received and the eventual-send posted (but not yet executed)
when the poller sees it, the poller might erroneously conclude that the
client is idle and cause the same problem as above. To fix this, the poller
(probably all pollers) could be enhanced to do a flushEventualQueue before
querying the are-we-done-yet predicate function.
2012-03-31 00:29:06 +00:00
|
|
|
self.the_introducer = introducer
|
|
|
|
newfurl = self.central_tub.registerReference(self.the_introducer,
|
2009-06-23 02:10:47 +00:00
|
|
|
furlFile=iff)
|
|
|
|
assert newfurl == self.introducer_furl
|
|
|
|
d.addCallback(_restart_introducer)
|
new introducer: signed extensible dictionary-based messages! refs #466
This introduces new client and server halves to the Introducer (renaming the
old one with a _V1 suffix). Both have fallbacks to accomodate talking to a
different version: the publishing client switches on whether the server's
.get_version() advertises V2 support, the server switches on which
subscription method was invoked by the subscribing client.
The V2 protocol sends a three-tuple of (serialized announcement dictionary,
signature, pubkey) for each announcement. The V2 server dispatches messages
to subscribers according to the service-name, and throws errors for invalid
signatures, but does not otherwise examine the messages. The V2 receiver's
subscription callback will receive a (serverid, ann_dict) pair. The
'serverid' will be equal to the pubkey if all of the following are true:
the originating client is V2, and was told a privkey to use
the announcement went through a V2 server
the signature is valid
If not, 'serverid' will be equal to the tubid portion of the announced FURL,
as was the case for V1 receivers.
Servers will create a keypair if one does not exist yet, stored in
private/server.privkey .
The signed announcement dictionary puts the server FURL in a key named
"anonymous-storage-FURL", which anticipates upcoming Accounting-related
changes in the server advertisements. It also provides a key named
"permutation-seed-base32" to tell clients what permutation seed to use. This
is computed at startup, using tubid if there are existing shares, otherwise
the pubkey, to retain share-order compatibility for existing servers.
2011-11-20 10:21:32 +00:00
|
|
|
|
|
|
|
d.addCallback(_wait_for_connected)
|
|
|
|
d.addCallback(_wait_for_expected_announcements)
|
|
|
|
d.addCallback(_wait_until_idle)
|
2008-02-05 20:05:13 +00:00
|
|
|
|
2009-06-23 02:10:47 +00:00
|
|
|
def _check3(res):
|
|
|
|
log.msg("doing _check3")
|
test_introducer.SystemTest: fix race condition
SystemTest has a couple of different phases, separated by a poller which
waits for everything to be idle (all messages delivered, none in flight). It
does this by watching some internal "_debug_outstanding" counters in the
server and in each client, and waiting for them to hit zero.
Just before the last phase, we replace the server with a new one (to make
sure clients re-send their messages properly). Unfortunately, the polling
function closed over the variable holding the original server, and didn't see
the replacement. It kept polling the old server, and failed to notice the
outstanding messages for the new server. The last phase of the test (check3)
was started too early, which failed (since some messages had not yet been
delivered), and then exploded in a flurry of dirty-reactor errors (because
some messages were delivered after test shutdown).
This replaces the closed-over-variable with a "self.the_introducer", which
seems to fix the race.
One additional place to look at in the future: the client
announcement-receive path (remote_announce) uses an eventually(). If the
message has been received and the eventual-send posted (but not yet executed)
when the poller sees it, the poller might erroneously conclude that the
client is idle and cause the same problem as above. To fix this, the poller
(probably all pollers) could be enhanced to do a flushEventualQueue before
querying the are-we-done-yet predicate function.
2012-03-31 00:29:06 +00:00
|
|
|
dc = self.the_introducer._debug_counts
|
new introducer: signed extensible dictionary-based messages! refs #466
This introduces new client and server halves to the Introducer (renaming the
old one with a _V1 suffix). Both have fallbacks to accomodate talking to a
different version: the publishing client switches on whether the server's
.get_version() advertises V2 support, the server switches on which
subscription method was invoked by the subscribing client.
The V2 protocol sends a three-tuple of (serialized announcement dictionary,
signature, pubkey) for each announcement. The V2 server dispatches messages
to subscribers according to the service-name, and throws errors for invalid
signatures, but does not otherwise examine the messages. The V2 receiver's
subscription callback will receive a (serverid, ann_dict) pair. The
'serverid' will be equal to the pubkey if all of the following are true:
the originating client is V2, and was told a privkey to use
the announcement went through a V2 server
the signature is valid
If not, 'serverid' will be equal to the tubid portion of the announced FURL,
as was the case for V1 receivers.
Servers will create a keypair if one does not exist yet, stored in
private/server.privkey .
The signed announcement dictionary puts the server FURL in a key named
"anonymous-storage-FURL", which anticipates upcoming Accounting-related
changes in the server advertisements. It also provides a key named
"permutation-seed-base32" to tell clients what permutation seed to use. This
is computed at startup, using tubid if there are existing shares, otherwise
the pubkey, to retain share-order compatibility for existing servers.
2011-11-20 10:21:32 +00:00
|
|
|
self.failUnlessEqual(dc["outbound_announcements"],
|
2016-06-30 05:58:14 +00:00
|
|
|
NUM_STORAGE*NUM_CLIENTS)
|
new introducer: signed extensible dictionary-based messages! refs #466
This introduces new client and server halves to the Introducer (renaming the
old one with a _V1 suffix). Both have fallbacks to accomodate talking to a
different version: the publishing client switches on whether the server's
.get_version() advertises V2 support, the server switches on which
subscription method was invoked by the subscribing client.
The V2 protocol sends a three-tuple of (serialized announcement dictionary,
signature, pubkey) for each announcement. The V2 server dispatches messages
to subscribers according to the service-name, and throws errors for invalid
signatures, but does not otherwise examine the messages. The V2 receiver's
subscription callback will receive a (serverid, ann_dict) pair. The
'serverid' will be equal to the pubkey if all of the following are true:
the originating client is V2, and was told a privkey to use
the announcement went through a V2 server
the signature is valid
If not, 'serverid' will be equal to the tubid portion of the announced FURL,
as was the case for V1 receivers.
Servers will create a keypair if one does not exist yet, stored in
private/server.privkey .
The signed announcement dictionary puts the server FURL in a key named
"anonymous-storage-FURL", which anticipates upcoming Accounting-related
changes in the server advertisements. It also provides a key named
"permutation-seed-base32" to tell clients what permutation seed to use. This
is computed at startup, using tubid if there are existing shares, otherwise
the pubkey, to retain share-order compatibility for existing servers.
2011-11-20 10:21:32 +00:00
|
|
|
self.failUnless(dc["outbound_message"] > 0)
|
|
|
|
self.failUnlessEqual(dc["inbound_subscribe"], NUM_CLIENTS)
|
2009-06-23 02:10:47 +00:00
|
|
|
for c in subscribing_clients:
|
|
|
|
cdc = c._debug_counts
|
new introducer: signed extensible dictionary-based messages! refs #466
This introduces new client and server halves to the Introducer (renaming the
old one with a _V1 suffix). Both have fallbacks to accomodate talking to a
different version: the publishing client switches on whether the server's
.get_version() advertises V2 support, the server switches on which
subscription method was invoked by the subscribing client.
The V2 protocol sends a three-tuple of (serialized announcement dictionary,
signature, pubkey) for each announcement. The V2 server dispatches messages
to subscribers according to the service-name, and throws errors for invalid
signatures, but does not otherwise examine the messages. The V2 receiver's
subscription callback will receive a (serverid, ann_dict) pair. The
'serverid' will be equal to the pubkey if all of the following are true:
the originating client is V2, and was told a privkey to use
the announcement went through a V2 server
the signature is valid
If not, 'serverid' will be equal to the tubid portion of the announced FURL,
as was the case for V1 receivers.
Servers will create a keypair if one does not exist yet, stored in
private/server.privkey .
The signed announcement dictionary puts the server FURL in a key named
"anonymous-storage-FURL", which anticipates upcoming Accounting-related
changes in the server advertisements. It also provides a key named
"permutation-seed-base32" to tell clients what permutation seed to use. This
is computed at startup, using tubid if there are existing shares, otherwise
the pubkey, to retain share-order compatibility for existing servers.
2011-11-20 10:21:32 +00:00
|
|
|
self.failUnless(cdc["inbound_message"] > 0)
|
2016-06-30 05:58:14 +00:00
|
|
|
self.failUnlessEqual(cdc["inbound_announcement"], NUM_STORAGE)
|
new introducer: signed extensible dictionary-based messages! refs #466
This introduces new client and server halves to the Introducer (renaming the
old one with a _V1 suffix). Both have fallbacks to accomodate talking to a
different version: the publishing client switches on whether the server's
.get_version() advertises V2 support, the server switches on which
subscription method was invoked by the subscribing client.
The V2 protocol sends a three-tuple of (serialized announcement dictionary,
signature, pubkey) for each announcement. The V2 server dispatches messages
to subscribers according to the service-name, and throws errors for invalid
signatures, but does not otherwise examine the messages. The V2 receiver's
subscription callback will receive a (serverid, ann_dict) pair. The
'serverid' will be equal to the pubkey if all of the following are true:
the originating client is V2, and was told a privkey to use
the announcement went through a V2 server
the signature is valid
If not, 'serverid' will be equal to the tubid portion of the announced FURL,
as was the case for V1 receivers.
Servers will create a keypair if one does not exist yet, stored in
private/server.privkey .
The signed announcement dictionary puts the server FURL in a key named
"anonymous-storage-FURL", which anticipates upcoming Accounting-related
changes in the server advertisements. It also provides a key named
"permutation-seed-base32" to tell clients what permutation seed to use. This
is computed at startup, using tubid if there are existing shares, otherwise
the pubkey, to retain share-order compatibility for existing servers.
2011-11-20 10:21:32 +00:00
|
|
|
self.failUnlessEqual(cdc["new_announcement"], 0)
|
|
|
|
self.failUnlessEqual(cdc["wrong_service"], 0)
|
2016-06-30 05:58:14 +00:00
|
|
|
self.failUnlessEqual(cdc["duplicate_announcement"], NUM_STORAGE)
|
2009-06-23 02:10:47 +00:00
|
|
|
|
|
|
|
d.addCallback(_check3)
|
2007-03-27 23:12:11 +00:00
|
|
|
return d
|
2008-11-22 03:07:27 +00:00
|
|
|
|
new introducer: signed extensible dictionary-based messages! refs #466
This introduces new client and server halves to the Introducer (renaming the
old one with a _V1 suffix). Both have fallbacks to accomodate talking to a
different version: the publishing client switches on whether the server's
.get_version() advertises V2 support, the server switches on which
subscription method was invoked by the subscribing client.
The V2 protocol sends a three-tuple of (serialized announcement dictionary,
signature, pubkey) for each announcement. The V2 server dispatches messages
to subscribers according to the service-name, and throws errors for invalid
signatures, but does not otherwise examine the messages. The V2 receiver's
subscription callback will receive a (serverid, ann_dict) pair. The
'serverid' will be equal to the pubkey if all of the following are true:
the originating client is V2, and was told a privkey to use
the announcement went through a V2 server
the signature is valid
If not, 'serverid' will be equal to the tubid portion of the announced FURL,
as was the case for V1 receivers.
Servers will create a keypair if one does not exist yet, stored in
private/server.privkey .
The signed announcement dictionary puts the server FURL in a key named
"anonymous-storage-FURL", which anticipates upcoming Accounting-related
changes in the server advertisements. It also provides a key named
"permutation-seed-base32" to tell clients what permutation seed to use. This
is computed at startup, using tubid if there are existing shares, otherwise
the pubkey, to retain share-order compatibility for existing servers.
2011-11-20 10:21:32 +00:00
|
|
|
|
|
|
|
def test_system_v2_server(self):
|
|
|
|
self.basedir = "introducer/SystemTest/system_v2_server"
|
|
|
|
os.makedirs(self.basedir)
|
2016-06-02 16:47:58 +00:00
|
|
|
return self.do_system_test()
|
new introducer: signed extensible dictionary-based messages! refs #466
This introduces new client and server halves to the Introducer (renaming the
old one with a _V1 suffix). Both have fallbacks to accomodate talking to a
different version: the publishing client switches on whether the server's
.get_version() advertises V2 support, the server switches on which
subscription method was invoked by the subscribing client.
The V2 protocol sends a three-tuple of (serialized announcement dictionary,
signature, pubkey) for each announcement. The V2 server dispatches messages
to subscribers according to the service-name, and throws errors for invalid
signatures, but does not otherwise examine the messages. The V2 receiver's
subscription callback will receive a (serverid, ann_dict) pair. The
'serverid' will be equal to the pubkey if all of the following are true:
the originating client is V2, and was told a privkey to use
the announcement went through a V2 server
the signature is valid
If not, 'serverid' will be equal to the tubid portion of the announced FURL,
as was the case for V1 receivers.
Servers will create a keypair if one does not exist yet, stored in
private/server.privkey .
The signed announcement dictionary puts the server FURL in a key named
"anonymous-storage-FURL", which anticipates upcoming Accounting-related
changes in the server advertisements. It also provides a key named
"permutation-seed-base32" to tell clients what permutation seed to use. This
is computed at startup, using tubid if there are existing shares, otherwise
the pubkey, to retain share-order compatibility for existing servers.
2011-11-20 10:21:32 +00:00
|
|
|
test_system_v2_server.timeout = 480
|
|
|
|
# occasionally takes longer than 350s on "draco"
|
|
|
|
|
|
|
|
class FakeRemoteReference:
|
|
|
|
def notifyOnDisconnect(self, *args, **kwargs): pass
|
|
|
|
def getRemoteTubID(self): return "62ubehyunnyhzs7r6vdonnm2hpi52w6y"
|
2015-09-22 23:37:12 +00:00
|
|
|
def getLocationHints(self): return ["tcp:here.example.com:1234",
|
|
|
|
"tcp:there.example.com2345"]
|
2012-04-23 22:02:22 +00:00
|
|
|
def getPeer(self): return address.IPv4Address("TCP", "remote.example.com",
|
|
|
|
3456)
|
new introducer: signed extensible dictionary-based messages! refs #466
This introduces new client and server halves to the Introducer (renaming the
old one with a _V1 suffix). Both have fallbacks to accomodate talking to a
different version: the publishing client switches on whether the server's
.get_version() advertises V2 support, the server switches on which
subscription method was invoked by the subscribing client.
The V2 protocol sends a three-tuple of (serialized announcement dictionary,
signature, pubkey) for each announcement. The V2 server dispatches messages
to subscribers according to the service-name, and throws errors for invalid
signatures, but does not otherwise examine the messages. The V2 receiver's
subscription callback will receive a (serverid, ann_dict) pair. The
'serverid' will be equal to the pubkey if all of the following are true:
the originating client is V2, and was told a privkey to use
the announcement went through a V2 server
the signature is valid
If not, 'serverid' will be equal to the tubid portion of the announced FURL,
as was the case for V1 receivers.
Servers will create a keypair if one does not exist yet, stored in
private/server.privkey .
The signed announcement dictionary puts the server FURL in a key named
"anonymous-storage-FURL", which anticipates upcoming Accounting-related
changes in the server advertisements. It also provides a key named
"permutation-seed-base32" to tell clients what permutation seed to use. This
is computed at startup, using tubid if there are existing shares, otherwise
the pubkey, to retain share-order compatibility for existing servers.
2011-11-20 10:21:32 +00:00
|
|
|
|
2019-03-07 20:04:53 +00:00
|
|
|
class ClientInfo(AsyncTestCase):
|
new introducer: signed extensible dictionary-based messages! refs #466
This introduces new client and server halves to the Introducer (renaming the
old one with a _V1 suffix). Both have fallbacks to accomodate talking to a
different version: the publishing client switches on whether the server's
.get_version() advertises V2 support, the server switches on which
subscription method was invoked by the subscribing client.
The V2 protocol sends a three-tuple of (serialized announcement dictionary,
signature, pubkey) for each announcement. The V2 server dispatches messages
to subscribers according to the service-name, and throws errors for invalid
signatures, but does not otherwise examine the messages. The V2 receiver's
subscription callback will receive a (serverid, ann_dict) pair. The
'serverid' will be equal to the pubkey if all of the following are true:
the originating client is V2, and was told a privkey to use
the announcement went through a V2 server
the signature is valid
If not, 'serverid' will be equal to the tubid portion of the announced FURL,
as was the case for V1 receivers.
Servers will create a keypair if one does not exist yet, stored in
private/server.privkey .
The signed announcement dictionary puts the server FURL in a key named
"anonymous-storage-FURL", which anticipates upcoming Accounting-related
changes in the server advertisements. It also provides a key named
"permutation-seed-base32" to tell clients what permutation seed to use. This
is computed at startup, using tubid if there are existing shares, otherwise
the pubkey, to retain share-order compatibility for existing servers.
2011-11-20 10:21:32 +00:00
|
|
|
def test_client_v2(self):
|
|
|
|
introducer = IntroducerService()
|
|
|
|
tub = introducer_furl = None
|
|
|
|
app_versions = {"whizzy": "fizzy"}
|
2012-04-23 22:02:22 +00:00
|
|
|
client_v2 = IntroducerClient(tub, introducer_furl, NICKNAME % u"v2",
|
2013-03-19 00:40:56 +00:00
|
|
|
"my_version", "oldest", app_versions,
|
2016-05-10 19:14:36 +00:00
|
|
|
fakeseq, FilePath(self.mktemp()))
|
new introducer: signed extensible dictionary-based messages! refs #466
This introduces new client and server halves to the Introducer (renaming the
old one with a _V1 suffix). Both have fallbacks to accomodate talking to a
different version: the publishing client switches on whether the server's
.get_version() advertises V2 support, the server switches on which
subscription method was invoked by the subscribing client.
The V2 protocol sends a three-tuple of (serialized announcement dictionary,
signature, pubkey) for each announcement. The V2 server dispatches messages
to subscribers according to the service-name, and throws errors for invalid
signatures, but does not otherwise examine the messages. The V2 receiver's
subscription callback will receive a (serverid, ann_dict) pair. The
'serverid' will be equal to the pubkey if all of the following are true:
the originating client is V2, and was told a privkey to use
the announcement went through a V2 server
the signature is valid
If not, 'serverid' will be equal to the tubid portion of the announced FURL,
as was the case for V1 receivers.
Servers will create a keypair if one does not exist yet, stored in
private/server.privkey .
The signed announcement dictionary puts the server FURL in a key named
"anonymous-storage-FURL", which anticipates upcoming Accounting-related
changes in the server advertisements. It also provides a key named
"permutation-seed-base32" to tell clients what permutation seed to use. This
is computed at startup, using tubid if there are existing shares, otherwise
the pubkey, to retain share-order compatibility for existing servers.
2011-11-20 10:21:32 +00:00
|
|
|
#furl1 = "pb://62ubehyunnyhzs7r6vdonnm2hpi52w6y@127.0.0.1:0/swissnum"
|
2012-06-11 02:10:22 +00:00
|
|
|
#ann_s = make_ann_t(client_v2, furl1, None, 10)
|
new introducer: signed extensible dictionary-based messages! refs #466
This introduces new client and server halves to the Introducer (renaming the
old one with a _V1 suffix). Both have fallbacks to accomodate talking to a
different version: the publishing client switches on whether the server's
.get_version() advertises V2 support, the server switches on which
subscription method was invoked by the subscribing client.
The V2 protocol sends a three-tuple of (serialized announcement dictionary,
signature, pubkey) for each announcement. The V2 server dispatches messages
to subscribers according to the service-name, and throws errors for invalid
signatures, but does not otherwise examine the messages. The V2 receiver's
subscription callback will receive a (serverid, ann_dict) pair. The
'serverid' will be equal to the pubkey if all of the following are true:
the originating client is V2, and was told a privkey to use
the announcement went through a V2 server
the signature is valid
If not, 'serverid' will be equal to the tubid portion of the announced FURL,
as was the case for V1 receivers.
Servers will create a keypair if one does not exist yet, stored in
private/server.privkey .
The signed announcement dictionary puts the server FURL in a key named
"anonymous-storage-FURL", which anticipates upcoming Accounting-related
changes in the server advertisements. It also provides a key named
"permutation-seed-base32" to tell clients what permutation seed to use. This
is computed at startup, using tubid if there are existing shares, otherwise
the pubkey, to retain share-order compatibility for existing servers.
2011-11-20 10:21:32 +00:00
|
|
|
#introducer.remote_publish_v2(ann_s, Referenceable())
|
|
|
|
subscriber = FakeRemoteReference()
|
|
|
|
introducer.remote_subscribe_v2(subscriber, "storage",
|
|
|
|
client_v2._my_subscriber_info)
|
2012-04-23 22:02:22 +00:00
|
|
|
subs = introducer.get_subscribers()
|
|
|
|
self.failUnlessEqual(len(subs), 1)
|
|
|
|
s0 = subs[0]
|
|
|
|
self.failUnlessEqual(s0.service_name, "storage")
|
|
|
|
self.failUnlessEqual(s0.app_versions, app_versions)
|
|
|
|
self.failUnlessEqual(s0.nickname, NICKNAME % u"v2")
|
|
|
|
self.failUnlessEqual(s0.version, "my_version")
|
new introducer: signed extensible dictionary-based messages! refs #466
This introduces new client and server halves to the Introducer (renaming the
old one with a _V1 suffix). Both have fallbacks to accomodate talking to a
different version: the publishing client switches on whether the server's
.get_version() advertises V2 support, the server switches on which
subscription method was invoked by the subscribing client.
The V2 protocol sends a three-tuple of (serialized announcement dictionary,
signature, pubkey) for each announcement. The V2 server dispatches messages
to subscribers according to the service-name, and throws errors for invalid
signatures, but does not otherwise examine the messages. The V2 receiver's
subscription callback will receive a (serverid, ann_dict) pair. The
'serverid' will be equal to the pubkey if all of the following are true:
the originating client is V2, and was told a privkey to use
the announcement went through a V2 server
the signature is valid
If not, 'serverid' will be equal to the tubid portion of the announced FURL,
as was the case for V1 receivers.
Servers will create a keypair if one does not exist yet, stored in
private/server.privkey .
The signed announcement dictionary puts the server FURL in a key named
"anonymous-storage-FURL", which anticipates upcoming Accounting-related
changes in the server advertisements. It also provides a key named
"permutation-seed-base32" to tell clients what permutation seed to use. This
is computed at startup, using tubid if there are existing shares, otherwise
the pubkey, to retain share-order compatibility for existing servers.
2011-11-20 10:21:32 +00:00
|
|
|
|
2019-03-07 20:04:53 +00:00
|
|
|
class Announcements(AsyncTestCase):
|
new introducer: signed extensible dictionary-based messages! refs #466
This introduces new client and server halves to the Introducer (renaming the
old one with a _V1 suffix). Both have fallbacks to accomodate talking to a
different version: the publishing client switches on whether the server's
.get_version() advertises V2 support, the server switches on which
subscription method was invoked by the subscribing client.
The V2 protocol sends a three-tuple of (serialized announcement dictionary,
signature, pubkey) for each announcement. The V2 server dispatches messages
to subscribers according to the service-name, and throws errors for invalid
signatures, but does not otherwise examine the messages. The V2 receiver's
subscription callback will receive a (serverid, ann_dict) pair. The
'serverid' will be equal to the pubkey if all of the following are true:
the originating client is V2, and was told a privkey to use
the announcement went through a V2 server
the signature is valid
If not, 'serverid' will be equal to the tubid portion of the announced FURL,
as was the case for V1 receivers.
Servers will create a keypair if one does not exist yet, stored in
private/server.privkey .
The signed announcement dictionary puts the server FURL in a key named
"anonymous-storage-FURL", which anticipates upcoming Accounting-related
changes in the server advertisements. It also provides a key named
"permutation-seed-base32" to tell clients what permutation seed to use. This
is computed at startup, using tubid if there are existing shares, otherwise
the pubkey, to retain share-order compatibility for existing servers.
2011-11-20 10:21:32 +00:00
|
|
|
def test_client_v2_signed(self):
|
|
|
|
introducer = IntroducerService()
|
|
|
|
tub = introducer_furl = None
|
|
|
|
app_versions = {"whizzy": "fizzy"}
|
|
|
|
client_v2 = IntroducerClient(tub, introducer_furl, u"nick-v2",
|
2013-03-19 00:40:56 +00:00
|
|
|
"my_version", "oldest", app_versions,
|
2016-05-10 19:14:36 +00:00
|
|
|
fakeseq, FilePath(self.mktemp()))
|
new introducer: signed extensible dictionary-based messages! refs #466
This introduces new client and server halves to the Introducer (renaming the
old one with a _V1 suffix). Both have fallbacks to accomodate talking to a
different version: the publishing client switches on whether the server's
.get_version() advertises V2 support, the server switches on which
subscription method was invoked by the subscribing client.
The V2 protocol sends a three-tuple of (serialized announcement dictionary,
signature, pubkey) for each announcement. The V2 server dispatches messages
to subscribers according to the service-name, and throws errors for invalid
signatures, but does not otherwise examine the messages. The V2 receiver's
subscription callback will receive a (serverid, ann_dict) pair. The
'serverid' will be equal to the pubkey if all of the following are true:
the originating client is V2, and was told a privkey to use
the announcement went through a V2 server
the signature is valid
If not, 'serverid' will be equal to the tubid portion of the announced FURL,
as was the case for V1 receivers.
Servers will create a keypair if one does not exist yet, stored in
private/server.privkey .
The signed announcement dictionary puts the server FURL in a key named
"anonymous-storage-FURL", which anticipates upcoming Accounting-related
changes in the server advertisements. It also provides a key named
"permutation-seed-base32" to tell clients what permutation seed to use. This
is computed at startup, using tubid if there are existing shares, otherwise
the pubkey, to retain share-order compatibility for existing servers.
2011-11-20 10:21:32 +00:00
|
|
|
furl1 = "pb://62ubehyunnyhzs7r6vdonnm2hpi52w6y@127.0.0.1:0/swissnum"
|
|
|
|
sk_s, vk_s = keyutil.make_keypair()
|
|
|
|
sk, _ignored = keyutil.parse_privkey(sk_s)
|
|
|
|
pks = keyutil.remove_prefix(vk_s, "pub-")
|
2013-03-19 00:40:56 +00:00
|
|
|
ann_t0 = make_ann_t(client_v2, furl1, sk, 10)
|
new introducer: signed extensible dictionary-based messages! refs #466
This introduces new client and server halves to the Introducer (renaming the
old one with a _V1 suffix). Both have fallbacks to accomodate talking to a
different version: the publishing client switches on whether the server's
.get_version() advertises V2 support, the server switches on which
subscription method was invoked by the subscribing client.
The V2 protocol sends a three-tuple of (serialized announcement dictionary,
signature, pubkey) for each announcement. The V2 server dispatches messages
to subscribers according to the service-name, and throws errors for invalid
signatures, but does not otherwise examine the messages. The V2 receiver's
subscription callback will receive a (serverid, ann_dict) pair. The
'serverid' will be equal to the pubkey if all of the following are true:
the originating client is V2, and was told a privkey to use
the announcement went through a V2 server
the signature is valid
If not, 'serverid' will be equal to the tubid portion of the announced FURL,
as was the case for V1 receivers.
Servers will create a keypair if one does not exist yet, stored in
private/server.privkey .
The signed announcement dictionary puts the server FURL in a key named
"anonymous-storage-FURL", which anticipates upcoming Accounting-related
changes in the server advertisements. It also provides a key named
"permutation-seed-base32" to tell clients what permutation seed to use. This
is computed at startup, using tubid if there are existing shares, otherwise
the pubkey, to retain share-order compatibility for existing servers.
2011-11-20 10:21:32 +00:00
|
|
|
canary0 = Referenceable()
|
|
|
|
introducer.remote_publish_v2(ann_t0, canary0)
|
|
|
|
a = introducer.get_announcements()
|
|
|
|
self.failUnlessEqual(len(a), 1)
|
2019-03-07 20:04:53 +00:00
|
|
|
self.assertThat(a[0].canary, Is(canary0))
|
2016-05-11 03:19:55 +00:00
|
|
|
self.failUnlessEqual(a[0].index, ("storage", pks))
|
2012-04-23 22:02:22 +00:00
|
|
|
self.failUnlessEqual(a[0].announcement["app-versions"], app_versions)
|
|
|
|
self.failUnlessEqual(a[0].nickname, u"nick-v2")
|
|
|
|
self.failUnlessEqual(a[0].service_name, "storage")
|
|
|
|
self.failUnlessEqual(a[0].version, "my_version")
|
|
|
|
self.failUnlessEqual(a[0].announcement["anonymous-storage-FURL"], furl1)
|
new introducer: signed extensible dictionary-based messages! refs #466
This introduces new client and server halves to the Introducer (renaming the
old one with a _V1 suffix). Both have fallbacks to accomodate talking to a
different version: the publishing client switches on whether the server's
.get_version() advertises V2 support, the server switches on which
subscription method was invoked by the subscribing client.
The V2 protocol sends a three-tuple of (serialized announcement dictionary,
signature, pubkey) for each announcement. The V2 server dispatches messages
to subscribers according to the service-name, and throws errors for invalid
signatures, but does not otherwise examine the messages. The V2 receiver's
subscription callback will receive a (serverid, ann_dict) pair. The
'serverid' will be equal to the pubkey if all of the following are true:
the originating client is V2, and was told a privkey to use
the announcement went through a V2 server
the signature is valid
If not, 'serverid' will be equal to the tubid portion of the announced FURL,
as was the case for V1 receivers.
Servers will create a keypair if one does not exist yet, stored in
private/server.privkey .
The signed announcement dictionary puts the server FURL in a key named
"anonymous-storage-FURL", which anticipates upcoming Accounting-related
changes in the server advertisements. It also provides a key named
"permutation-seed-base32" to tell clients what permutation seed to use. This
is computed at startup, using tubid if there are existing shares, otherwise
the pubkey, to retain share-order compatibility for existing servers.
2011-11-20 10:21:32 +00:00
|
|
|
|
2016-05-11 20:20:22 +00:00
|
|
|
def _load_cache(self, cache_filepath):
|
|
|
|
with cache_filepath.open() as f:
|
2016-07-20 00:22:12 +00:00
|
|
|
return yamlutil.safe_load(f)
|
2016-05-11 20:20:22 +00:00
|
|
|
|
2016-05-11 23:41:52 +00:00
|
|
|
@defer.inlineCallbacks
|
2016-05-11 20:30:39 +00:00
|
|
|
def test_client_cache(self):
|
2016-05-10 20:19:35 +00:00
|
|
|
basedir = "introducer/ClientSeqnums/test_client_cache_1"
|
|
|
|
fileutil.make_dirs(basedir)
|
2016-05-10 19:14:36 +00:00
|
|
|
cache_filepath = FilePath(os.path.join(basedir, "private",
|
2016-09-12 23:01:23 +00:00
|
|
|
"introducer_default_cache.yaml"))
|
2016-05-10 20:19:35 +00:00
|
|
|
|
|
|
|
# if storage is enabled, the Client will publish its storage server
|
|
|
|
# during startup (although the announcement will wait in a queue
|
|
|
|
# until the introducer connection is established). To avoid getting
|
|
|
|
# confused by this, disable storage.
|
|
|
|
f = open(os.path.join(basedir, "tahoe.cfg"), "w")
|
|
|
|
f.write("[client]\n")
|
|
|
|
f.write("introducer.furl = nope\n")
|
|
|
|
f.write("[storage]\n")
|
|
|
|
f.write("enabled = false\n")
|
|
|
|
f.close()
|
|
|
|
|
2018-01-28 06:13:50 +00:00
|
|
|
c = yield create_client(basedir)
|
2016-09-12 23:01:23 +00:00
|
|
|
ic = c.introducer_clients[0]
|
2016-05-10 20:19:35 +00:00
|
|
|
sk_s, vk_s = keyutil.make_keypair()
|
|
|
|
sk, _ignored = keyutil.parse_privkey(sk_s)
|
2016-05-11 20:30:39 +00:00
|
|
|
pub1 = keyutil.remove_prefix(vk_s, "pub-")
|
2016-05-10 20:19:35 +00:00
|
|
|
furl1 = "pb://onug64tu@127.0.0.1:123/short" # base32("short")
|
|
|
|
ann_t = make_ann_t(ic, furl1, sk, 1)
|
|
|
|
|
|
|
|
ic.got_announcements([ann_t])
|
2016-09-02 02:26:53 +00:00
|
|
|
yield flushEventualQueue()
|
2016-05-10 20:19:35 +00:00
|
|
|
|
|
|
|
# check the cache for the announcement
|
2016-05-11 20:20:22 +00:00
|
|
|
announcements = self._load_cache(cache_filepath)
|
2016-05-10 20:19:35 +00:00
|
|
|
self.failUnlessEqual(len(announcements), 1)
|
2016-05-11 20:30:39 +00:00
|
|
|
self.failUnlessEqual(announcements[0]['key_s'], pub1)
|
|
|
|
ann = announcements[0]["ann"]
|
|
|
|
self.failUnlessEqual(ann["anonymous-storage-FURL"], furl1)
|
|
|
|
self.failUnlessEqual(ann["seqnum"], 1)
|
|
|
|
|
|
|
|
# a new announcement that replaces the first should replace the
|
|
|
|
# cached entry, not duplicate it
|
|
|
|
furl2 = furl1 + "er"
|
|
|
|
ann_t2 = make_ann_t(ic, furl2, sk, 2)
|
|
|
|
ic.got_announcements([ann_t2])
|
2016-09-02 02:26:53 +00:00
|
|
|
yield flushEventualQueue()
|
2016-05-11 20:30:39 +00:00
|
|
|
announcements = self._load_cache(cache_filepath)
|
|
|
|
self.failUnlessEqual(len(announcements), 1)
|
|
|
|
self.failUnlessEqual(announcements[0]['key_s'], pub1)
|
|
|
|
ann = announcements[0]["ann"]
|
|
|
|
self.failUnlessEqual(ann["anonymous-storage-FURL"], furl2)
|
|
|
|
self.failUnlessEqual(ann["seqnum"], 2)
|
|
|
|
|
|
|
|
# but a third announcement with a different key should add to the
|
|
|
|
# cache
|
|
|
|
sk_s2, vk_s2 = keyutil.make_keypair()
|
|
|
|
sk2, _ignored = keyutil.parse_privkey(sk_s2)
|
|
|
|
pub2 = keyutil.remove_prefix(vk_s2, "pub-")
|
|
|
|
furl3 = "pb://onug64tu@127.0.0.1:456/short"
|
|
|
|
ann_t3 = make_ann_t(ic, furl3, sk2, 1)
|
|
|
|
ic.got_announcements([ann_t3])
|
2016-09-02 02:26:53 +00:00
|
|
|
yield flushEventualQueue()
|
2016-05-11 20:30:39 +00:00
|
|
|
|
|
|
|
announcements = self._load_cache(cache_filepath)
|
|
|
|
self.failUnlessEqual(len(announcements), 2)
|
|
|
|
self.failUnlessEqual(set([pub1, pub2]),
|
|
|
|
set([a["key_s"] for a in announcements]))
|
|
|
|
self.failUnlessEqual(set([furl2, furl3]),
|
|
|
|
set([a["ann"]["anonymous-storage-FURL"]
|
|
|
|
for a in announcements]))
|
2016-05-10 20:19:35 +00:00
|
|
|
|
2016-05-11 23:41:52 +00:00
|
|
|
# test loading
|
2016-09-02 02:26:53 +00:00
|
|
|
yield flushEventualQueue()
|
2016-05-11 23:41:52 +00:00
|
|
|
ic2 = IntroducerClient(None, "introducer.furl", u"my_nickname",
|
|
|
|
"my_version", "oldest_version", {}, fakeseq,
|
|
|
|
ic._cache_filepath)
|
|
|
|
announcements = {}
|
|
|
|
def got(key_s, ann):
|
|
|
|
announcements[key_s] = ann
|
|
|
|
ic2.subscribe_to("storage", got)
|
|
|
|
ic2._load_announcements() # normally happens when connection fails
|
|
|
|
yield flushEventualQueue()
|
|
|
|
|
|
|
|
self.failUnless(pub1 in announcements)
|
|
|
|
self.failUnlessEqual(announcements[pub1]["anonymous-storage-FURL"],
|
|
|
|
furl2)
|
|
|
|
self.failUnlessEqual(announcements[pub2]["anonymous-storage-FURL"],
|
|
|
|
furl3)
|
2016-05-10 20:19:35 +00:00
|
|
|
|
2018-01-28 06:13:50 +00:00
|
|
|
c2 = yield create_client(basedir)
|
2016-09-12 23:01:23 +00:00
|
|
|
c2.introducer_clients[0]._load_announcements()
|
2016-09-02 02:26:53 +00:00
|
|
|
yield flushEventualQueue()
|
|
|
|
self.assertEqual(c2.storage_broker.get_all_serverids(),
|
|
|
|
frozenset([pub1, pub2]))
|
|
|
|
|
2019-03-07 23:56:25 +00:00
|
|
|
class ClientSeqnums(AsyncBrokenTestCase):
|
2018-01-28 06:13:50 +00:00
|
|
|
|
|
|
|
@defer.inlineCallbacks
|
2013-03-19 00:40:56 +00:00
|
|
|
def test_client(self):
|
|
|
|
basedir = "introducer/ClientSeqnums/test_client"
|
|
|
|
fileutil.make_dirs(basedir)
|
2016-04-27 01:38:21 +00:00
|
|
|
# if storage is enabled, the Client will publish its storage server
|
|
|
|
# during startup (although the announcement will wait in a queue
|
|
|
|
# until the introducer connection is established). To avoid getting
|
|
|
|
# confused by this, disable storage.
|
2013-03-19 00:40:56 +00:00
|
|
|
f = open(os.path.join(basedir, "tahoe.cfg"), "w")
|
|
|
|
f.write("[client]\n")
|
|
|
|
f.write("introducer.furl = nope\n")
|
2016-04-27 01:38:21 +00:00
|
|
|
f.write("[storage]\n")
|
|
|
|
f.write("enabled = false\n")
|
2013-03-19 00:40:56 +00:00
|
|
|
f.close()
|
2016-04-27 01:38:21 +00:00
|
|
|
|
2018-01-28 06:13:50 +00:00
|
|
|
c = yield create_client(basedir)
|
2016-09-12 23:01:23 +00:00
|
|
|
ic = c.introducer_clients[0]
|
2013-03-19 00:40:56 +00:00
|
|
|
outbound = ic._outbound_announcements
|
|
|
|
published = ic._published_announcements
|
|
|
|
def read_seqnum():
|
|
|
|
f = open(os.path.join(basedir, "announcement-seqnum"))
|
|
|
|
seqnum = f.read().strip()
|
|
|
|
f.close()
|
|
|
|
return int(seqnum)
|
|
|
|
|
2013-04-14 20:22:10 +00:00
|
|
|
ic.publish("sA", {"key": "value1"}, c._node_key)
|
2013-03-19 00:40:56 +00:00
|
|
|
self.failUnlessEqual(read_seqnum(), 1)
|
|
|
|
self.failUnless("sA" in outbound)
|
|
|
|
self.failUnlessEqual(outbound["sA"]["seqnum"], 1)
|
|
|
|
nonce1 = outbound["sA"]["nonce"]
|
|
|
|
self.failUnless(isinstance(nonce1, str))
|
2017-01-19 22:39:53 +00:00
|
|
|
self.failUnlessEqual(json.loads(published["sA"][0]),
|
2013-03-19 00:40:56 +00:00
|
|
|
outbound["sA"])
|
|
|
|
# [1] is the signature, [2] is the pubkey
|
|
|
|
|
|
|
|
# publishing a second service causes both services to be
|
|
|
|
# re-published, with the next higher sequence number
|
2013-04-14 20:22:10 +00:00
|
|
|
ic.publish("sB", {"key": "value2"}, c._node_key)
|
2013-03-19 00:40:56 +00:00
|
|
|
self.failUnlessEqual(read_seqnum(), 2)
|
|
|
|
self.failUnless("sB" in outbound)
|
|
|
|
self.failUnlessEqual(outbound["sB"]["seqnum"], 2)
|
|
|
|
self.failUnless("sA" in outbound)
|
|
|
|
self.failUnlessEqual(outbound["sA"]["seqnum"], 2)
|
|
|
|
nonce2 = outbound["sA"]["nonce"]
|
|
|
|
self.failUnless(isinstance(nonce2, str))
|
|
|
|
self.failIfEqual(nonce1, nonce2)
|
2017-01-19 22:39:53 +00:00
|
|
|
self.failUnlessEqual(json.loads(published["sA"][0]),
|
2013-03-19 00:40:56 +00:00
|
|
|
outbound["sA"])
|
2017-01-19 22:39:53 +00:00
|
|
|
self.failUnlessEqual(json.loads(published["sB"][0]),
|
2013-03-19 00:40:56 +00:00
|
|
|
outbound["sB"])
|
|
|
|
|
|
|
|
|
new introducer: signed extensible dictionary-based messages! refs #466
This introduces new client and server halves to the Introducer (renaming the
old one with a _V1 suffix). Both have fallbacks to accomodate talking to a
different version: the publishing client switches on whether the server's
.get_version() advertises V2 support, the server switches on which
subscription method was invoked by the subscribing client.
The V2 protocol sends a three-tuple of (serialized announcement dictionary,
signature, pubkey) for each announcement. The V2 server dispatches messages
to subscribers according to the service-name, and throws errors for invalid
signatures, but does not otherwise examine the messages. The V2 receiver's
subscription callback will receive a (serverid, ann_dict) pair. The
'serverid' will be equal to the pubkey if all of the following are true:
the originating client is V2, and was told a privkey to use
the announcement went through a V2 server
the signature is valid
If not, 'serverid' will be equal to the tubid portion of the announced FURL,
as was the case for V1 receivers.
Servers will create a keypair if one does not exist yet, stored in
private/server.privkey .
The signed announcement dictionary puts the server FURL in a key named
"anonymous-storage-FURL", which anticipates upcoming Accounting-related
changes in the server advertisements. It also provides a key named
"permutation-seed-base32" to tell clients what permutation seed to use. This
is computed at startup, using tubid if there are existing shares, otherwise
the pubkey, to retain share-order compatibility for existing servers.
2011-11-20 10:21:32 +00:00
|
|
|
|
2008-11-22 03:07:27 +00:00
|
|
|
class TooNewServer(IntroducerService):
|
|
|
|
VERSION = { "http://allmydata.org/tahoe/protocols/introducer/v999":
|
|
|
|
{ },
|
|
|
|
"application-version": "greetings from the crazy future",
|
|
|
|
}
|
|
|
|
|
2019-03-07 20:04:53 +00:00
|
|
|
class NonV1Server(SystemTestMixin, AsyncTestCase):
|
2016-06-30 05:58:14 +00:00
|
|
|
# if the client connects to a server that doesn't provide the 'v2'
|
2008-11-22 03:07:27 +00:00
|
|
|
# protocol, it is supposed to provide a useful error instead of a weird
|
|
|
|
# exception.
|
|
|
|
|
|
|
|
def test_failure(self):
|
2009-06-23 02:10:47 +00:00
|
|
|
self.basedir = "introducer/NonV1Server/failure"
|
|
|
|
os.makedirs(self.basedir)
|
|
|
|
self.create_tub()
|
2008-11-22 03:07:27 +00:00
|
|
|
i = TooNewServer()
|
|
|
|
i.setServiceParent(self.parent)
|
|
|
|
self.introducer_furl = self.central_tub.registerReference(i)
|
|
|
|
|
|
|
|
tub = Tub()
|
2009-05-22 00:46:32 +00:00
|
|
|
tub.setOption("expose-remote-exception-types", False)
|
2008-11-22 03:07:27 +00:00
|
|
|
tub.setServiceParent(self.parent)
|
2018-06-08 15:21:25 +00:00
|
|
|
listenOnUnused(tub)
|
2008-11-22 03:07:27 +00:00
|
|
|
c = IntroducerClient(tub, self.introducer_furl,
|
2013-03-19 00:40:56 +00:00
|
|
|
u"nickname-client", "version", "oldest", {},
|
2016-05-10 19:14:36 +00:00
|
|
|
fakeseq, FilePath(self.mktemp()))
|
2009-06-23 02:10:47 +00:00
|
|
|
announcements = {}
|
new introducer: signed extensible dictionary-based messages! refs #466
This introduces new client and server halves to the Introducer (renaming the
old one with a _V1 suffix). Both have fallbacks to accomodate talking to a
different version: the publishing client switches on whether the server's
.get_version() advertises V2 support, the server switches on which
subscription method was invoked by the subscribing client.
The V2 protocol sends a three-tuple of (serialized announcement dictionary,
signature, pubkey) for each announcement. The V2 server dispatches messages
to subscribers according to the service-name, and throws errors for invalid
signatures, but does not otherwise examine the messages. The V2 receiver's
subscription callback will receive a (serverid, ann_dict) pair. The
'serverid' will be equal to the pubkey if all of the following are true:
the originating client is V2, and was told a privkey to use
the announcement went through a V2 server
the signature is valid
If not, 'serverid' will be equal to the tubid portion of the announced FURL,
as was the case for V1 receivers.
Servers will create a keypair if one does not exist yet, stored in
private/server.privkey .
The signed announcement dictionary puts the server FURL in a key named
"anonymous-storage-FURL", which anticipates upcoming Accounting-related
changes in the server advertisements. It also provides a key named
"permutation-seed-base32" to tell clients what permutation seed to use. This
is computed at startup, using tubid if there are existing shares, otherwise
the pubkey, to retain share-order compatibility for existing servers.
2011-11-20 10:21:32 +00:00
|
|
|
def got(key_s, ann):
|
|
|
|
announcements[key_s] = ann
|
2009-06-23 02:10:47 +00:00
|
|
|
c.subscribe_to("storage", got)
|
2008-11-22 03:07:27 +00:00
|
|
|
|
|
|
|
c.setServiceParent(self.parent)
|
|
|
|
|
|
|
|
# now we wait for it to connect and notice the bad version
|
|
|
|
|
|
|
|
def _got_bad():
|
|
|
|
return bool(c._introducer_error) or bool(c._publisher)
|
|
|
|
d = self.poll(_got_bad)
|
|
|
|
def _done(res):
|
|
|
|
self.failUnless(c._introducer_error)
|
new introducer: signed extensible dictionary-based messages! refs #466
This introduces new client and server halves to the Introducer (renaming the
old one with a _V1 suffix). Both have fallbacks to accomodate talking to a
different version: the publishing client switches on whether the server's
.get_version() advertises V2 support, the server switches on which
subscription method was invoked by the subscribing client.
The V2 protocol sends a three-tuple of (serialized announcement dictionary,
signature, pubkey) for each announcement. The V2 server dispatches messages
to subscribers according to the service-name, and throws errors for invalid
signatures, but does not otherwise examine the messages. The V2 receiver's
subscription callback will receive a (serverid, ann_dict) pair. The
'serverid' will be equal to the pubkey if all of the following are true:
the originating client is V2, and was told a privkey to use
the announcement went through a V2 server
the signature is valid
If not, 'serverid' will be equal to the tubid portion of the announced FURL,
as was the case for V1 receivers.
Servers will create a keypair if one does not exist yet, stored in
private/server.privkey .
The signed announcement dictionary puts the server FURL in a key named
"anonymous-storage-FURL", which anticipates upcoming Accounting-related
changes in the server advertisements. It also provides a key named
"permutation-seed-base32" to tell clients what permutation seed to use. This
is computed at startup, using tubid if there are existing shares, otherwise
the pubkey, to retain share-order compatibility for existing servers.
2011-11-20 10:21:32 +00:00
|
|
|
self.failUnless(c._introducer_error.check(InsufficientVersionError),
|
|
|
|
c._introducer_error)
|
2008-11-22 03:07:27 +00:00
|
|
|
d.addCallback(_done)
|
|
|
|
return d
|
|
|
|
|
2019-03-07 20:04:53 +00:00
|
|
|
class DecodeFurl(SyncTestCase):
|
2009-06-24 19:40:38 +00:00
|
|
|
def test_decode(self):
|
2009-05-19 03:41:01 +00:00
|
|
|
# make sure we have a working base64.b32decode. The one in
|
|
|
|
# python2.4.[01] was broken.
|
2009-06-24 19:40:38 +00:00
|
|
|
furl = 'pb://t5g7egomnnktbpydbuijt6zgtmw4oqi5@127.0.0.1:51857/hfzv36i'
|
|
|
|
m = re.match(r'pb://(\w+)@', furl)
|
|
|
|
assert m
|
|
|
|
nodeid = b32decode(m.group(1).upper())
|
2009-05-19 03:41:01 +00:00
|
|
|
self.failUnlessEqual(nodeid, "\x9fM\xf2\x19\xcckU0\xbf\x03\r\x10\x99\xfb&\x9b-\xc7A\x1d")
|
|
|
|
|
2019-03-07 20:04:53 +00:00
|
|
|
class Signatures(SyncTestCase):
|
new introducer: signed extensible dictionary-based messages! refs #466
This introduces new client and server halves to the Introducer (renaming the
old one with a _V1 suffix). Both have fallbacks to accomodate talking to a
different version: the publishing client switches on whether the server's
.get_version() advertises V2 support, the server switches on which
subscription method was invoked by the subscribing client.
The V2 protocol sends a three-tuple of (serialized announcement dictionary,
signature, pubkey) for each announcement. The V2 server dispatches messages
to subscribers according to the service-name, and throws errors for invalid
signatures, but does not otherwise examine the messages. The V2 receiver's
subscription callback will receive a (serverid, ann_dict) pair. The
'serverid' will be equal to the pubkey if all of the following are true:
the originating client is V2, and was told a privkey to use
the announcement went through a V2 server
the signature is valid
If not, 'serverid' will be equal to the tubid portion of the announced FURL,
as was the case for V1 receivers.
Servers will create a keypair if one does not exist yet, stored in
private/server.privkey .
The signed announcement dictionary puts the server FURL in a key named
"anonymous-storage-FURL", which anticipates upcoming Accounting-related
changes in the server advertisements. It also provides a key named
"permutation-seed-base32" to tell clients what permutation seed to use. This
is computed at startup, using tubid if there are existing shares, otherwise
the pubkey, to retain share-order compatibility for existing servers.
2011-11-20 10:21:32 +00:00
|
|
|
def test_sign(self):
|
|
|
|
ann = {"key1": "value1"}
|
|
|
|
sk_s,vk_s = keyutil.make_keypair()
|
|
|
|
sk,ignored = keyutil.parse_privkey(sk_s)
|
|
|
|
ann_t = sign_to_foolscap(ann, sk)
|
|
|
|
(msg, sig, key) = ann_t
|
|
|
|
self.failUnlessEqual(type(msg), type("".encode("utf-8"))) # bytes
|
2017-01-19 22:39:53 +00:00
|
|
|
self.failUnlessEqual(json.loads(msg.decode("utf-8")), ann)
|
new introducer: signed extensible dictionary-based messages! refs #466
This introduces new client and server halves to the Introducer (renaming the
old one with a _V1 suffix). Both have fallbacks to accomodate talking to a
different version: the publishing client switches on whether the server's
.get_version() advertises V2 support, the server switches on which
subscription method was invoked by the subscribing client.
The V2 protocol sends a three-tuple of (serialized announcement dictionary,
signature, pubkey) for each announcement. The V2 server dispatches messages
to subscribers according to the service-name, and throws errors for invalid
signatures, but does not otherwise examine the messages. The V2 receiver's
subscription callback will receive a (serverid, ann_dict) pair. The
'serverid' will be equal to the pubkey if all of the following are true:
the originating client is V2, and was told a privkey to use
the announcement went through a V2 server
the signature is valid
If not, 'serverid' will be equal to the tubid portion of the announced FURL,
as was the case for V1 receivers.
Servers will create a keypair if one does not exist yet, stored in
private/server.privkey .
The signed announcement dictionary puts the server FURL in a key named
"anonymous-storage-FURL", which anticipates upcoming Accounting-related
changes in the server advertisements. It also provides a key named
"permutation-seed-base32" to tell clients what permutation seed to use. This
is computed at startup, using tubid if there are existing shares, otherwise
the pubkey, to retain share-order compatibility for existing servers.
2011-11-20 10:21:32 +00:00
|
|
|
self.failUnless(sig.startswith("v0-"))
|
|
|
|
self.failUnless(key.startswith("v0-"))
|
|
|
|
(ann2,key2) = unsign_from_foolscap(ann_t)
|
|
|
|
self.failUnlessEqual(ann2, ann)
|
|
|
|
self.failUnlessEqual("pub-"+key2, vk_s)
|
|
|
|
|
2016-07-05 23:41:15 +00:00
|
|
|
# not signed
|
|
|
|
self.failUnlessRaises(UnknownKeyError,
|
|
|
|
unsign_from_foolscap, (msg, None, key))
|
|
|
|
self.failUnlessRaises(UnknownKeyError,
|
|
|
|
unsign_from_foolscap, (msg, sig, None))
|
new introducer: signed extensible dictionary-based messages! refs #466
This introduces new client and server halves to the Introducer (renaming the
old one with a _V1 suffix). Both have fallbacks to accomodate talking to a
different version: the publishing client switches on whether the server's
.get_version() advertises V2 support, the server switches on which
subscription method was invoked by the subscribing client.
The V2 protocol sends a three-tuple of (serialized announcement dictionary,
signature, pubkey) for each announcement. The V2 server dispatches messages
to subscribers according to the service-name, and throws errors for invalid
signatures, but does not otherwise examine the messages. The V2 receiver's
subscription callback will receive a (serverid, ann_dict) pair. The
'serverid' will be equal to the pubkey if all of the following are true:
the originating client is V2, and was told a privkey to use
the announcement went through a V2 server
the signature is valid
If not, 'serverid' will be equal to the tubid portion of the announced FURL,
as was the case for V1 receivers.
Servers will create a keypair if one does not exist yet, stored in
private/server.privkey .
The signed announcement dictionary puts the server FURL in a key named
"anonymous-storage-FURL", which anticipates upcoming Accounting-related
changes in the server advertisements. It also provides a key named
"permutation-seed-base32" to tell clients what permutation seed to use. This
is computed at startup, using tubid if there are existing shares, otherwise
the pubkey, to retain share-order compatibility for existing servers.
2011-11-20 10:21:32 +00:00
|
|
|
# bad signature
|
|
|
|
bad_ann = {"key1": "value2"}
|
2017-01-19 22:39:53 +00:00
|
|
|
bad_msg = json.dumps(bad_ann).encode("utf-8")
|
new introducer: signed extensible dictionary-based messages! refs #466
This introduces new client and server halves to the Introducer (renaming the
old one with a _V1 suffix). Both have fallbacks to accomodate talking to a
different version: the publishing client switches on whether the server's
.get_version() advertises V2 support, the server switches on which
subscription method was invoked by the subscribing client.
The V2 protocol sends a three-tuple of (serialized announcement dictionary,
signature, pubkey) for each announcement. The V2 server dispatches messages
to subscribers according to the service-name, and throws errors for invalid
signatures, but does not otherwise examine the messages. The V2 receiver's
subscription callback will receive a (serverid, ann_dict) pair. The
'serverid' will be equal to the pubkey if all of the following are true:
the originating client is V2, and was told a privkey to use
the announcement went through a V2 server
the signature is valid
If not, 'serverid' will be equal to the tubid portion of the announced FURL,
as was the case for V1 receivers.
Servers will create a keypair if one does not exist yet, stored in
private/server.privkey .
The signed announcement dictionary puts the server FURL in a key named
"anonymous-storage-FURL", which anticipates upcoming Accounting-related
changes in the server advertisements. It also provides a key named
"permutation-seed-base32" to tell clients what permutation seed to use. This
is computed at startup, using tubid if there are existing shares, otherwise
the pubkey, to retain share-order compatibility for existing servers.
2011-11-20 10:21:32 +00:00
|
|
|
self.failUnlessRaises(keyutil.BadSignatureError,
|
|
|
|
unsign_from_foolscap, (bad_msg,sig,key))
|
|
|
|
|
|
|
|
# unrecognized signatures
|
|
|
|
self.failUnlessRaises(UnknownKeyError,
|
|
|
|
unsign_from_foolscap, (bad_msg,"v999-sig",key))
|
|
|
|
self.failUnlessRaises(UnknownKeyError,
|
|
|
|
unsign_from_foolscap, (bad_msg,sig,"v999-key"))
|
|
|
|
|
|
|
|
|
|
|
|
# add tests of StorageFarmBroker: if it receives duplicate announcements, it
|
|
|
|
# should leave the Reconnector in place, also if it receives
|
|
|
|
# same-FURL-different-misc, but if it receives same-nodeid-different-FURL, it
|
|
|
|
# should tear down the Reconnector and make a new one. This behavior used to
|
|
|
|
# live in the IntroducerClient, and thus used to be tested by test_introducer
|
|
|
|
|
|
|
|
# copying more tests from old branch:
|
|
|
|
|
|
|
|
# then also add Upgrade test
|