private DhtRpcPacket Query(DhtRpcPacket query, NodeContact contact) { Stream s = null; try { if (contact.IsCurrentNode) { return(ProcessQuery(query, contact.NodeEP)); } s = _manager.GetConnection(contact.NodeEP); //set timeout s.WriteTimeout = _queryTimeout; s.ReadTimeout = _queryTimeout; //send query query.WriteTo(new BinaryWriter(s)); s.Flush(); Debug.Write(this.GetType().Name, "query sent to: " + contact.ToString()); //read response DhtRpcPacket response = new DhtRpcPacket(new BinaryReader(s)); Debug.Write(this.GetType().Name, "response received from: " + contact.ToString()); //auto add contact or update last seen time { NodeContact bucketContact = _routingTable.FindContact(contact.NodeId); if (bucketContact == null) { contact.UpdateLastSeenTime(); _routingTable.AddContact(contact); } else { bucketContact.UpdateLastSeenTime(); } } return(response); } catch (Exception ex) { Debug.Write(this.GetType().Name, ex); contact.IncrementRpcFailCount(); return(null); } finally { if (s != null) { s.Dispose(); } } }
private EndPoint[] QueryAnnounce(NodeContact[] initialContacts, BinaryNumber networkId, EndPoint serviceEP) { NodeContact[] contacts = QueryFindNode(initialContacts, networkId); if ((contacts == null) || (contacts.Length == 0)) { return(null); } List <EndPoint> peers = new List <EndPoint>(); lock (peers) { int respondedContacts = 0; foreach (NodeContact contact in contacts) { ThreadPool.QueueUserWorkItem(delegate(object state) { DhtRpcPacket response = Query(DhtRpcPacket.CreateAnnouncePeerPacketQuery(_currentNode, networkId, serviceEP), contact); if ((response != null) && (response.Type == DhtRpcType.ANNOUNCE_PEER) && (response.Peers.Length > 0)) { lock (peers) { foreach (EndPoint peer in response.Peers) { if (!peers.Contains(peer)) { peers.Add(peer); } } respondedContacts++; if (respondedContacts == contacts.Length) { Monitor.Pulse(peers); } } } }); } if (Monitor.Wait(peers, _queryTimeout)) { return(peers.ToArray()); } return(null); } }
public void AddNode(NodeContact contact) { if (contact.NodeEP.AddressFamily != _currentNode.NodeEP.AddressFamily) { return; } if (_routingTable.AddContact(contact)) { Debug.Write(this.GetType().Name, "node contact added: " + contact.ToString()); ThreadPool.QueueUserWorkItem(delegate(object state) { Query(DhtRpcPacket.CreatePingPacket(_currentNode), contact); }); } }
public void AcceptConnection(Stream s, EndPoint remoteNodeEP) { //set timeout s.WriteTimeout = _queryTimeout; s.ReadTimeout = _queryTimeout; BinaryReader bR = new BinaryReader(s); BinaryWriter bW = new BinaryWriter(s); DhtRpcPacket response = ProcessQuery(new DhtRpcPacket(bR), remoteNodeEP); if (response == null) { return; } response.WriteTo(bW); s.Flush(); }
private object QueryFind(NodeContact[] initialContacts, BinaryNumber nodeId, DhtRpcType queryType) { if (initialContacts.Length < 1) { return(null); } List <NodeContact> seenContacts = new List <NodeContact>(initialContacts); List <NodeContact> learnedNotQueriedContacts = new List <NodeContact>(initialContacts); List <NodeContact> respondedContacts = new List <NodeContact>(); List <EndPoint> receivedPeers = null; int alpha = KADEMLIA_ALPHA; bool finalRound = false; bool checkTerminationCondition = false; if (queryType == DhtRpcType.FIND_PEERS) { receivedPeers = new List <EndPoint>(); } NodeContact previousClosestSeenContact = KBucket.SelectClosestContacts(seenContacts, nodeId, 1)[0]; while (true) { NodeContact[] alphaContacts; //pick alpha contacts to query from learned contacts lock (learnedNotQueriedContacts) { alphaContacts = KBucket.SelectClosestContacts(learnedNotQueriedContacts, nodeId, alpha); //remove selected alpha contacts from learned not queries contacts list foreach (NodeContact alphaContact in alphaContacts) { learnedNotQueriedContacts.Remove(alphaContact); } } if (alphaContacts.Length < 1) { checkTerminationCondition = true; } else { object lockObj = new object(); lock (lockObj) { int respondedAlphaContacts = 0; //query each alpha contact async foreach (NodeContact alphaContact in alphaContacts) { ThreadPool.QueueUserWorkItem(delegate(object state) { DhtRpcPacket response; if (queryType == DhtRpcType.FIND_NODE) { response = Query(DhtRpcPacket.CreateFindNodePacketQuery(_currentNode, nodeId), alphaContact); } else { response = Query(DhtRpcPacket.CreateFindPeersPacketQuery(_currentNode, nodeId), alphaContact); } if ((response == null) || (response.Type != queryType)) { //time out or error //ignore contact by removing from seen contacts list lock (seenContacts) { seenContacts.Remove(alphaContact); } } else { //got reply! if ((queryType == DhtRpcType.FIND_PEERS) && (response.Peers.Length > 0)) { lock (receivedPeers) { foreach (EndPoint peer in response.Peers) { if (!receivedPeers.Contains(peer)) { receivedPeers.Add(peer); } } } } //add alpha contact to responded contacts list lock (respondedContacts) { if (!respondedContacts.Contains(alphaContact)) { respondedContacts.Add(alphaContact); } } //add received contacts to learned contacts list lock (seenContacts) { lock (learnedNotQueriedContacts) { foreach (NodeContact contact in response.Contacts) { if (!seenContacts.Contains(contact)) { seenContacts.Add(contact); learnedNotQueriedContacts.Add(contact); } } } } } //wait for all alpha contacts to respond and signal only when all contacts responded lock (lockObj) { respondedAlphaContacts++; if (respondedAlphaContacts == alphaContacts.Length) { Monitor.Pulse(lockObj); } } }); } //wait for any of the node contact to return new contacts if (Monitor.Wait(lockObj, _queryTimeout)) { //got reply or final round! NodeContact currentClosestSeenContact; lock (seenContacts) { currentClosestSeenContact = KBucket.SelectClosestContacts(seenContacts, nodeId, 1)[0]; } BinaryNumber previousDistance = nodeId ^ previousClosestSeenContact.NodeId; BinaryNumber currentDistance = nodeId ^ currentClosestSeenContact.NodeId; if (previousDistance <= currentDistance) { //current round failed to return a node contact any closer than the closest already seen if (finalRound) { //final round over, check for termination condition checkTerminationCondition = true; } else { //resend query to k closest node not already queried finalRound = true; alpha = KADEMLIA_K; } } else { //current closest seen contact is closer than previous closest seen contact previousClosestSeenContact = currentClosestSeenContact; finalRound = false; alpha = KADEMLIA_ALPHA; } } } } if (checkTerminationCondition) { checkTerminationCondition = false; //reset if (queryType == DhtRpcType.FIND_PEERS) { //check only in final round to get most peers lock (receivedPeers) { if (receivedPeers.Count > 0) { return(receivedPeers.ToArray()); } return(null); } } //lookup terminates when k closest seen contacts have responded NodeContact[] kClosestSeenContacts; lock (seenContacts) { kClosestSeenContacts = KBucket.SelectClosestContacts(seenContacts, nodeId, KADEMLIA_K); } lock (respondedContacts) { bool success = true; foreach (NodeContact contact in kClosestSeenContacts) { if (!respondedContacts.Contains(contact)) { success = false; break; } } if (success) { return(kClosestSeenContacts); } if (alphaContacts.Length < 1) { return(KBucket.SelectClosestContacts(respondedContacts, nodeId, KADEMLIA_K)); } } } } }
internal bool Ping(NodeContact contact) { DhtRpcPacket response = Query(DhtRpcPacket.CreatePingPacket(_currentNode), contact); return(response != null); }
private DhtRpcPacket ProcessQuery(DhtRpcPacket query, EndPoint remoteNodeEP) { //in case of remote node querying via Tor, remoteNodeEP.Address will be loopback IP. Use the onion address from the query as remote end point if (!_currentNode.NodeEP.Equals(remoteNodeEP)) { switch (remoteNodeEP.AddressFamily) { case AddressFamily.InterNetwork: case AddressFamily.InterNetworkV6: IPAddress remoteNodeAddress = (remoteNodeEP as IPEndPoint).Address; if (IPAddress.IsLoopback(remoteNodeAddress) && (query.SourceNodeEP.AddressFamily == AddressFamily.Unspecified) && (query.SourceNodeEP as DomainEndPoint).Address.EndsWith(".onion", StringComparison.OrdinalIgnoreCase)) { AddNode(query.SourceNodeEP); //use the tor hidden end point claimed by remote node } else { AddNode(new IPEndPoint(remoteNodeAddress, query.SourceNodeEP.GetPort())); //use remote node end point as seen by connection manager and use port from query } break; default: throw new NotSupportedException(); } } Debug.Write(this.GetType().Name, "query received from: " + remoteNodeEP.ToString() + "; type: " + query.Type.ToString()); //process query switch (query.Type) { case DhtRpcType.PING: return(DhtRpcPacket.CreatePingPacket(_currentNode)); case DhtRpcType.FIND_NODE: return(DhtRpcPacket.CreateFindNodePacketResponse(_currentNode, query.NetworkId, _routingTable.GetKClosestContacts(query.NetworkId, false))); case DhtRpcType.FIND_PEERS: EndPoint[] peers = _currentNode.GetPeers(query.NetworkId); if (peers.Length == 0) { return(DhtRpcPacket.CreateFindPeersPacketResponse(_currentNode, query.NetworkId, _routingTable.GetKClosestContacts(query.NetworkId, false), peers)); } else { return(DhtRpcPacket.CreateFindPeersPacketResponse(_currentNode, query.NetworkId, new NodeContact[] { }, peers)); } case DhtRpcType.ANNOUNCE_PEER: if ((query.Peers != null) && (query.Peers.Length > 0)) { EndPoint peerEP; if (query.Peers[0].AddressFamily == AddressFamily.Unspecified) { peerEP = query.Peers[0]; } else { peerEP = new IPEndPoint((remoteNodeEP as IPEndPoint).Address, query.Peers[0].GetPort()); } _currentNode.StorePeer(query.NetworkId, peerEP); } return(DhtRpcPacket.CreateAnnouncePeerPacketResponse(_currentNode, query.NetworkId, _currentNode.GetPeers(query.NetworkId))); default: throw new Exception("Invalid DHT-RPC type."); } }