public static NodeContact[] SelectClosestContacts(ICollection <NodeContact> contacts, BinaryNumber nodeID, int count) { if (contacts.Count < count) { count = contacts.Count; } NodeContact[] closestContacts = new NodeContact[count]; BinaryNumber[] closestContactDistances = new BinaryNumber[count]; foreach (NodeContact contact in contacts) { BinaryNumber distance = nodeID ^ contact.NodeId; for (int i = 0; i < count; i++) { if ((closestContactDistances[i] == null) || (distance < closestContactDistances[i])) { //demote existing values for (int j = count - 1; j > i; j--) { closestContactDistances[j] = closestContactDistances[j - 1]; closestContacts[j] = closestContacts[j - 1]; } //place current on top closestContactDistances[i] = distance; closestContacts[i] = contact; break; } } } return(closestContacts); }
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(); } } }
public override bool Equals(object obj) { if (obj is null) { return(false); } if (ReferenceEquals(this, obj)) { return(true); } NodeContact contact = obj as NodeContact; if (contact == null) { return(false); } if (_nodeEP.Equals(contact._nodeEP)) { return(true); } return(_nodeId.Equals(contact._nodeId)); }
public KBucket(NodeContact currentNode) { _bucketDepth = 0; _contacts = new NodeContact[DhtNode.KADEMLIA_K * 2]; _contacts[0] = currentNode; _contactCount = 1; _lastChanged = DateTime.UtcNow; }
private static void SplitBucket(KBucket bucket, NodeContact newContact) { if (bucket._contacts == null) { return; } KBucket leftBucket = new KBucket(bucket, true); KBucket rightBucket = new KBucket(bucket, false); foreach (NodeContact contact in bucket._contacts) { if (contact != null) { if ((leftBucket._bucketID & contact.NodeId) == leftBucket._bucketID) { leftBucket._contacts[leftBucket._contactCount++] = contact; } else { rightBucket._contacts[rightBucket._contactCount++] = contact; } } } KBucket selectedBucket; if ((leftBucket._bucketID & newContact.NodeId) == leftBucket._bucketID) { selectedBucket = leftBucket; } else { selectedBucket = rightBucket; } if (selectedBucket._contactCount == selectedBucket._contacts.Length) { SplitBucket(selectedBucket, newContact); selectedBucket._contactCount++; } else { selectedBucket._contacts[selectedBucket._contactCount++] = newContact; } bucket._contacts = null; bucket._leftBucket = leftBucket; bucket._rightBucket = rightBucket; }
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 static DhtRpcPacket CreateAnnouncePeerPacketResponse(NodeContact sourceNode, BinaryNumber networkId, EndPoint[] peers) { return(new DhtRpcPacket(sourceNode.NodeEP, DhtRpcType.ANNOUNCE_PEER, networkId, null, peers)); }
public DhtRpcPacket(BinaryReader bR) { int version = bR.ReadByte(); switch (version) { case 1: _sourceNodeEP = EndPointExtension.Parse(bR); _type = (DhtRpcType)bR.ReadByte(); switch (_type) { case DhtRpcType.PING: break; case DhtRpcType.FIND_NODE: _networkId = new BinaryNumber(bR.BaseStream); _contacts = new NodeContact[bR.ReadByte()]; for (int i = 0; i < _contacts.Length; i++) { _contacts[i] = new NodeContact(bR); } break; case DhtRpcType.FIND_PEERS: _networkId = new BinaryNumber(bR.BaseStream); _contacts = new NodeContact[bR.ReadByte()]; for (int i = 0; i < _contacts.Length; i++) { _contacts[i] = new NodeContact(bR); } _peers = new EndPoint[bR.ReadByte()]; for (int i = 0; i < _peers.Length; i++) { _peers[i] = EndPointExtension.Parse(bR); } break; case DhtRpcType.ANNOUNCE_PEER: _networkId = new BinaryNumber(bR.BaseStream); _peers = new EndPoint[bR.ReadByte()]; for (int i = 0; i < _peers.Length; i++) { _peers[i] = EndPointExtension.Parse(bR); } break; default: throw new IOException("Invalid DHT-RPC type."); } break; default: throw new InvalidDataException("DHT-RPC packet version not supported: " + version); } }
public static DhtRpcPacket CreateFindPeersPacketResponse(NodeContact sourceNode, BinaryNumber networkId, NodeContact[] contacts, EndPoint[] peers) { return(new DhtRpcPacket(sourceNode.NodeEP, DhtRpcType.FIND_PEERS, networkId, contacts, peers)); }
public static DhtRpcPacket CreateAnnouncePeerPacketQuery(NodeContact sourceNode, BinaryNumber networkId, EndPoint serviceEP) { return(new DhtRpcPacket(sourceNode.NodeEP, DhtRpcType.ANNOUNCE_PEER, networkId, null, new EndPoint[] { serviceEP })); }
public static DhtRpcPacket CreateFindNodePacketResponse(NodeContact sourceNode, BinaryNumber networkId, NodeContact[] contacts) { return(new DhtRpcPacket(sourceNode.NodeEP, DhtRpcType.FIND_NODE, networkId, contacts, null)); }
public static DhtRpcPacket CreateFindPeersPacketQuery(NodeContact sourceNode, BinaryNumber networkId) { return(new DhtRpcPacket(sourceNode.NodeEP, DhtRpcType.FIND_PEERS, networkId, null, null)); }
public static DhtRpcPacket CreatePingPacket(NodeContact sourceNode) { return(new DhtRpcPacket(sourceNode.NodeEP, DhtRpcType.PING, null, null, null)); }
public bool RemoveStaleContact(NodeContact contact) { KBucket currentBucket = this; while (true) { NodeContact[] contacts; KBucket leftBucket; KBucket rightBucket; lock (currentBucket) { contacts = currentBucket._contacts; leftBucket = currentBucket._leftBucket; rightBucket = currentBucket._rightBucket; if (contacts != null) { #region remove contact from this bucket if (currentBucket._contactCount <= DhtNode.KADEMLIA_K) { return(false); //k-bucket is not full and replacement cache is empty } //check if there is more deserving contact to be removed than the current one foreach (NodeContact testContact in contacts) { if ((testContact != null) && testContact.IsStale() && (contact.SuccessfulRpcCount > testContact.SuccessfulRpcCount)) { //set test contact for removal contact = testContact; break; } } for (int i = 0; i < contacts.Length; i++) { if (contact.Equals(contacts[i])) { if (contacts[i].IsStale()) { //remove stale contact contacts[i] = null; currentBucket._lastChanged = DateTime.UtcNow; KBucket bucket = currentBucket; do { Interlocked.Decrement(ref bucket._contactCount); bucket = bucket._parentBucket; }while (bucket != null); return(true); } break; } } return(false); //contact was not found or was not stale #endregion } } if ((leftBucket._bucketID & contact.NodeId) == leftBucket._bucketID) { currentBucket = leftBucket; } else { currentBucket = rightBucket; } } }
public bool AddContact(NodeContact contact) { KBucket currentBucket = this; while (true) { NodeContact[] contacts; KBucket leftBucket; KBucket rightBucket; lock (currentBucket) { contacts = currentBucket._contacts; leftBucket = currentBucket._leftBucket; rightBucket = currentBucket._rightBucket; if (contacts != null) { #region add contact in this bucket //search if contact already exists for (int i = 0; i < contacts.Length; i++) { if (contact.Equals(contacts[i])) { return(false); //contact already exists } } //try add contact for (int i = 0; i < contacts.Length; i++) { if (contacts[i] == null) { contacts[i] = contact; currentBucket._lastChanged = DateTime.UtcNow; KBucket bucket = currentBucket; do { Interlocked.Increment(ref bucket._contactCount); bucket = bucket._parentBucket; }while (bucket != null); return(true); } } //k-bucket is full so contact was not added //if current contact is not stale then find and replace with any existing stale contact if (!contact.IsStale()) { for (int i = 0; i < contacts.Length; i++) { if (contacts[i].IsStale()) { contacts[i] = contact; currentBucket._lastChanged = DateTime.UtcNow; KBucket bucket = currentBucket; do { Interlocked.Increment(ref bucket._contactCount); bucket = bucket._parentBucket; }while (bucket != null); return(true); } } } //no stale contact in this k-bucket to replace! if (contacts[0].IsCurrentNode || (currentBucket._bucketDepth < (DhtNode.KADEMLIA_B - 1))) { //split current bucket and add contact! SplitBucket(currentBucket, contact); KBucket bucket = currentBucket; do { Interlocked.Increment(ref bucket._contactCount); bucket = bucket._parentBucket; }while (bucket != null); return(true); } //k-bucket is full! return(false); #endregion } } if ((leftBucket._bucketID & contact.NodeId) == leftBucket._bucketID) { currentBucket = leftBucket; } else { currentBucket = rightBucket; } } }
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); }