def testNameLookup(self): t1 = HelperTarget() t2 = HelperTarget() self.names["foo"] = t1 self.names2["bar"] = t2 self.names2["baz"] = t2 self.tubB.registerNameLookupHandler(self.lookup) self.tubB.registerNameLookupHandler(self.lookup2) # hack up a new furl pointing at the same tub but with a name that # hasn't been registered. s = SturdyRef(self.url_on_b) s.name = "foo" d = self.tubA.getReference(s) def _check(res): self.assertTrue(isinstance(res, RemoteReference)) self.assertEqual(self.lookups, ["foo"]) # the first lookup should short-circuit the process self.assertEqual(self.lookups2, []) self.lookups = []; self.lookups2 = [] s.name = "bar" return self.tubA.getReference(s) d.addCallback(_check) def _check2(res): self.assertTrue(isinstance(res, RemoteReference)) # if the first lookup fails, the second handler should be asked self.assertEqual(self.lookups, ["bar"]) self.assertEqual(self.lookups2, ["bar"]) self.lookups = []; self.lookups2 = [] # make sure that loopbacks use this too return self.tubB.getReference(s) d.addCallback(_check2) def _check3(res): self.assertTrue(isinstance(res, RemoteReference)) self.assertEqual(self.lookups, ["bar"]) self.assertEqual(self.lookups2, ["bar"]) self.lookups = []; self.lookups2 = [] # and make sure we can de-register handlers self.tubB.unregisterNameLookupHandler(self.lookup) s.name = "baz" return self.tubA.getReference(s) d.addCallback(_check3) def _check4(res): self.assertTrue(isinstance(res, RemoteReference)) self.assertEqual(self.lookups, []) self.assertEqual(self.lookups2, ["baz"]) self.lookups = []; self.lookups2 = [] d.addCallback(_check4) return d
def testNameLookup(self): t1 = HelperTarget() t2 = HelperTarget() self.names["foo"] = t1 self.names2["bar"] = t2 self.names2["baz"] = t2 self.tubB.registerNameLookupHandler(self.lookup) self.tubB.registerNameLookupHandler(self.lookup2) # hack up a new furl pointing at the same tub but with a name that # hasn't been registered. s = SturdyRef(self.url_on_b) s.name = "foo" d = self.tubA.getReference(s) def _check(res): self.failUnless(isinstance(res, RemoteReference)) self.failUnlessEqual(self.lookups, ["foo"]) # the first lookup should short-circuit the process self.failUnlessEqual(self.lookups2, []) self.lookups = []; self.lookups2 = [] s.name = "bar" return self.tubA.getReference(s) d.addCallback(_check) def _check2(res): self.failUnless(isinstance(res, RemoteReference)) # if the first lookup fails, the second handler should be asked self.failUnlessEqual(self.lookups, ["bar"]) self.failUnlessEqual(self.lookups2, ["bar"]) self.lookups = []; self.lookups2 = [] # make sure that loopbacks use this too return self.tubB.getReference(s) d.addCallback(_check2) def _check3(res): self.failUnless(isinstance(res, RemoteReference)) self.failUnlessEqual(self.lookups, ["bar"]) self.failUnlessEqual(self.lookups2, ["bar"]) self.lookups = []; self.lookups2 = [] # and make sure we can de-register handlers self.tubB.unregisterNameLookupHandler(self.lookup) s.name = "baz" return self.tubA.getReference(s) d.addCallback(_check3) def _check4(res): self.failUnless(isinstance(res, RemoteReference)) self.failUnlessEqual(self.lookups, []) self.failUnlessEqual(self.lookups2, ["baz"]) self.lookups = []; self.lookups2 = [] d.addCallback(_check4) return d
def _publish(self, announcement): self._debug_counts["inbound_message"] += 1 self.log("introducer: announcement published: %s" % (announcement,) ) (furl, service_name, ri_name, nickname_utf8, ver, oldest) = announcement #print "PUB", service_name, nickname_utf8 nodeid = b32decode(SturdyRef(furl).tubID.upper()) index = (service_name, nodeid) if index in self._announcements: (old_announcement, timestamp) = self._announcements[index] if old_announcement == announcement: self.log("but we already knew it, ignoring", level=log.NOISY) self._debug_counts["inbound_duplicate"] += 1 return else: self.log("old announcement being updated", level=log.NOISY) self._debug_counts["inbound_update"] += 1 self._announcements[index] = (announcement, time.time()) for s in self._subscribers.get(service_name, []): self._debug_counts["outbound_message"] += 1 self._debug_counts["outbound_announcements"] += 1 self._debug_outstanding += 1 d = s.callRemote("announce", set([announcement])) d.addBoth(self._debug_retired) d.addErrback(rrefutil.trap_deadref) d.addErrback(log.err, format="subscriber errored on announcement %(ann)s", ann=announcement, facility="tahoe.introducer", level=log.UNUSUAL, umid="jfGMXQ")
def test_wait_for_brokers(self): """ The L{Deferred} returned by L{Tub.stopService} fires only after the L{Broker} connections belonging to the L{Tub} have disconnected. """ tub = Tub() tub.startService() another_tub = Tub() another_tub.startService() brokers = list(tub.brokerClass(None) for i in range(3)) for n, b in enumerate(brokers): b.makeConnection(StringTransport()) ref = SturdyRef(encode_furl(another_tub.tubID, [], str(n))) tub.brokerAttached(ref, b, isClient=(n % 2) == 1) stopping = tub.stopService() d = flushEventualQueue() def event(ignored): self.assertNoResult(stopping) for b in brokers: b.connectionLost(failure.Failure(Exception("Connection lost"))) return flushEventualQueue() d.addCallback(event) def connectionsLost(ignored): self.successResultOf(stopping) d.addCallback(connectionsLost) return d
def hosts_for_furl(furl, ignore_localhost=True): advertised = [] for hint in SturdyRef(furl).locationHints: assert not isinstance(hint, str), hint if hint[0] == "ipv4": host = hint[1] if ignore_localhost and host == "127.0.0.1": continue advertised.append(host) return advertised
def _process_announcement(self, ann): self._debug_counts["inbound_announcement"] += 1 (furl, service_name, ri_name, nickname_utf8, ver, oldest) = ann if service_name not in self._subscribed_service_names: self.log("announcement for a service we don't care about [%s]" % (service_name, ), level=log.UNUSUAL, umid="dIpGNA") self._debug_counts["wrong_service"] += 1 return self.log("announcement for [%s]: %s" % (service_name, ann), umid="BoKEag") assert type(furl) is str assert type(service_name) is str assert type(ri_name) is str assert type(nickname_utf8) is str nickname = nickname_utf8.decode("utf-8") assert type(nickname) is unicode assert type(ver) is str assert type(oldest) is str nodeid = b32decode(SturdyRef(furl).tubID.upper()) nodeid_s = idlib.shortnodeid_b2a(nodeid) ann_d = { "version": 0, "service-name": service_name, "FURL": furl, "nickname": nickname, "app-versions": {}, # need #466 and v2 introducer "my-version": ver, "oldest-supported": oldest, } index = (service_name, nodeid) if self._current_announcements.get(index, None) == ann_d: self.log("reannouncement for [%(service)s]:%(nodeid)s, ignoring", service=service_name, nodeid=nodeid_s, level=log.UNUSUAL, umid="B1MIdA") self._debug_counts["duplicate_announcement"] += 1 return if index in self._current_announcements: self._debug_counts["update"] += 1 else: self._debug_counts["new_announcement"] += 1 self._current_announcements[index] = ann_d # note: we never forget an index, but we might update its value for (service_name2, cb, args, kwargs) in self._local_subscribers: if service_name2 == service_name: eventually(cb, nodeid, ann_d, *args, **kwargs)
def _check(furl): sr = SturdyRef(furl) portnum = l.getPortnum() if sr.encrypted: for lh in sr.locationHints: self.failUnlessEqual(lh[2], portnum, lh) self.failUnless(("ipv4", "127.0.0.1", portnum) in sr.locationHints) else: # TODO: unauthenticated tubs need review, I think they # deserve to have tubids and multiple connection hints pass
def connection_hints_for_furl(furl): hints = [] for h in SturdyRef(furl).locationHints: # Foolscap-0.2.5 and earlier used strings in .locationHints, 0.2.6 # through 0.6.4 used tuples of ("ipv4",host,port), 0.6.5 through # 0.8.0 used tuples of ("tcp",host,port), and >=0.9.0 uses strings # again. Tolerate them all. if isinstance(h, tuple): hints.append(":".join([str(s) for s in h])) else: hints.append(h) return hints
def data_subscribers(self, ctx, data): # use the "stub_client" announcements to get information per nodeid clients = {} for (ann,when) in self.introducer_service.get_announcements().values(): if ann[1] != "stub_client": continue (furl, service_name, ri_name, nickname, ver, oldest) = ann sr = SturdyRef(furl) nodeid = sr.tubID clients[nodeid] = ann # then we actually provide information per subscriber s = [] introsvc = self.introducer_service for service_name, subscribers in introsvc.get_subscribers().items(): for (rref, timestamp) in subscribers.items(): sr = rref.getSturdyRef() nodeid = sr.tubID ann = clients.get(nodeid) s.append( (service_name, rref, timestamp, ann) ) s.sort() return s
def render_JSON(self, ctx): res = {} clients = self.introducer_service.get_subscribers() subscription_summary = dict([ (name, len(clients[name])) for name in clients ]) res["subscription_summary"] = subscription_summary announcement_summary = {} service_hosts = {} for (ann,when) in self.introducer_service.get_announcements().values(): (furl, service_name, ri_name, nickname, ver, oldest) = ann if service_name not in announcement_summary: announcement_summary[service_name] = 0 announcement_summary[service_name] += 1 if service_name not in service_hosts: service_hosts[service_name] = set() # it's nice to know how many distinct hosts are available for # each service. We define a "host" by a set of addresses # (hostnames or ipv4 addresses), which we extract from the # connection hints. In practice, this is usually close # enough: when multiple services are run on a single host, # they're usually either configured with the same addresses, # or setLocationAutomatically picks up the same interfaces. locations = SturdyRef(furl).getTubRef().getLocations() # list of tuples, ("ipv4", host, port) host = frozenset([hint[1] for hint in locations if hint[0] == "ipv4"]) service_hosts[service_name].add(host) res["announcement_summary"] = announcement_summary distinct_hosts = dict([(name, len(hosts)) for (name, hosts) in service_hosts.iteritems()]) res["announcement_distinct_hosts"] = distinct_hosts return simplejson.dumps(res, indent=1) + "\n"
class IntroducerRoot(rend.Page): addSlash = True docFactory = getxmlfile("introducer.xhtml") child_operations = None def __init__(self, introducer_node): self.introducer_node = introducer_node self.introducer_service = introducer_node.getServiceNamed("introducer") rend.Page.__init__(self, introducer_node) def renderHTTP(self, ctx): t = get_arg(inevow.IRequest(ctx), "t") if t == "json": return self.render_JSON(ctx) return rend.Page.renderHTTP(self, ctx) def render_JSON(self, ctx): res = {} clients = self.introducer_service.get_subscribers() subscription_summary = dict([ (name, len(clients[name])) for name in clients ]) res["subscription_summary"] = subscription_summary announcement_summary = {} service_hosts = {} for (ann,when) in self.introducer_service.get_announcements().values(): (furl, service_name, ri_name, nickname, ver, oldest) = ann if service_name not in announcement_summary: announcement_summary[service_name] = 0 announcement_summary[service_name] += 1 if service_name not in service_hosts: service_hosts[service_name] = set() # it's nice to know how many distinct hosts are available for # each service. We define a "host" by a set of addresses # (hostnames or ipv4 addresses), which we extract from the # connection hints. In practice, this is usually close # enough: when multiple services are run on a single host, # they're usually either configured with the same addresses, # or setLocationAutomatically picks up the same interfaces. locations = SturdyRef(furl).getTubRef().getLocations() # list of tuples, ("ipv4", host, port) host = frozenset([hint[1] for hint in locations if hint[0] == "ipv4"]) service_hosts[service_name].add(host) res["announcement_summary"] = announcement_summary distinct_hosts = dict([(name, len(hosts)) for (name, hosts) in service_hosts.iteritems()]) res["announcement_distinct_hosts"] = distinct_hosts return simplejson.dumps(res, indent=1) + "\n" # FIXME: This code is duplicated in root.py and introweb.py. def data_version(self, ctx, data): return get_package_versions_string() def data_import_path(self, ctx, data): return str(allmydata).replace("/", "/ ") # XXX kludge for wrapping def data_my_nodeid(self, ctx, data): return idlib.nodeid_b2a(self.introducer_node.nodeid) def render_announcement_summary(self, ctx, data): services = {} for (ann,when) in self.introducer_service.get_announcements().values(): (furl, service_name, ri_name, nickname, ver, oldest) = ann if service_name not in services: services[service_name] = 0 services[service_name] += 1 service_names = services.keys() service_names.sort() return ", ".join(["%s: %d" % (service_name, services[service_name]) for service_name in service_names]) def render_client_summary(self, ctx, data): clients = self.introducer_service.get_subscribers() service_names = clients.keys() service_names.sort() return ", ".join(["%s: %d" % (service_name, len(clients[service_name])) for service_name in service_names]) def data_services(self, ctx, data): introsvc = self.introducer_service ann = [(since,a) for (a,since) in introsvc.get_announcements().values() if a[1] != "stub_client"] ann.sort(lambda a,b: cmp( (a[1][1], a), (b[1][1], b) ) ) return ann def render_service_row(self, ctx, (since,announcement)): (furl, service_name, ri_name, nickname, ver, oldest) = announcement sr = SturdyRef(furl) nodeid = sr.tubID advertised = self.show_location_hints(sr) ctx.fillSlots("peerid", "%s %s" % (nodeid, nickname)) ctx.fillSlots("advertised", " ".join(advertised)) ctx.fillSlots("connected", "?") TIME_FORMAT = "%H:%M:%S %d-%b-%Y" ctx.fillSlots("announced", time.strftime(TIME_FORMAT, time.localtime(since))) ctx.fillSlots("version", ver) ctx.fillSlots("service_name", service_name) return ctx.tag
def _check(furl): sr = SturdyRef(furl) portnum = l.getPortnum() for lh in sr.locationHints: self.failUnlessEqual(lh[2], portnum, lh) self.failUnless(("tcp", "127.0.0.1", portnum) in sr.locationHints)