Esempio n. 1
0
        private NodeContact[] PickClosestContacts(List <NodeContact> availableContacts, int count)
        {
            if (availableContacts.Count < count)
            {
                count = availableContacts.Count;
            }

            NodeContact[] closestContacts = KBucket.GetClosestContacts(availableContacts, _currentNode.NodeID, count);

            //remove selected contacts from available contacts
            foreach (NodeContact closestContact in closestContacts)
            {
                availableContacts.Remove(closestContact);
            }

            return(closestContacts);
        }
Esempio n. 2
0
        private object QueryFind(NodeContact[] initialContacts, BinaryID nodeID, RpcQueryType queryType)
        {
            List <NodeContact> availableContacts = new List <NodeContact>(initialContacts);
            List <NodeContact> respondedContacts = new List <NodeContact>();
            List <NodeContact> failedContacts    = new List <NodeContact>();

            NodeContact[] alphaContacts;
            int           alpha      = KADEMLIA_ALPHA;
            bool          finalRound = false;

            while (true)
            {
                //pick alpha contacts to query from available contacts
                lock (availableContacts)
                {
                    alphaContacts = PickClosestContacts(availableContacts, alpha);
                }

                if (alphaContacts.Length < 1)
                {
                    //no contacts available to query further

                    lock (respondedContacts)
                    {
                        if (respondedContacts.Count > KADEMLIA_K)
                        {
                            return(KBucket.GetClosestContacts(respondedContacts, nodeID, KADEMLIA_K));
                        }
                        else if (respondedContacts.Count > 0)
                        {
                            return(respondedContacts.ToArray());
                        }
                    }

                    return(null);
                }

                object              lockObj          = new object();
                List <NodeContact>  receivedContacts = new List <NodeContact>();
                List <PeerEndPoint> receivedPeers    = null;

                if (queryType == RpcQueryType.FIND_PEERS)
                {
                    receivedPeers = new List <PeerEndPoint>();
                }

                lock (lockObj)
                {
                    //query each alpha contact async
                    foreach (NodeContact alphaContact in alphaContacts)
                    {
                        ThreadPool.QueueUserWorkItem(QueryFindAsync, new object[] { lockObj, queryType, alphaContact, nodeID, availableContacts, respondedContacts, failedContacts, receivedContacts, receivedPeers });
                    }

                    //wait for any of the contact to return new contacts
                    if (Monitor.Wait(lockObj, QUERY_TIMEOUT))
                    {
                        //got reply!

                        if (queryType == RpcQueryType.FIND_PEERS)
                        {
                            lock (receivedPeers)
                            {
                                if (receivedPeers.Count > 0)
                                {
                                    return(receivedPeers.ToArray());
                                }
                            }
                        }

                        lock (receivedContacts)
                        {
                            if (receivedContacts.Count < 1)
                            {
                                //current round failed to return any new closer nodes

                                if (finalRound)
                                {
                                    if (queryType == RpcQueryType.FIND_PEERS)
                                    {
                                        return(null);
                                    }

                                    lock (respondedContacts)
                                    {
                                        if (respondedContacts.Count > KADEMLIA_K)
                                        {
                                            return(KBucket.GetClosestContacts(respondedContacts, nodeID, KADEMLIA_K));
                                        }
                                        else
                                        {
                                            return(respondedContacts.ToArray());
                                        }
                                    }
                                }
                                else
                                {
                                    //resend query to k closest node not already queried
                                    finalRound = true;
                                    alpha      = KADEMLIA_K;
                                }
                            }
                            else
                            {
                                finalRound = false;
                                alpha      = KADEMLIA_ALPHA;
                            }
                        }
                    }
                }
            }
        }
Esempio n. 3
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 <PeerEndPoint> receivedPeers             = null;
            int  alpha      = KADEMLIA_ALPHA;
            bool finalRound = false;
            bool checkTerminationCondition = false;

            if (queryType == DhtRpcType.FIND_PEERS)
            {
                receivedPeers = new List <PeerEndPoint>();
            }

            NodeContact previousClosestSeenContact = KBucket.GetClosestContacts(seenContacts, nodeID, 1)[0];

            while (true)
            {
                NodeContact[] alphaContacts;

                //pick alpha contacts to query from learned contacts
                lock (learnedNotQueriedContacts)
                {
                    alphaContacts = KBucket.GetClosestContacts(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)
                    {
                        //query each alpha contact async
                        foreach (NodeContact alphaContact in alphaContacts)
                        {
                            Thread t = new Thread(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);
                                    }

                                    return;
                                }

                                //got reply!
                                if ((queryType == DhtRpcType.FIND_PEERS) && (response.Peers.Length > 0))
                                {
                                    lock (receivedPeers)
                                    {
                                        foreach (PeerEndPoint 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);
                                            }
                                        }
                                    }
                                }

                                //no pulse for final round to wait for all k contacts to respond. this allows any failed node contact to be removed from seen contacts list during the wait.
                                lock (lockObj)
                                {
                                    Monitor.Pulse(lockObj);
                                }
                            });

                            t.IsBackground = true;
                            t.Start();
                        }

                        //wait for any of the node contact to return new contacts
                        if (Monitor.Wait(lockObj, QUERY_TIMEOUT))
                        {
                            //got reply or final round!

                            NodeContact currentClosestSeenContact;

                            lock (seenContacts)
                            {
                                currentClosestSeenContact = KBucket.GetClosestContacts(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.GetClosestContacts(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.GetClosestContacts(respondedContacts, nodeID, KADEMLIA_K));
                        }
                    }
                }
            }
        }