예제 #1
0
        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);
        }
예제 #2
0
파일: DhtNode.cs 프로젝트: orf53975/Mesh
        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();
                }
            }
        }
예제 #3
0
        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));
        }
예제 #4
0
        public KBucket(NodeContact currentNode)
        {
            _bucketDepth = 0;

            _contacts = new NodeContact[DhtNode.KADEMLIA_K * 2];

            _contacts[0]  = currentNode;
            _contactCount = 1;
            _lastChanged  = DateTime.UtcNow;
        }
예제 #5
0
        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;
        }
예제 #6
0
        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);
                });
            }
        }
예제 #7
0
 public static DhtRpcPacket CreateAnnouncePeerPacketResponse(NodeContact sourceNode, BinaryNumber networkId, EndPoint[] peers)
 {
     return(new DhtRpcPacket(sourceNode.NodeEP, DhtRpcType.ANNOUNCE_PEER, networkId, null, peers));
 }
예제 #8
0
        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);
            }
        }
예제 #9
0
 public static DhtRpcPacket CreateFindPeersPacketResponse(NodeContact sourceNode, BinaryNumber networkId, NodeContact[] contacts, EndPoint[] peers)
 {
     return(new DhtRpcPacket(sourceNode.NodeEP, DhtRpcType.FIND_PEERS, networkId, contacts, peers));
 }
예제 #10
0
 public static DhtRpcPacket CreateAnnouncePeerPacketQuery(NodeContact sourceNode, BinaryNumber networkId, EndPoint serviceEP)
 {
     return(new DhtRpcPacket(sourceNode.NodeEP, DhtRpcType.ANNOUNCE_PEER, networkId, null, new EndPoint[] { serviceEP }));
 }
예제 #11
0
 public static DhtRpcPacket CreateFindNodePacketResponse(NodeContact sourceNode, BinaryNumber networkId, NodeContact[] contacts)
 {
     return(new DhtRpcPacket(sourceNode.NodeEP, DhtRpcType.FIND_NODE, networkId, contacts, null));
 }
예제 #12
0
 public static DhtRpcPacket CreateFindPeersPacketQuery(NodeContact sourceNode, BinaryNumber networkId)
 {
     return(new DhtRpcPacket(sourceNode.NodeEP, DhtRpcType.FIND_PEERS, networkId, null, null));
 }
예제 #13
0
 public static DhtRpcPacket CreatePingPacket(NodeContact sourceNode)
 {
     return(new DhtRpcPacket(sourceNode.NodeEP, DhtRpcType.PING, null, null, null));
 }
예제 #14
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;
                }
            }
        }
예제 #15
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;
                }
            }
        }
예제 #16
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));
                        }
                    }
                }
            }
        }
예제 #17
0
        internal bool Ping(NodeContact contact)
        {
            DhtRpcPacket response = Query(DhtRpcPacket.CreatePingPacket(_currentNode), contact);

            return(response != null);
        }