Beispiel #1
0
        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));
                        }
                    }
                }
            }
        }
Beispiel #2
0
        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;
                }
            }
        }
Beispiel #3
0
        public NodeContact[] GetKClosestContacts(BinaryNumber nodeID, bool includeSelfContact)
        {
            KBucket currentBucket = this;

            while (true)
            {
                NodeContact[] contacts    = currentBucket._contacts;
                KBucket       leftBucket  = currentBucket._leftBucket;
                KBucket       rightBucket = currentBucket._rightBucket;

                if (contacts != null)
                {
                    #region find closest contacts from this bucket

                    KBucket       closestBucket   = currentBucket;
                    NodeContact[] closestContacts = null;

                    if (closestBucket._contactCount >= DhtNode.KADEMLIA_K)
                    {
                        closestContacts = closestBucket.GetAllContacts(false, includeSelfContact);

                        if (closestContacts.Length > DhtNode.KADEMLIA_K)
                        {
                            return(SelectClosestContacts(closestContacts, nodeID, DhtNode.KADEMLIA_K));
                        }

                        if (closestContacts.Length == DhtNode.KADEMLIA_K)
                        {
                            return(closestContacts);
                        }

                        if (closestBucket._parentBucket == null)
                        {
                            return(closestContacts);
                        }
                    }

                    while (closestBucket._parentBucket != null)
                    {
                        KBucket parentBucket = closestBucket._parentBucket;

                        closestContacts = parentBucket.GetAllContacts(false, includeSelfContact);

                        if (closestContacts.Length > DhtNode.KADEMLIA_K)
                        {
                            return(SelectClosestContacts(closestContacts, nodeID, DhtNode.KADEMLIA_K));
                        }

                        if (closestContacts.Length == DhtNode.KADEMLIA_K)
                        {
                            return(closestContacts);
                        }

                        closestBucket = parentBucket;
                    }

                    if (closestContacts == null)
                    {
                        closestContacts = closestBucket.GetAllContacts(false, includeSelfContact);
                    }

                    return(closestContacts);

                    #endregion
                }

                if ((leftBucket._bucketID & nodeID) == leftBucket._bucketID)
                {
                    currentBucket = leftBucket;
                }
                else
                {
                    currentBucket = rightBucket;
                }
            }
        }
Beispiel #4
0
        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;
                }
            }
        }