Forráskód Böngészése

Everything in for new multicast except IncomingPacket parsing...

Adam Ierymenko 11 éve
szülő
commit
8607aa7c3c
9 módosított fájl, 98 hozzáadás és 207 törlés
  1. 9 8
      node/Multicaster.cpp
  2. 2 1
      node/Network.cpp
  3. 30 1
      node/Network.hpp
  4. 2 7
      node/Node.cpp
  5. 3 0
      node/OutboundMulticast.cpp
  6. 14 16
      node/Packet.hpp
  7. 34 6
      node/Peer.cpp
  8. 4 146
      node/Switch.cpp
  9. 0 22
      node/Switch.hpp

+ 9 - 8
node/Multicaster.cpp

@@ -56,10 +56,10 @@ void Multicaster::send(const RuntimeEnvironment *RR,uint64_t nwid,const Certific
 		// If we already have enough members, just send and we're done -- no need for TX queue
 		OutboundMulticast out;
 
-		out.init(now,RR->identity.address(),nwid,ZT_MULTICAST_DEFAULT_IMPLICIT_GATHER,src,mg,etherType,data,len);
+		out.init(now,RR->identity.address(),nwid,com,ZT_MULTICAST_DEFAULT_IMPLICIT_GATHER,src,mg,etherType,data,len);
 		unsigned int count = 0;
 		for(std::vector<MulticastGroupMember>::const_reverse_iterator m(gs.members.rbegin());m!=gs.members.rend();++m) {
-			out.sendOnly(*(RR->sw),m->address);
+			out.sendOnly(*(RR->sw),m->address); // sendOnly() avoids overhead of creating sent log since we're going to discard this immediately
 			if (++count >= limit)
 				break;
 		}
@@ -68,25 +68,26 @@ void Multicaster::send(const RuntimeEnvironment *RR,uint64_t nwid,const Certific
 		gs.txQueue.push_back(OutboundMulticast());
 		OutboundMulticast &out = gs.txQueue.back();
 
-		out.init(now,RR->identity.address(),nwid,ZT_MULTICAST_DEFAULT_IMPLICIT_GATHER,src,mg,etherType,data,len);
+		out.init(now,RR->identity.address(),nwid,com,ZT_MULTICAST_DEFAULT_IMPLICIT_GATHER,src,mg,etherType,data,len);
 		for(std::vector<MulticastGroupMember>::const_reverse_iterator m(gs.members.rbegin());m!=gs.members.rend();++m)
 			out.sendAndLog(*(RR->sw),m->address);
 
 		if ((now - gs.lastExplicitGather) >= ZT_MULTICAST_GATHER_DELAY) {
 			gs.lastExplicitGather = now;
 
-			// Explicitly gather -- right now we only do this from supernodes since they
-			// know all multicast group memberships. In the future this might be more
-			// distributed somehow.
+			// TODO / INPROGRESS: right now supernodes track multicast LIKEs, a relic
+			// from the old algorithm. The next step will be to devolve this duty
+			// somewhere else, such as node(s) nominated by netconf masters. But
+			// we'll keep announcing LIKEs to supernodes for the near future to
+			// gradually migrate from old multicast to new without losing old nodes.
 			SharedPtr<Peer> sn(RR->topology->getBestSupernode());
 			if (sn) {
 				Packet outp(sn->address(),RR->identity.address(),Packet::VERB_MULTICAST_GATHER);
 				outp.append(nwid);
-				outp.append((uint8_t)((com) ? 0x01: 0x00));
+				outp.append((uint8_t)0);
 				mg.mac().appendTo(outp);
 				outp.append((uint32_t)mg.adi());
 				outp.append((uint32_t)((limit - (unsigned int)gs.members.size()) + 1)); // +1 just means we'll have an extra in the queue if available
-				if (com) com->serialize(outp);
 				outp.armor(sn->key(),true);
 				sn->send(RR,outp.data(),outp.size(),now);
 			}

+ 2 - 1
node/Network.cpp

@@ -453,7 +453,8 @@ void Network::_CBhandleTapData(void *arg,const MAC &from,const MAC &to,unsigned
 
 void Network::_pushMembershipCertificate(const Address &peer,bool force,uint64_t now)
 {
-	// assumes _lock is locked
+	// assumes _lock is locked and _config is not null
+
 	uint64_t pushTimeout = _config->com().timestampMaxDelta() / 2;
 
 	// Zero means we're still waiting on our own cert

+ 30 - 1
node/Network.hpp

@@ -148,7 +148,7 @@ public:
 	}
 
 	/**
-	 * Update multicast groups for this network's tap
+	 * Update multicast groups for this network's tap and announce changes
 	 *
 	 * @return True if internal multicast group set has changed since last update
 	 */
@@ -227,6 +227,35 @@ public:
 			_pushMembershipCertificate(peer,force,now);
 	}
 
+	/**
+	 * Send a multicast packet to the members of a group
+	 *
+	 * This performs no rate checking or other permission checking.
+	 *
+	 * @param mg Multicast group destination
+	 * @param src Source Ethernet MAC address
+	 * @param etherType Ethernet frame type
+	 * @param data Payload data
+	 * @param len Length of payload
+	 */
+	inline void sendMulticast(const MulticastGroup &mg,const MAC &src,unsigned int etherType,const void *data,unsigned int len)
+	{
+		Mutex::Lock _l(_lock);
+		if (!_config)
+			return;
+		_multicaster.send(
+			RR,
+			_id,
+			(((!_config->isPublic())&&(_config->com())) ? &(_config->com()) : (const CertificateOfMembership *)0),
+			_config->multicastLimit(),
+			Utils::now(),
+			mg,
+			src,
+			etherType,
+			data,
+			len);
+	}
+
 	/**
 	 * @param peer Peer address to check
 	 * @return True if peer is allowed to communicate on this network

+ 2 - 7
node/Node.cpp

@@ -565,14 +565,9 @@ Node::ReasonForTermination Node::run()
 				if ((now - lastMulticastCheck) >= ZT_MULTICAST_LOCAL_POLL_PERIOD) {
 					lastMulticastCheck = now;
 					try {
-						std::map< SharedPtr<Network>,std::set<MulticastGroup> > toAnnounce;
 						std::vector< SharedPtr<Network> > networks(RR->nc->networks());
-						for(std::vector< SharedPtr<Network> >::const_iterator nw(networks.begin());nw!=networks.end();++nw) {
-							if ((*nw)->updateMulticastGroups())
-								toAnnounce.insert(std::pair< SharedPtr<Network>,std::set<MulticastGroup> >(*nw,(*nw)->multicastGroups()));
-						}
-						if (toAnnounce.size())
-							RR->sw->announceMulticastGroups(toAnnounce);
+						for(std::vector< SharedPtr<Network> >::const_iterator nw(networks.begin());nw!=networks.end();++nw)
+							(*nw)->updateMulticastGroups());
 					} catch (std::exception &exc) {
 						LOG("unexpected exception announcing multicast groups: %s",exc.what());
 					} catch ( ... ) {

+ 3 - 0
node/OutboundMulticast.cpp

@@ -39,8 +39,10 @@ void OutboundMulticast::init(uint64_t timestamp,const Address &self,uint64_t nwi
 	_source = src;
 	_destination = dest;
 	_etherType = etherType;
+
 	_packet.setSource(self);
 	_packet.setVerb(Packet::VERB_MULTICAST_FRAME);
+
 	_packet.append((uint64_t)nwid);
 	_packet.append((uint8_t)((com) ? 0x01 : 0x00));
 	_packet.append((uint32_t)gatherLimit); // gather limit -- set before send, start with 0
@@ -50,6 +52,7 @@ void OutboundMulticast::init(uint64_t timestamp,const Address &self,uint64_t nwi
 	src.appendTo(_packet);
 	_packet.append((uint16_t)etherType);
 	_packet.append(payload,len);
+
 	_packet.compress();
 }
 

+ 14 - 16
node/Packet.hpp

@@ -513,13 +513,15 @@ public:
 		 */
 		VERB_RENDEZVOUS = 5,
 
-		/* A ZT-to-ZT unicast ethernet frame (shortened EXT_FRAME):
+		/* ZT-to-ZT unicast ethernet frame (shortened EXT_FRAME):
 		 *   <[8] 64-bit network ID>
 		 *   <[2] 16-bit ethertype>
 		 *   <[...] ethernet payload>
 		 *
 		 * MAC addresses are derived from the packet's source and destination
-		 * ZeroTier addresses.
+		 * ZeroTier addresses. This is a shortened EXT_FRAME that elides full
+		 * Ethernet framing and other optional flags and features when they
+		 * are not necessary.
 		 *
 		 * ERROR may be generated if a membership certificate is needed for a
 		 * closed network. Payload will be network ID.
@@ -527,17 +529,21 @@ public:
 		VERB_FRAME = 6,
 
 		/*
-		 * An ethernet frame to or from specified MAC addresses:
+		 * Full Ethernet frame with MAC addressing and optional fields:
 		 *   <[8] 64-bit network ID>
-		 *   <[1] flags (currently unused, must be 0)>
+		 *   <[1] flags>
+		 *  [<[...] certificate of network membership>]
 		 *   <[6] destination MAC or all zero for destination node>
 		 *   <[6] source MAC or all zero for node of origin>
 		 *   <[2] 16-bit ethertype>
 		 *   <[...] ethernet payload>
 		 *
-		 * Extended frames include full MAC addressing and are used for bridged
-		 * configurations. Theoretically they could carry multicast as well but
-		 * currently they're not used for that.
+		 * Flags:
+		 *   0x01 - Certificate of network membership is attached
+		 *
+		 * An extended frame carries full MAC addressing, making them a
+		 * superset of VERB_FRAME. They're used for bridging or when we
+		 * want to attach a certificate since FRAME does not support that.
 		 *
 		 * ERROR may be generated if a membership certificate is needed for a
 		 * closed network. Payload will be network ID.
@@ -678,24 +684,16 @@ public:
 
 		/* Request endpoints for multicast distribution:
 		 *   <[8] 64-bit network ID>
-		 *   <[1] flags>
+		 *   <[1] flags (unused, must be 0)>
 		 *   <[6] MAC address of multicast group being queried>
 		 *   <[4] 32-bit ADI for multicast group being queried>
 		 *   <[4] 32-bit (suggested) max number of multicast peers desired or 0 for no limit>
-		 *  [<[...] network certificate of membership if included>]
-		 *
-		 * Flags:
-		 *   0x01 - Network certificate of membership is attached
 		 *
 		 * This message asks a peer for additional known endpoints that have
 		 * LIKEd a given multicast group. It's sent when the sender wishes
 		 * to send multicast but does not have the desired number of recipient
 		 * peers.
 		 *
-		 * A certificate of network membership can be included so that peers
-		 * can check network membership before responding. Without certificate
-		 * check any peer could probe multicast memberships on any network.
-		 *
 		 * OK response payload:
 		 *   <[8] 64-bit network ID>
 		 *   <[6] MAC address of multicast group being queried>

+ 34 - 6
node/Peer.cpp

@@ -28,6 +28,9 @@
 #include "Constants.hpp"
 #include "Peer.hpp"
 #include "Switch.hpp"
+#include "Packet.hpp"
+#include "Network.hpp"
+#include "NodeConfig.hpp"
 #include "AntiRecursion.hpp"
 
 #include <algorithm>
@@ -76,14 +79,14 @@ void Peer::receive(
 	// Update system-wide last packet receive time
 	*((const_cast<uint64_t *>(&(RR->timeOfLastPacketReceived)))) = now;
 
+	Mutex::Lock _l(_lock);
+
 	// Global last receive time regardless of path
 	_lastReceive = now;
 
-	// Learn paths from direct packets (hops == 0)
 	if (!hops) {
+		// Learn paths from direct packets (hops == 0)
 		{
-			Mutex::Lock _l(_lock);
-
 			bool havePath = false;
 			for(std::vector<Path>::iterator p(_paths.begin());p!=_paths.end();++p) {
 				if ((p->address() == remoteAddr)&&(p->tcp() == fromSock->tcp())) {
@@ -110,11 +113,36 @@ void Peer::receive(
 			}
 		}
 
-		// Announce multicast LIKEs to peers to whom we have a direct link
-		// Lock can't be locked here or it'll recurse and deadlock.
+		// Announce multicast groups of interest to direct peers if they are
+		// considered authorized members of a given network. Also announce to
+		// supernodes and network controllers. TODO: the former may go
+		// obsolete with time as network controllers take over this role.
 		if ((now - _lastAnnouncedTo) >= ((ZT_MULTICAST_LIKE_EXPIRE / 2) - 1000)) {
 			_lastAnnouncedTo = now;
-			RR->sw->announceMulticastGroups(SharedPtr<Peer>(this));
+
+			Packet outp(_id.address(),RR->identity.address(),Packet::VERB_MULTICAST_LIKE);
+			std::vector< SharedPtr<Network> > networks(RR->nc->networks());
+			for(std::vector< SharedPtr<Network> >::iterator n(networks.begin());n!=networks.end();++n) {
+				if ( ((*n)->isAllowed(_id.address())) || ((*n)->controller() == _id.address()) || (RR->topology->isSupernode(_id.address())) ) {
+					std::set<MulticastGroup> mgs((*n)->multicastGroups());
+					for(std::set<MulticastGroup>::iterator mg(mgs.begin());mg!=mgs.end();++mg) {
+						if ((outp.size() + 18) > ZT_UDP_DEFAULT_PAYLOAD_MTU) {
+							outp.armor(_key,true);
+							fromSock->send(remoteAddr,outp.data(),outp.size());
+							outp.reset(_id.address(),RR->identity.address(),Packet::VERB_MULTICAST_LIKE);
+						}
+
+						// network ID, MAC, ADI
+						outp.append((uint64_t)(*n)->id());
+						mg->mac().appendTo(outp);
+						outp.append((uint32_t)mg->adi());
+					}
+				}
+			}
+			if (outp.size() > ZT_PROTO_MIN_PACKET_LENGTH) {
+				outp.armor(_key,true);
+				fromSock->send(remoteAddr,outp.data(),outp.size());
+			}
 		}
 	}
 

+ 4 - 146
node/Switch.cpp

@@ -143,96 +143,20 @@ void Switch::onLocalEthernet(const SharedPtr<Network> &network,const MAC &from,c
 			network->learnBridgedMulticastGroup(mg,now);
 
 		// Check multicast/broadcast bandwidth quotas and reject if quota exceeded
-		if (!network->updateAndCheckMulticastBalance(RR->identity.address(),mg,data.size())) {
+		if (!network->updateAndCheckMulticastBalance(mg,data.size())) {
 			TRACE("%s: didn't multicast %d bytes, quota exceeded for multicast group %s",network->tapDeviceName().c_str(),(int)data.size(),mg.toString().c_str());
 			return;
 		}
 
 		TRACE("%s: MULTICAST %s -> %s %s %d",network->tapDeviceName().c_str(),from.toString().c_str(),mg.toString().c_str(),etherTypeName(etherType),(int)data.size());
 
-		/* old P5 multicast algorithm
-		const unsigned int mcid = ++_multicastIdCounter & 0xffffff;
-		const uint16_t bloomNonce = (uint16_t)(RR->prng->next32() & 0xffff); // doesn't need to be cryptographically strong
-		unsigned char bloom[ZT_PROTO_VERB_MULTICAST_FRAME_LEN_PROPAGATION_BLOOM];
-		unsigned char fifo[ZT_PROTO_VERB_MULTICAST_FRAME_LEN_PROPAGATION_FIFO + ZT_ADDRESS_LENGTH]; // extra ZT_ADDRESS_LENGTH is for first hop, not put in packet but serves as destination for packet
-		unsigned char *const fifoEnd = fifo + sizeof(fifo);
-		const unsigned int signedPartLen = (ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FRAME - ZT_PROTO_VERB_MULTICAST_FRAME_IDX__START_OF_SIGNED_PORTION) + data.size();
-		const SharedPtr<Peer> supernode(RR->topology->getBestSupernode());
-
-		// For each bit prefix send a packet to a list of destinations within it
-		for(unsigned int prefix=0,np=((unsigned int)2 << (nconf->multicastPrefixBits() - 1));prefix<np;++prefix) {
-			memset(bloom,0,sizeof(bloom));
-			unsigned char *fifoPtr = fifo;
-
-			// Add all active bridges and then next hops we know about to propagation queue
-			Multicaster::AddToPropagationQueue appender(
-				&fifoPtr,
-				fifoEnd,
-				bloom,
-				bloomNonce,
-				RR->identity.address(),
-				nconf->multicastPrefixBits(),
-				prefix,
-				RR->topology,
-				now);
-			for(std::set<Address>::const_iterator ab(nconf->activeBridges().begin());ab!=nconf->activeBridges().end();++ab) {
-				if (!appender(*ab))
-					break;
-			}
-			RR->mc->getNextHops(network->id(),mg,appender);
-
-			// Pad remainder of FIFO with zeroes
-			while (fifoPtr != fifoEnd)
-				*(fifoPtr++) = (unsigned char)0;
-
-			// First element in FIFO is first hop, rest of FIFO is sent in packet *to* first hop
-			Address firstHop(fifo,ZT_ADDRESS_LENGTH);
-			if (!firstHop) {
-				if (supernode)
-					firstHop = supernode->address();
-				else continue; // nowhere to go
-			}
-
-			Packet outp(firstHop,RR->identity.address(),Packet::VERB_MULTICAST_FRAME);
-			outp.append((uint16_t)0);
-			outp.append(fifo + ZT_ADDRESS_LENGTH,ZT_PROTO_VERB_MULTICAST_FRAME_LEN_PROPAGATION_FIFO); // remainder of fifo is loaded into packet
-			outp.append(bloom,ZT_PROTO_VERB_MULTICAST_FRAME_LEN_PROPAGATION_BLOOM);
-			outp.append((nconf->com()) ? (unsigned char)ZT_PROTO_VERB_MULTICAST_FRAME_FLAGS_HAS_MEMBERSHIP_CERTIFICATE : (unsigned char)0);
-			outp.append(network->id());
-			outp.append(bloomNonce);
-			outp.append((unsigned char)nconf->multicastPrefixBits());
-			outp.append((unsigned char)prefix);
-			RR->identity.address().appendTo(outp); // lower 40 bits of MCID are my address
-			outp.append((unsigned char)((mcid >> 16) & 0xff));
-			outp.append((unsigned char)((mcid >> 8) & 0xff));
-			outp.append((unsigned char)(mcid & 0xff)); // upper 24 bits of MCID are from our counter
-			from.appendTo(outp);
-			mg.mac().appendTo(outp);
-			outp.append(mg.adi());
-			outp.append((uint16_t)etherType);
-			outp.append((uint16_t)data.size());
-			outp.append(data);
-
-			C25519::Signature sig(RR->identity.sign(outp.field(ZT_PROTO_VERB_MULTICAST_FRAME_IDX__START_OF_SIGNED_PORTION,signedPartLen),signedPartLen));
-			outp.append((uint16_t)sig.size());
-			outp.append(sig.data,(unsigned int)sig.size());
-
-			// FIXME: now we send the netconf cert with every single multicast,
-			// which pretty much ensures everyone has it ahead of time but adds
-			// some redundant payload. Maybe think abouut this in the future.
-			if (nconf->com())
-				nconf->com().serialize(outp);
-
-			outp.compress();
-			send(outp,true);
-		}
-		*/
+		network->sendMulticast(mg,from,etherType,data.data(),data.size());
 
 		return;
 	}
 
 	if (to[0] == MAC::firstOctetForNetwork(network->id())) {
-		// Destination is another ZeroTier node
+		// Destination is another ZeroTier peer
 
 		Address toZT(to.toAddress(network->id()));
 		if (network->isAllowed(toZT)) {
@@ -266,7 +190,7 @@ void Switch::onLocalEthernet(const SharedPtr<Network> &network,const MAC &from,c
 	}
 
 	{
-		// Destination is behind another bridge
+		// Destination is bridged behind a remote peer
 
 		Address bridges[ZT_MAX_BRIDGE_SPAM];
 		unsigned int numBridges = 0;
@@ -477,72 +401,6 @@ void Switch::contact(const SharedPtr<Peer> &peer,const InetAddress &atAddr)
 	RR->sm->whack();
 }
 
-void Switch::announceMulticastGroups(const std::map< SharedPtr<Network>,std::set<MulticastGroup> > &allMemberships)
-{
-	std::vector< SharedPtr<Peer> > directPeers;
-	RR->topology->eachPeer(Topology::CollectPeersWithActiveDirectPath(directPeers,Utils::now()));
-
-#ifdef ZT_TRACE
-	unsigned int totalMulticastGroups = 0;
-	for(std::map< SharedPtr<Network>,std::set<MulticastGroup> >::const_iterator i(allMemberships.begin());i!=allMemberships.end();++i)
-		totalMulticastGroups += (unsigned int)i->second.size();
-	TRACE("announcing %u multicast groups for %u networks to %u peers",totalMulticastGroups,(unsigned int)allMemberships.size(),(unsigned int)directPeers.size());
-#endif
-
-	uint64_t now = Utils::now();
-	for(std::vector< SharedPtr<Peer> >::iterator p(directPeers.begin());p!=directPeers.end();++p) {
-		Packet outp((*p)->address(),RR->identity.address(),Packet::VERB_MULTICAST_LIKE);
-
-		for(std::map< SharedPtr<Network>,std::set<MulticastGroup> >::const_iterator nwmgs(allMemberships.begin());nwmgs!=allMemberships.end();++nwmgs) {
-			nwmgs->first->pushMembershipCertificate((*p)->address(),false,now);
-
-			if ((RR->topology->isSupernode((*p)->address()))||(nwmgs->first->isAllowed((*p)->address()))) {
-				for(std::set<MulticastGroup>::iterator mg(nwmgs->second.begin());mg!=nwmgs->second.end();++mg) {
-					if ((outp.size() + 18) > ZT_UDP_DEFAULT_PAYLOAD_MTU) {
-						send(outp,true);
-						outp.reset((*p)->address(),RR->identity.address(),Packet::VERB_MULTICAST_LIKE);
-					}
-
-					// network ID, MAC, ADI
-					outp.append((uint64_t)nwmgs->first->id());
-					mg->mac().appendTo(outp);
-					outp.append((uint32_t)mg->adi());
-				}
-			}
-		}
-
-		if (outp.size() > ZT_PROTO_MIN_PACKET_LENGTH)
-			send(outp,true);
-	}
-}
-
-void Switch::announceMulticastGroups(const SharedPtr<Peer> &peer)
-{
-	Packet outp(peer->address(),RR->identity.address(),Packet::VERB_MULTICAST_LIKE);
-	std::vector< SharedPtr<Network> > networks(RR->nc->networks());
-	uint64_t now = Utils::now();
-	for(std::vector< SharedPtr<Network> >::iterator n(networks.begin());n!=networks.end();++n) {
-		if (((*n)->isAllowed(peer->address()))||(RR->topology->isSupernode(peer->address()))) {
-			(*n)->pushMembershipCertificate(peer->address(),false,now);
-
-			std::set<MulticastGroup> mgs((*n)->multicastGroups());
-			for(std::set<MulticastGroup>::iterator mg(mgs.begin());mg!=mgs.end();++mg) {
-				if ((outp.size() + 18) > ZT_UDP_DEFAULT_PAYLOAD_MTU) {
-					send(outp,true);
-					outp.reset(peer->address(),RR->identity.address(),Packet::VERB_MULTICAST_LIKE);
-				}
-
-				// network ID, MAC, ADI
-				outp.append((uint64_t)(*n)->id());
-				mg->mac().appendTo(outp);
-				outp.append((uint32_t)mg->adi());
-			}
-		}
-	}
-	if (outp.size() > ZT_PROTO_MIN_PACKET_LENGTH)
-		send(outp,true);
-}
-
 void Switch::requestWhois(const Address &addr)
 {
 	//TRACE("requesting WHOIS for %s",addr.toString().c_str());

+ 0 - 22
node/Switch.hpp

@@ -165,28 +165,6 @@ public:
 	 */
 	void contact(const SharedPtr<Peer> &peer,const InetAddress &atAddr);
 
-	/**
-	 * Announce multicast group memberships
-	 *
-	 * This announces all the groups for all the networks in the supplied map to
-	 * all peers with whom we have an active direct link. Only isAllowed() peers
-	 * and supernodes get announcements for each given network.
-	 *
-	 * @param allMemberships Memberships for a number of networks
-	 */
-	void announceMulticastGroups(const std::map< SharedPtr<Network>,std::set<MulticastGroup> > &allMemberships);
-
-	/**
-	 * Announce multicast group memberships
-	 *
-	 * This announces all current multicast memberships to a single peer. Only
-	 * memberships for networks where the peer isAllowed() are included, unless
-	 * the peer is a supernode.
-	 *
-	 * @param peer Peer to announce all memberships to
-	 */
-	void announceMulticastGroups(const SharedPtr<Peer> &peer);
-
 	/**
 	 * Request WHOIS on a given address
 	 *