2007-03-27 23:12:11 +00:00
|
|
|
|
2009-06-24 19:40:38 +00:00
|
|
|
import os, re
|
|
|
|
from base64 import b32decode
|
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
|
|
|
import simplejson
|
2007-12-03 21:52:42 +00:00
|
|
|
|
2007-03-27 23:12:11 +00:00
|
|
|
from twisted.trial import unittest
|
2008-02-05 20:05:13 +00:00
|
|
|
from twisted.internet import defer
|
2007-03-27 23:12:11 +00:00
|
|
|
from twisted.python import log
|
|
|
|
|
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
|
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.client import IntroducerClient, \
|
|
|
|
WrapV2ClientInV1Interface
|
2008-06-18 19:24:16 +00:00
|
|
|
from allmydata.introducer.server import IntroducerService
|
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
|
|
|
|
from allmydata.introducer import old
|
2008-06-18 19:24:16 +00:00
|
|
|
# test compatibility with old introducer .tac files
|
|
|
|
from allmydata.introducer import IntroducerNode
|
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.util import pollmixin, keyutil
|
2010-02-26 08:14:33 +00:00
|
|
|
import allmydata.test.common_util as testutil
|
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
|
|
|
|
2008-06-18 23:58:34 +00:00
|
|
|
class Node(testutil.SignalMixin, unittest.TestCase):
|
2007-12-03 21:52:42 +00:00
|
|
|
def test_loadable(self):
|
|
|
|
basedir = "introducer.IntroducerNode.test_loadable"
|
|
|
|
os.mkdir(basedir)
|
|
|
|
q = IntroducerNode(basedir)
|
|
|
|
d = fireEventually(None)
|
|
|
|
d.addCallback(lambda res: q.startService())
|
|
|
|
d.addCallback(lambda res: q.when_tub_ready())
|
|
|
|
d.addCallback(lambda res: q.stopService())
|
|
|
|
d.addCallback(flushEventualQueue)
|
|
|
|
return d
|
|
|
|
|
2008-06-18 23:58:34 +00:00
|
|
|
class ServiceMixin:
|
2007-03-27 23:12:11 +00:00
|
|
|
def setUp(self):
|
|
|
|
self.parent = LoggingMultiService()
|
|
|
|
self.parent.startService()
|
|
|
|
def tearDown(self):
|
|
|
|
log.msg("TestIntroducer.tearDown")
|
2007-04-04 23:09:13 +00:00
|
|
|
d = defer.succeed(None)
|
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
|
|
|
|
|
2008-10-29 04:15:48 +00:00
|
|
|
class Introducer(ServiceMixin, unittest.TestCase, pollmixin.PollMixin):
|
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",
|
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
|
|
|
"my_version", "oldest_version", {})
|
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
|
|
|
def test_duplicate_publish(self):
|
2008-04-23 22:05:39 +00:00
|
|
|
i = IntroducerService()
|
|
|
|
self.failUnlessEqual(len(i.get_announcements()), 0)
|
|
|
|
self.failUnlessEqual(len(i.get_subscribers()), 0)
|
|
|
|
furl1 = "pb://62ubehyunnyhzs7r6vdonnm2hpi52w6y@192.168.69.247:36106,127.0.0.1:36106/gydnpigj2ja2qr2srq4ikjwnl7xfgbra"
|
|
|
|
furl2 = "pb://ttwwooyunnyhzs7r6vdonnm2hpi52w6y@192.168.69.247:36111,127.0.0.1:36106/ttwwoogj2ja2qr2srq4ikjwnl7xfgbra"
|
|
|
|
ann1 = (furl1, "storage", "RIStorage", "nick1", "ver23", "ver0")
|
|
|
|
ann1b = (furl1, "storage", "RIStorage", "nick1", "ver24", "ver0")
|
|
|
|
ann2 = (furl2, "storage", "RIStorage", "nick2", "ver30", "ver0")
|
|
|
|
i.remote_publish(ann1)
|
|
|
|
self.failUnlessEqual(len(i.get_announcements()), 1)
|
|
|
|
self.failUnlessEqual(len(i.get_subscribers()), 0)
|
|
|
|
i.remote_publish(ann2)
|
|
|
|
self.failUnlessEqual(len(i.get_announcements()), 2)
|
|
|
|
self.failUnlessEqual(len(i.get_subscribers()), 0)
|
|
|
|
i.remote_publish(ann1b)
|
|
|
|
self.failUnlessEqual(len(i.get_announcements()), 2)
|
|
|
|
self.failUnlessEqual(len(i.get_subscribers()), 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
|
|
|
def test_id_collision(self):
|
|
|
|
# test replacement case where tubid equals a keyid (one should
|
|
|
|
# not replace the other)
|
|
|
|
i = IntroducerService()
|
|
|
|
ic = IntroducerClient(None,
|
|
|
|
"introducer.furl", u"my_nickname",
|
|
|
|
"my_version", "oldest_version", {})
|
|
|
|
sk_s, vk_s = keyutil.make_keypair()
|
|
|
|
sk, _ignored = keyutil.parse_privkey(sk_s)
|
|
|
|
keyid = keyutil.remove_prefix(vk_s, "pub-v0-")
|
|
|
|
furl1 = "pb://onug64tu@127.0.0.1:123/short" # base32("short")
|
|
|
|
ann_t = ic.create_announcement("storage", make_ann(furl1), sk)
|
|
|
|
i.remote_publish_v2(ann_t, Referenceable())
|
|
|
|
announcements = i.get_announcements()
|
|
|
|
self.failUnlessEqual(len(announcements), 1)
|
|
|
|
key1 = ("storage", "v0-"+keyid, None)
|
|
|
|
self.failUnless(key1 in announcements)
|
|
|
|
(ign, ign, ann1_out, ign) = announcements[key1]
|
|
|
|
self.failUnlessEqual(ann1_out["anonymous-storage-FURL"], furl1)
|
|
|
|
|
|
|
|
furl2 = "pb://%s@127.0.0.1:36106/swissnum" % keyid
|
|
|
|
ann2 = (furl2, "storage", "RIStorage", "nick1", "ver23", "ver0")
|
|
|
|
i.remote_publish(ann2)
|
|
|
|
self.failUnlessEqual(len(announcements), 2)
|
|
|
|
key2 = ("storage", None, keyid)
|
|
|
|
self.failUnless(key2 in announcements)
|
|
|
|
(ign, ign, ann2_out, ign) = announcements[key2]
|
|
|
|
self.failUnlessEqual(ann2_out["anonymous-storage-FURL"], furl2)
|
|
|
|
|
|
|
|
|
|
|
|
def make_ann(furl):
|
|
|
|
ann = { "anonymous-storage-FURL": furl,
|
|
|
|
"permutation-seed-base32": get_tubid_string(furl) }
|
|
|
|
return ann
|
|
|
|
|
|
|
|
def make_ann_t(ic, furl, privkey):
|
|
|
|
return ic.create_announcement("storage", make_ann(furl), privkey)
|
|
|
|
|
|
|
|
class Client(unittest.TestCase):
|
|
|
|
def test_duplicate_receive_v1(self):
|
|
|
|
ic = IntroducerClient(None,
|
|
|
|
"introducer.furl", u"my_nickname",
|
|
|
|
"my_version", "oldest_version", {})
|
|
|
|
announcements = []
|
|
|
|
ic.subscribe_to("storage",
|
|
|
|
lambda key_s,ann: announcements.append(ann))
|
|
|
|
furl1 = "pb://62ubehyunnyhzs7r6vdonnm2hpi52w6y@127.0.0.1:36106/gydnpigj2ja2qr2srq4ikjwnl7xfgbra"
|
|
|
|
ann1 = (furl1, "storage", "RIStorage", "nick1", "ver23", "ver0")
|
|
|
|
ann1b = (furl1, "storage", "RIStorage", "nick1", "ver24", "ver0")
|
|
|
|
ca = WrapV2ClientInV1Interface(ic)
|
|
|
|
|
|
|
|
ca.remote_announce([ann1])
|
|
|
|
d = fireEventually()
|
|
|
|
def _then(ign):
|
|
|
|
self.failUnlessEqual(len(announcements), 1)
|
|
|
|
self.failUnlessEqual(announcements[0]["nickname"], u"nick1")
|
|
|
|
self.failUnlessEqual(announcements[0]["my-version"], "ver23")
|
|
|
|
self.failUnlessEqual(ic._debug_counts["inbound_announcement"], 1)
|
|
|
|
self.failUnlessEqual(ic._debug_counts["new_announcement"], 1)
|
|
|
|
self.failUnlessEqual(ic._debug_counts["update"], 0)
|
|
|
|
self.failUnlessEqual(ic._debug_counts["duplicate_announcement"], 0)
|
|
|
|
# now send a duplicate announcement: this should not notify clients
|
|
|
|
ca.remote_announce([ann1])
|
|
|
|
return fireEventually()
|
|
|
|
d.addCallback(_then)
|
|
|
|
def _then2(ign):
|
|
|
|
self.failUnlessEqual(len(announcements), 1)
|
|
|
|
self.failUnlessEqual(ic._debug_counts["inbound_announcement"], 2)
|
|
|
|
self.failUnlessEqual(ic._debug_counts["new_announcement"], 1)
|
|
|
|
self.failUnlessEqual(ic._debug_counts["update"], 0)
|
|
|
|
self.failUnlessEqual(ic._debug_counts["duplicate_announcement"], 1)
|
|
|
|
# and a replacement announcement: same FURL, new other stuff.
|
|
|
|
# Clients should be notified.
|
|
|
|
ca.remote_announce([ann1b])
|
|
|
|
return fireEventually()
|
|
|
|
d.addCallback(_then2)
|
|
|
|
def _then3(ign):
|
|
|
|
self.failUnlessEqual(len(announcements), 2)
|
|
|
|
self.failUnlessEqual(ic._debug_counts["inbound_announcement"], 3)
|
|
|
|
self.failUnlessEqual(ic._debug_counts["new_announcement"], 1)
|
|
|
|
self.failUnlessEqual(ic._debug_counts["update"], 1)
|
|
|
|
self.failUnlessEqual(ic._debug_counts["duplicate_announcement"], 1)
|
|
|
|
# test that the other stuff changed
|
|
|
|
self.failUnlessEqual(announcements[-1]["nickname"], u"nick1")
|
|
|
|
self.failUnlessEqual(announcements[-1]["my-version"], "ver24")
|
|
|
|
d.addCallback(_then3)
|
|
|
|
return d
|
|
|
|
|
|
|
|
def test_duplicate_receive_v2(self):
|
|
|
|
ic1 = IntroducerClient(None,
|
|
|
|
"introducer.furl", u"my_nickname",
|
|
|
|
"ver23", "oldest_version", {})
|
|
|
|
# we use a second client just to create a different-looking
|
|
|
|
# announcement
|
|
|
|
ic2 = IntroducerClient(None,
|
|
|
|
"introducer.furl", u"my_nickname",
|
|
|
|
"ver24","oldest_version",{})
|
|
|
|
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
|
|
|
|
|
|
|
|
self.ann1 = make_ann_t(ic1, furl1, privkey)
|
|
|
|
self.ann1a = make_ann_t(ic1, furl1a, privkey)
|
|
|
|
self.ann1b = make_ann_t(ic2, furl1, privkey)
|
|
|
|
self.ann2 = make_ann_t(ic2, furl2, privkey)
|
|
|
|
|
|
|
|
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)
|
|
|
|
|
|
|
|
# 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
|
|
|
|
|
|
|
|
def test_id_collision(self):
|
|
|
|
# test replacement case where tubid equals a keyid (one should
|
|
|
|
# not replace the other)
|
|
|
|
ic = IntroducerClient(None,
|
|
|
|
"introducer.furl", u"my_nickname",
|
|
|
|
"my_version", "oldest_version", {})
|
|
|
|
announcements = []
|
|
|
|
ic.subscribe_to("storage",
|
|
|
|
lambda key_s,ann: announcements.append(ann))
|
|
|
|
sk_s, vk_s = keyutil.make_keypair()
|
|
|
|
sk, _ignored = keyutil.parse_privkey(sk_s)
|
|
|
|
keyid = keyutil.remove_prefix(vk_s, "pub-v0-")
|
|
|
|
furl1 = "pb://onug64tu@127.0.0.1:123/short" # base32("short")
|
|
|
|
furl2 = "pb://%s@127.0.0.1:36106/swissnum" % keyid
|
|
|
|
ann_t = ic.create_announcement("storage", make_ann(furl1), sk)
|
|
|
|
ic.remote_announce_v2([ann_t])
|
|
|
|
d = fireEventually()
|
|
|
|
def _then(ign):
|
|
|
|
# first announcement has been processed
|
|
|
|
self.failUnlessEqual(len(announcements), 1)
|
|
|
|
self.failUnlessEqual(announcements[0]["anonymous-storage-FURL"],
|
|
|
|
furl1)
|
|
|
|
# now submit a second one, with a tubid that happens to look just
|
|
|
|
# like the pubkey-based serverid we just processed. They should
|
|
|
|
# not overlap.
|
|
|
|
ann2 = (furl2, "storage", "RIStorage", "nick1", "ver23", "ver0")
|
|
|
|
ca = WrapV2ClientInV1Interface(ic)
|
|
|
|
ca.remote_announce([ann2])
|
|
|
|
return fireEventually()
|
|
|
|
d.addCallback(_then)
|
|
|
|
def _then2(ign):
|
|
|
|
# if they overlapped, the second announcement would be ignored
|
|
|
|
self.failUnlessEqual(len(announcements), 2)
|
|
|
|
self.failUnlessEqual(announcements[1]["anonymous-storage-FURL"],
|
|
|
|
furl2)
|
|
|
|
d.addCallback(_then2)
|
|
|
|
return d
|
|
|
|
|
|
|
|
|
2008-10-29 04:15:48 +00:00
|
|
|
class SystemTestMixin(ServiceMixin, pollmixin.PollMixin):
|
2008-04-23 22:05:39 +00:00
|
|
|
|
2009-06-23 02:10:47 +00:00
|
|
|
def create_tub(self, portnum=0):
|
|
|
|
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)
|
2009-06-23 02:10:47 +00:00
|
|
|
l = tub.listenOn("tcp:%d" % portnum)
|
|
|
|
self.central_portnum = l.getPortnum()
|
|
|
|
if portnum != 0:
|
|
|
|
assert self.central_portnum == portnum
|
|
|
|
tub.setLocation("localhost:%d" % self.central_portnum)
|
2007-03-27 23:12:11 +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
|
|
|
class Queue(SystemTestMixin, unittest.TestCase):
|
|
|
|
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,
|
|
|
|
u"nickname", "version", "oldest", {})
|
|
|
|
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):
|
|
|
|
v = list(introducer.get_announcements().values())[0]
|
|
|
|
(ign, ign, ann1_out, ign) = v
|
|
|
|
self.failUnlessEqual(ann1_out["anonymous-storage-FURL"], furl1)
|
|
|
|
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
|
|
|
|
|
|
|
V1 = "v1"; V2 = "v2"
|
|
|
|
class SystemTest(SystemTestMixin, unittest.TestCase):
|
|
|
|
|
|
|
|
def do_system_test(self, server_version):
|
2009-06-23 02:10:47 +00:00
|
|
|
self.create_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
|
|
|
if server_version == V1:
|
|
|
|
introducer = old.IntroducerService_v1()
|
|
|
|
else:
|
|
|
|
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 = []
|
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 = {}
|
|
|
|
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)
|
|
|
|
l = tub.listenOn("tcp:0")
|
|
|
|
portnum = l.getPortnum()
|
|
|
|
tub.setLocation("localhost:%d" % portnum)
|
|
|
|
|
2008-02-02 02:48:38 +00:00
|
|
|
log.msg("creating client %d: %s" % (i, tub.getShortTubID()))
|
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 == 0:
|
|
|
|
c = old.IntroducerClient_v1(tub, self.introducer_furl,
|
|
|
|
u"nickname-%d" % i,
|
|
|
|
"version", "oldest")
|
|
|
|
else:
|
|
|
|
c = IntroducerClient(tub, self.introducer_furl,
|
|
|
|
u"nickname-%d" % i,
|
|
|
|
"version", "oldest",
|
|
|
|
{"component": "component-v1"})
|
2010-01-14 22:15:29 +00:00
|
|
|
received_announcements[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
|
|
|
def got(key_s_or_tubid, ann, announcements, i):
|
|
|
|
if i == 0:
|
|
|
|
index = get_tubid_string_from_ann(ann)
|
|
|
|
else:
|
|
|
|
index = key_s_or_tubid or get_tubid_string_from_ann(ann)
|
|
|
|
announcements[index] = ann
|
|
|
|
c.subscribe_to("storage", got, received_announcements[c], i)
|
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())
|
|
|
|
if i < NUM_STORAGE:
|
|
|
|
if i == 0:
|
|
|
|
c.publish(node_furl, "storage", "ri_name")
|
|
|
|
elif i == 1:
|
|
|
|
# sign the announcement
|
|
|
|
privkey_s, pubkey_s = keyutil.make_keypair()
|
|
|
|
privkey, _ignored = keyutil.parse_privkey(privkey_s)
|
|
|
|
privkeys[c] = privkey
|
|
|
|
c.publish("storage", make_ann(node_furl), privkey)
|
|
|
|
else:
|
|
|
|
c.publish("storage", make_ann(node_furl))
|
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 == 0:
|
|
|
|
# users of the V1 client were required to publish a
|
|
|
|
# 'stub_client' record (somewhat after they published the
|
|
|
|
# 'storage' record), so the introducer could see their
|
|
|
|
# version. Match that behavior.
|
|
|
|
c.publish(node_furl, "stub_client", "stub_ri_name")
|
|
|
|
|
|
|
|
if i == 2:
|
|
|
|
# also publish something that nobody cares about
|
|
|
|
boring_furl = tub.registerReference(Referenceable())
|
|
|
|
c.publish("boring", make_ann(boring_furl))
|
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
|
|
|
|
if 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")
|
2009-06-23 02:10:47 +00:00
|
|
|
dc = 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
|
|
|
if server_version == V1:
|
|
|
|
# each storage server publishes a record, and (after its
|
|
|
|
# 'subscribe' has been ACKed) also publishes a "stub_client".
|
|
|
|
# The non-storage client (which subscribes) also publishes a
|
|
|
|
# stub_client. There is also one "boring" service. The number
|
|
|
|
# of messages is higher, because the stub_clients aren't
|
|
|
|
# published until after we get the 'subscribe' ack (since we
|
|
|
|
# don't realize that we're dealing with a v1 server [which
|
|
|
|
# needs stub_clients] until then), and the act of publishing
|
|
|
|
# the stub_client causes us to re-send all previous
|
|
|
|
# announcements.
|
|
|
|
self.failUnlessEqual(dc["inbound_message"] - dc["inbound_duplicate"],
|
|
|
|
NUM_STORAGE + NUM_CLIENTS + 1)
|
|
|
|
else:
|
|
|
|
# each storage server publishes a record. There is also one
|
|
|
|
# "stub_client" and one "boring"
|
|
|
|
self.failUnlessEqual(dc["inbound_message"], NUM_STORAGE+2)
|
|
|
|
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"],
|
|
|
|
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"],
|
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)
|
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"],
|
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)
|
2009-06-23 02:10:47 +00:00
|
|
|
anns = received_announcements[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
|
|
|
self.failUnlessEqual(len(anns), NUM_STORAGE)
|
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
|
|
|
nodeid0 = tubs[clients[0]].tubID
|
|
|
|
ann = anns[nodeid0]
|
|
|
|
nick = ann["nickname"]
|
2009-06-23 02:10:47 +00:00
|
|
|
self.failUnlessEqual(type(nick), unicode)
|
|
|
|
self.failUnlessEqual(nick, u"nickname-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
|
|
|
if server_version == V1:
|
|
|
|
for c in publishing_clients:
|
|
|
|
cdc = c._debug_counts
|
|
|
|
expected = 1 # storage
|
|
|
|
if c is clients[2]:
|
|
|
|
expected += 1 # boring
|
|
|
|
if c is not clients[0]:
|
|
|
|
# the v2 client tries to call publish_v2, which fails
|
|
|
|
# because the server is v1. It then re-sends
|
|
|
|
# everything it has so far, plus a stub_client record
|
|
|
|
expected = 2*expected + 1
|
|
|
|
if c is clients[0]:
|
|
|
|
# we always tell v1 client to send stub_client
|
|
|
|
expected += 1
|
|
|
|
self.failUnlessEqual(cdc["outbound_message"], expected)
|
|
|
|
else:
|
|
|
|
for c in publishing_clients:
|
|
|
|
cdc = c._debug_counts
|
|
|
|
expected = 1
|
|
|
|
if c in [clients[0], # stub_client
|
|
|
|
clients[2], # boring
|
|
|
|
]:
|
|
|
|
expected = 2
|
|
|
|
self.failUnlessEqual(cdc["outbound_message"], expected)
|
|
|
|
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
|
|
|
|
for k in introducer._debug_counts:
|
|
|
|
introducer._debug_counts[k] = 0
|
|
|
|
expected_announcements[i] += 1 # new 'storage' for everyone
|
2009-06-23 02:10:47 +00:00
|
|
|
self.create_tub(self.central_portnum)
|
|
|
|
newfurl = self.central_tub.registerReference(introducer,
|
|
|
|
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
|
|
|
|
dc = 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"],
|
|
|
|
NUM_STORAGE*NUM_CLIENTS)
|
|
|
|
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)
|
|
|
|
self.failUnlessEqual(cdc["inbound_announcement"], NUM_STORAGE)
|
|
|
|
self.failUnlessEqual(cdc["new_announcement"], 0)
|
|
|
|
self.failUnlessEqual(cdc["wrong_service"], 0)
|
|
|
|
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
|
|
|
|
if server_version == V1:
|
|
|
|
introducer = old.IntroducerService_v1()
|
|
|
|
else:
|
|
|
|
introducer = IntroducerService()
|
|
|
|
newfurl = self.central_tub.registerReference(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")
|
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
|
|
|
dc = introducer._debug_counts
|
|
|
|
self.failUnlessEqual(dc["outbound_announcements"],
|
|
|
|
NUM_STORAGE*NUM_CLIENTS)
|
|
|
|
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)
|
|
|
|
self.failUnlessEqual(cdc["inbound_announcement"], NUM_STORAGE)
|
|
|
|
self.failUnlessEqual(cdc["new_announcement"], 0)
|
|
|
|
self.failUnlessEqual(cdc["wrong_service"], 0)
|
|
|
|
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)
|
|
|
|
return self.do_system_test(V2)
|
|
|
|
test_system_v2_server.timeout = 480
|
|
|
|
# occasionally takes longer than 350s on "draco"
|
|
|
|
|
|
|
|
def test_system_v1_server(self):
|
|
|
|
self.basedir = "introducer/SystemTest/system_v1_server"
|
|
|
|
os.makedirs(self.basedir)
|
|
|
|
return self.do_system_test(V1)
|
|
|
|
test_system_v1_server.timeout = 480
|
|
|
|
# occasionally takes longer than 350s on "draco"
|
|
|
|
|
|
|
|
class FakeRemoteReference:
|
|
|
|
def notifyOnDisconnect(self, *args, **kwargs): pass
|
|
|
|
def getRemoteTubID(self): return "62ubehyunnyhzs7r6vdonnm2hpi52w6y"
|
|
|
|
|
|
|
|
class ClientInfo(unittest.TestCase):
|
|
|
|
def test_client_v2(self):
|
|
|
|
introducer = IntroducerService()
|
|
|
|
tub = introducer_furl = None
|
|
|
|
app_versions = {"whizzy": "fizzy"}
|
|
|
|
client_v2 = IntroducerClient(tub, introducer_furl, u"nick-v2",
|
|
|
|
"my_version", "oldest", app_versions)
|
|
|
|
#furl1 = "pb://62ubehyunnyhzs7r6vdonnm2hpi52w6y@127.0.0.1:0/swissnum"
|
|
|
|
#ann_s = make_ann_t(client_v2, furl1, None)
|
|
|
|
#introducer.remote_publish_v2(ann_s, Referenceable())
|
|
|
|
subscriber = FakeRemoteReference()
|
|
|
|
introducer.remote_subscribe_v2(subscriber, "storage",
|
|
|
|
client_v2._my_subscriber_info)
|
|
|
|
s = introducer.get_subscribers()
|
|
|
|
self.failUnlessEqual(len(s), 1)
|
|
|
|
sn, when, si, rref = s[0]
|
|
|
|
self.failUnlessIdentical(rref, subscriber)
|
|
|
|
self.failUnlessEqual(sn, "storage")
|
|
|
|
self.failUnlessEqual(si["version"], 0)
|
|
|
|
self.failUnlessEqual(si["oldest-supported"], "oldest")
|
|
|
|
self.failUnlessEqual(si["app-versions"], app_versions)
|
|
|
|
self.failUnlessEqual(si["nickname"], u"nick-v2")
|
|
|
|
self.failUnlessEqual(si["my-version"], "my_version")
|
|
|
|
|
|
|
|
def test_client_v1(self):
|
|
|
|
introducer = IntroducerService()
|
|
|
|
subscriber = FakeRemoteReference()
|
|
|
|
introducer.remote_subscribe(subscriber, "storage")
|
|
|
|
# the v1 subscribe interface had no subscriber_info: that was usually
|
|
|
|
# sent in a separate stub_client pseudo-announcement
|
|
|
|
s = introducer.get_subscribers()
|
|
|
|
self.failUnlessEqual(len(s), 1)
|
|
|
|
sn, when, si, rref = s[0]
|
|
|
|
# rref will be a WrapV1SubscriberInV2Interface around the real
|
|
|
|
# subscriber
|
|
|
|
self.failUnlessIdentical(rref.original, subscriber)
|
|
|
|
self.failUnlessEqual(si, None) # not known yet
|
|
|
|
self.failUnlessEqual(sn, "storage")
|
|
|
|
|
|
|
|
# now submit the stub_client announcement
|
|
|
|
furl1 = "pb://62ubehyunnyhzs7r6vdonnm2hpi52w6y@127.0.0.1:0/swissnum"
|
|
|
|
ann = (furl1, "stub_client", "RIStubClient",
|
|
|
|
u"nick-v1".encode("utf-8"), "my_version", "oldest")
|
|
|
|
introducer.remote_publish(ann)
|
|
|
|
# the server should correlate the two
|
|
|
|
s = introducer.get_subscribers()
|
|
|
|
self.failUnlessEqual(len(s), 1)
|
|
|
|
sn, when, si, rref = s[0]
|
|
|
|
self.failUnlessIdentical(rref.original, subscriber)
|
|
|
|
self.failUnlessEqual(sn, "storage")
|
|
|
|
|
|
|
|
self.failUnlessEqual(si["version"], 0)
|
|
|
|
self.failUnlessEqual(si["oldest-supported"], "oldest")
|
|
|
|
# v1 announcements do not contain app-versions
|
|
|
|
self.failUnlessEqual(si["app-versions"], {})
|
|
|
|
self.failUnlessEqual(si["nickname"], u"nick-v1")
|
|
|
|
self.failUnlessEqual(si["my-version"], "my_version")
|
|
|
|
|
|
|
|
# a subscription that arrives after the stub_client announcement
|
|
|
|
# should be correlated too
|
|
|
|
subscriber2 = FakeRemoteReference()
|
|
|
|
introducer.remote_subscribe(subscriber2, "thing2")
|
|
|
|
|
|
|
|
s = introducer.get_subscribers()
|
|
|
|
subs = dict([(sn, (si,rref)) for sn, when, si, rref in s])
|
|
|
|
self.failUnlessEqual(len(subs), 2)
|
|
|
|
(si,rref) = subs["thing2"]
|
|
|
|
self.failUnlessIdentical(rref.original, subscriber2)
|
|
|
|
self.failUnlessEqual(si["version"], 0)
|
|
|
|
self.failUnlessEqual(si["oldest-supported"], "oldest")
|
|
|
|
# v1 announcements do not contain app-versions
|
|
|
|
self.failUnlessEqual(si["app-versions"], {})
|
|
|
|
self.failUnlessEqual(si["nickname"], u"nick-v1")
|
|
|
|
self.failUnlessEqual(si["my-version"], "my_version")
|
|
|
|
|
|
|
|
class Announcements(unittest.TestCase):
|
|
|
|
def test_client_v2_unsigned(self):
|
|
|
|
introducer = IntroducerService()
|
|
|
|
tub = introducer_furl = None
|
|
|
|
app_versions = {"whizzy": "fizzy"}
|
|
|
|
client_v2 = IntroducerClient(tub, introducer_furl, u"nick-v2",
|
|
|
|
"my_version", "oldest", app_versions)
|
|
|
|
furl1 = "pb://62ubehyunnyhzs7r6vdonnm2hpi52w6y@127.0.0.1:0/swissnum"
|
|
|
|
tubid = "62ubehyunnyhzs7r6vdonnm2hpi52w6y"
|
|
|
|
ann_s0 = make_ann_t(client_v2, furl1, None)
|
|
|
|
canary0 = Referenceable()
|
|
|
|
introducer.remote_publish_v2(ann_s0, canary0)
|
|
|
|
a = introducer.get_announcements()
|
|
|
|
self.failUnlessEqual(len(a), 1)
|
|
|
|
(index, (ann_s, canary, ann, when)) = a.items()[0]
|
|
|
|
self.failUnlessIdentical(canary, canary0)
|
|
|
|
self.failUnlessEqual(index, ("storage", None, tubid))
|
|
|
|
self.failUnlessEqual(ann["app-versions"], app_versions)
|
|
|
|
self.failUnlessEqual(ann["nickname"], u"nick-v2")
|
|
|
|
self.failUnlessEqual(ann["service-name"], "storage")
|
|
|
|
self.failUnlessEqual(ann["my-version"], "my_version")
|
|
|
|
self.failUnlessEqual(ann["anonymous-storage-FURL"], furl1)
|
|
|
|
|
|
|
|
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",
|
|
|
|
"my_version", "oldest", app_versions)
|
|
|
|
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-")
|
|
|
|
ann_t0 = make_ann_t(client_v2, furl1, sk)
|
|
|
|
canary0 = Referenceable()
|
|
|
|
introducer.remote_publish_v2(ann_t0, canary0)
|
|
|
|
a = introducer.get_announcements()
|
|
|
|
self.failUnlessEqual(len(a), 1)
|
|
|
|
(index, (ann_s, canary, ann, when)) = a.items()[0]
|
|
|
|
self.failUnlessIdentical(canary, canary0)
|
|
|
|
self.failUnlessEqual(index, ("storage", pks, None))
|
|
|
|
self.failUnlessEqual(ann["app-versions"], app_versions)
|
|
|
|
self.failUnlessEqual(ann["nickname"], u"nick-v2")
|
|
|
|
self.failUnlessEqual(ann["service-name"], "storage")
|
|
|
|
self.failUnlessEqual(ann["my-version"], "my_version")
|
|
|
|
self.failUnlessEqual(ann["anonymous-storage-FURL"], furl1)
|
|
|
|
|
|
|
|
def test_client_v1(self):
|
|
|
|
introducer = IntroducerService()
|
|
|
|
|
|
|
|
furl1 = "pb://62ubehyunnyhzs7r6vdonnm2hpi52w6y@127.0.0.1:0/swissnum"
|
|
|
|
tubid = "62ubehyunnyhzs7r6vdonnm2hpi52w6y"
|
|
|
|
ann = (furl1, "storage", "RIStorage",
|
|
|
|
u"nick-v1".encode("utf-8"), "my_version", "oldest")
|
|
|
|
introducer.remote_publish(ann)
|
|
|
|
|
|
|
|
a = introducer.get_announcements()
|
|
|
|
self.failUnlessEqual(len(a), 1)
|
|
|
|
(index, (ann_s, canary, ann, when)) = a.items()[0]
|
|
|
|
self.failUnlessEqual(canary, None)
|
|
|
|
self.failUnlessEqual(index, ("storage", None, tubid))
|
|
|
|
self.failUnlessEqual(ann["app-versions"], {})
|
|
|
|
self.failUnlessEqual(ann["nickname"], u"nick-v1".encode("utf-8"))
|
|
|
|
self.failUnlessEqual(ann["service-name"], "storage")
|
|
|
|
self.failUnlessEqual(ann["my-version"], "my_version")
|
|
|
|
self.failUnlessEqual(ann["anonymous-storage-FURL"], furl1)
|
|
|
|
|
|
|
|
|
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",
|
|
|
|
}
|
|
|
|
|
|
|
|
class NonV1Server(SystemTestMixin, unittest.TestCase):
|
|
|
|
# if the 1.3.0 client connects to a server that doesn't provide the 'v1'
|
|
|
|
# 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)
|
|
|
|
l = tub.listenOn("tcp:0")
|
|
|
|
portnum = l.getPortnum()
|
|
|
|
tub.setLocation("localhost:%d" % portnum)
|
|
|
|
|
|
|
|
c = IntroducerClient(tub, self.introducer_furl,
|
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
|
|
|
u"nickname-client", "version", "oldest", {})
|
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
|
|
|
|
|
2009-06-24 19:40:38 +00:00
|
|
|
class DecodeFurl(unittest.TestCase):
|
|
|
|
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")
|
|
|
|
|
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
|
|
|
class Signatures(unittest.TestCase):
|
|
|
|
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
|
|
|
|
self.failUnlessEqual(simplejson.loads(msg.decode("utf-8")), ann)
|
|
|
|
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)
|
|
|
|
|
|
|
|
# bad signature
|
|
|
|
bad_ann = {"key1": "value2"}
|
|
|
|
bad_msg = simplejson.dumps(bad_ann).encode("utf-8")
|
|
|
|
self.failUnlessRaises(keyutil.BadSignatureError,
|
|
|
|
unsign_from_foolscap, (bad_msg,sig,key))
|
|
|
|
# sneaky bad signature should be ignored
|
|
|
|
(ann2,key2) = unsign_from_foolscap( (bad_msg,None,key) )
|
|
|
|
self.failUnlessEqual(key2, None)
|
|
|
|
self.failUnlessEqual(ann2, bad_ann)
|
|
|
|
|
|
|
|
# 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
|