public static NodeContact[] GetClosestContacts(IEnumerable <NodeContact> contacts, BinaryID nodeID, int count)
        {
            NodeContact[] closestContacts = new NodeContact[count];
            BinaryID[]    min             = new BinaryID[count];
            BinaryID      distance;
            int           ubound = count - 1;
            int           i;
            int           j;

            foreach (NodeContact contact in contacts)
            {
                distance = nodeID ^ contact.NodeID;

                for (i = 0; i < count; i++)
                {
                    if ((min[i] == null) || (distance < min[i]))
                    {
                        //demote existing values
                        for (j = ubound; j > i; j--)
                        {
                            min[j]             = min[j - 1];
                            closestContacts[j] = closestContacts[j - 1];
                        }

                        //place current on top
                        min[i]             = distance;
                        closestContacts[i] = contact;
                        break;
                    }
                }
            }

            return(closestContacts);
        }
 private DhtRpcPacket(int transactionID, NodeContact sourceNode, RpcPacketType type, RpcQueryType queryType)
 {
     _transactionID = transactionID;
     _sourceNode    = sourceNode;
     _type          = type;
     _queryType     = queryType;
 }
Beispiel #3
0
        public static NodeContact[] GetClosestContacts(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 void CheckContactHealthAsync(object state)
        {
            object[] param = state as object[];

            DhtClient   dhtClient = param[0] as DhtClient;
            NodeContact contact   = param[1] as NodeContact;
            int         retries   = 0;

            do
            {
                try
                {
                    if (dhtClient.Ping(contact))
                    {
                        return; //contact replied; do nothing.
                    }
                }
                catch
                { }

                retries++;
            }while (retries < HEALTH_PING_MAX_RETRIES);

            try
            {
                //remove stale node
                RemoveContactFromCurrentBucket(contact);
            }
            catch
            { }
        }
        public static DhtRpcPacket CreateFindPeersPacketQuery(NodeContact sourceNode, BinaryID networkID)
        {
            DhtRpcPacket packet = new DhtRpcPacket(GetRandomTransactionID(), sourceNode, RpcPacketType.Query, RpcQueryType.FIND_PEERS);

            packet._networkID = networkID;

            return(packet);
        }
        public static DhtRpcPacket CreateFindNodePacketResponse(int transactionID, NodeContact sourceNode, BinaryID networkID, NodeContact[] contacts)
        {
            DhtRpcPacket packet = new DhtRpcPacket(transactionID, sourceNode, RpcPacketType.Response, RpcQueryType.FIND_NODE);

            packet._networkID = networkID;
            packet._contacts  = contacts;

            return(packet);
        }
Beispiel #7
0
        public KBucket(NodeContact currentNode)
        {
            _bucketDepth = 0;

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

            _contacts[0]  = currentNode;
            _contactCount = 1;
            _lastChanged  = DateTime.UtcNow;
        }
        public static DhtRpcPacket CreateAnnouncePeerPacketQuery(NodeContact sourceNode, BinaryID networkID, ushort servicePort, BinaryID token)
        {
            DhtRpcPacket packet = new DhtRpcPacket(GetRandomTransactionID(), sourceNode, RpcPacketType.Query, RpcQueryType.ANNOUNCE_PEER);

            packet._networkID   = networkID;
            packet._servicePort = servicePort;
            packet._token       = token;

            return(packet);
        }
Beispiel #9
0
        public override bool Equals(object obj)
        {
            NodeContact contact = obj as NodeContact;

            if (contact == null)
            {
                return(false);
            }

            return(_nodeID.Equals(contact._nodeID));
        }
Beispiel #10
0
        private DhtRpcPacket Query(DhtRpcPacket query, NodeContact contact)
        {
            if (_currentNode.NodeEP.AddressFamily != contact.NodeEP.AddressFamily)
            {
                return(null);
            }

            Stream s = null;

            try
            {
                s = _manager.GetConnectionStream(contact.NodeEP);

                //set timeout
                s.WriteTimeout = QUERY_TIMEOUT;
                s.ReadTimeout  = QUERY_TIMEOUT;

                //send query
                query.WriteTo(s);
                s.Flush();

                //read response
                DhtRpcPacket response = new DhtRpcPacket(s);

                //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
            {
                contact.IncrementRpcFailCount();
                return(null);
            }
            finally
            {
                if (s != null)
                {
                    s.Dispose();
                }
            }
        }
        public static DhtRpcPacket CreateFindPeersPacketResponse(int transactionID, NodeContact sourceNode, BinaryID networkID, NodeContact[] contacts, PeerEndPoint[] peers, BinaryID token)
        {
            DhtRpcPacket packet = new DhtRpcPacket(transactionID, sourceNode, RpcPacketType.Response, RpcQueryType.FIND_PEERS);

            packet._networkID = networkID;
            packet._contacts  = contacts;
            packet._peers     = peers;
            packet._token     = token;

            return(packet);
        }
        public KBucket(NodeContact currentNode)
        {
            _bucketDepth = 0;

            _contacts            = new Dictionary <BinaryID, NodeContact>();
            _replacementContacts = new Dictionary <BinaryID, NodeContact>();

            _contacts.Add(currentNode.NodeID, currentNode);
            _bucketContainsCurrentNode = true;
            _lastChanged = DateTime.UtcNow;

            _lock = new ReaderWriterLockSlim();
        }
Beispiel #13
0
 public void AddNode(NodeContact contact)
 {
     if (!NetUtilities.IsPrivateIP(contact.NodeEP.Address) && (contact.NodeEP.AddressFamily == _currentNode.NodeEP.AddressFamily))
     {
         if (_routingTable.AddContact(contact))
         {
             ThreadPool.QueueUserWorkItem(delegate(object state)
             {
                 Query(DhtRpcPacket.CreatePingPacket(_currentNode), contact);
             });
         }
     }
 }
Beispiel #14
0
        private static void SplitBucket(KBucket bucket, NodeContact newContact)
        {
            if (bucket._contacts == null)
            {
                return;
            }

            if (!bucket._contacts[0].IsCurrentNode)
            {
                throw new ArgumentException("Cannot split this k-bucket: must contain current node to split.");
            }

            KBucket leftBucket  = new KBucket(bucket, true);
            KBucket rightBucket = new KBucket(bucket, false);

            foreach (NodeContact contact in bucket._contacts)
            {
                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);
            }
            else
            {
                selectedBucket._contacts[selectedBucket._contactCount++] = newContact;
            }

            bucket._contacts    = null;
            bucket._leftBucket  = leftBucket;
            bucket._rightBucket = rightBucket;
        }
Beispiel #15
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;
        }
Beispiel #16
0
        internal bool Ping(NodeContact contact)
        {
            DhtRpcPacket response = Query(DhtRpcPacket.CreatePingPacketQuery(_currentNode), contact);

            if (response == null)
            {
                return(false);
            }
            else
            {
                if (contact.Equals(response.SourceNode))
                {
                    return(true);
                }
                else
                {
                    contact.IncrementRpcFailCount();
                    return(false);
                }
            }
        }
Beispiel #17
0
        private void QueryAnnounceAsync(object state)
        {
            try
            {
                object[] parameters = state as object[];

                NodeContact         contact   = parameters[0] as NodeContact;
                BinaryID            networkID = parameters[1] as BinaryID;
                List <PeerEndPoint> peers     = parameters[2] as List <PeerEndPoint>;
                ushort servicePort            = (ushort)parameters[3];

                DhtRpcPacket responsePacket = Query(DhtRpcPacket.CreateFindPeersPacketQuery(_currentNode, networkID), contact);

                if ((responsePacket != null) && (responsePacket.QueryType == RpcQueryType.FIND_PEERS))
                {
                    if (responsePacket.Peers.Length > 0)
                    {
                        lock (peers)
                        {
                            foreach (PeerEndPoint peer in responsePacket.Peers)
                            {
                                if (!peers.Contains(peer))
                                {
                                    peers.Add(peer);
                                }
                            }

                            //Monitor.Pulse(peers); //removed so that response from multiple nodes is collected till query times out
                        }
                    }

                    Query(DhtRpcPacket.CreateAnnouncePeerPacketQuery(_currentNode, networkID, servicePort, responsePacket.Token), contact);
                }
            }
            catch
            { }
        }
Beispiel #18
0
 public static DhtRpcPacket CreateAnnouncePeerPacketQuery(NodeContact sourceNode, BinaryNumber networkID, ushort servicePort)
 {
     return(new DhtRpcPacket(Convert.ToUInt16(sourceNode.NodeEP.Port), DhtRpcType.ANNOUNCE_PEER, networkID, null, null, servicePort));
 }
Beispiel #19
0
 public static DhtRpcPacket CreateFindPeersPacketResponse(NodeContact sourceNode, BinaryNumber networkID, NodeContact[] contacts, PeerEndPoint[] peers)
 {
     return(new DhtRpcPacket(Convert.ToUInt16(sourceNode.NodeEP.Port), DhtRpcType.FIND_PEERS, networkID, contacts, peers, 0));
 }
Beispiel #20
0
 public static DhtRpcPacket CreateFindPeersPacketQuery(NodeContact sourceNode, BinaryNumber networkID)
 {
     return(new DhtRpcPacket(Convert.ToUInt16(sourceNode.NodeEP.Port), DhtRpcType.FIND_PEERS, networkID, null, null, 0));
 }
Beispiel #21
0
 public static DhtRpcPacket CreateFindNodePacketResponse(NodeContact sourceNode, BinaryNumber networkID, NodeContact[] contacts)
 {
     return(new DhtRpcPacket(Convert.ToUInt16(sourceNode.NodeEP.Port), DhtRpcType.FIND_NODE, networkID, contacts, null, 0));
 }
Beispiel #22
0
 public static DhtRpcPacket CreatePingPacket(NodeContact sourceNode)
 {
     return(new DhtRpcPacket(Convert.ToUInt16(sourceNode.NodeEP.Port), DhtRpcType.PING, null, null, null, 0));
 }
Beispiel #23
0
        private void QueryFindAsync(object state)
        {
            try
            {
                object[] parameters = state as object[];

                object             lockObj           = parameters[0] as object;
                RpcQueryType       queryType         = (RpcQueryType)parameters[1];
                NodeContact        contact           = parameters[2] as NodeContact;
                BinaryID           nodeID            = parameters[3] as BinaryID;
                List <NodeContact> availableContacts = parameters[4] as List <NodeContact>;
                List <NodeContact> respondedContacts = parameters[5] as List <NodeContact>;
                List <NodeContact> failedContacts    = parameters[6] as List <NodeContact>;
                List <NodeContact> receivedContacts  = parameters[7] as List <NodeContact>;

                DhtRpcPacket responsePacket;

                if (queryType == RpcQueryType.FIND_NODE)
                {
                    responsePacket = Query(DhtRpcPacket.CreateFindNodePacketQuery(_currentNode, nodeID), contact);
                }
                else
                {
                    responsePacket = Query(DhtRpcPacket.CreateFindPeersPacketQuery(_currentNode, nodeID), contact);
                }

                if ((responsePacket == null) || (responsePacket.QueryType != queryType))
                {
                    //time out
                    //add contact to failed contacts
                    lock (failedContacts)
                    {
                        if (!failedContacts.Contains(contact))
                        {
                            failedContacts.Add(contact);
                        }
                    }

                    return;
                }

                //got reply!
                switch (queryType)
                {
                case RpcQueryType.FIND_NODE:
                    lock (receivedContacts)
                    {
                        lock (respondedContacts)
                        {
                            //add contact to responded contacts list
                            if (!respondedContacts.Contains(contact))
                            {
                                respondedContacts.Add(contact);
                            }

                            lock (failedContacts)
                            {
                                //add received contacts to received contacts list
                                foreach (NodeContact receivedContact in responsePacket.Contacts)
                                {
                                    if (!respondedContacts.Contains(receivedContact) && !failedContacts.Contains(receivedContact))
                                    {
                                        receivedContacts.Add(receivedContact);
                                    }
                                }
                            }
                        }

                        //add received contacts to available contacts list
                        lock (availableContacts)
                        {
                            foreach (NodeContact receivedContact in receivedContacts)
                            {
                                if (!availableContacts.Contains(receivedContact))
                                {
                                    availableContacts.Add(receivedContact);
                                }
                            }
                        }
                    }

                    if (responsePacket.Contacts.Length > 0)
                    {
                        //pulse only if the contact has sent next level contacts list
                        lock (lockObj)
                        {
                            Monitor.Pulse(lockObj);
                        }
                    }
                    break;

                case RpcQueryType.FIND_PEERS:
                    if (responsePacket.Peers.Length > 0)
                    {
                        List <PeerEndPoint> receivedPeers = parameters[8] as List <PeerEndPoint>;

                        lock (receivedPeers)
                        {
                            foreach (PeerEndPoint peer in responsePacket.Peers)
                            {
                                if (!receivedPeers.Contains(peer))
                                {
                                    receivedPeers.Add(peer);
                                }
                            }
                        }

                        lock (lockObj)
                        {
                            Monitor.Pulse(lockObj);
                        }
                    }
                    break;
                }
            }
            catch
            { }
        }
Beispiel #24
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.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)
                    {
                        //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.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 #25
0
        internal bool Ping(NodeContact contact)
        {
            DhtRpcPacket response = Query(DhtRpcPacket.CreatePingPacket(_currentNode), contact);

            return(response != null);
        }
        public NodeContact[] GetAllContacts(bool includeReplacementCache)
        {
            _lock.TryEnterReadLock(LOCK_TIMEOUT);
            try
            {
                NodeContact[] contacts;

                if (_contacts == null)
                {
                    NodeContact[] leftContacts  = _leftBucket.GetAllContacts(includeReplacementCache);
                    NodeContact[] rightContacts = _rightBucket.GetAllContacts(includeReplacementCache);

                    contacts = new NodeContact[leftContacts.Length + rightContacts.Length];

                    Array.Copy(leftContacts, contacts, leftContacts.Length);
                    Array.Copy(rightContacts, 0, contacts, leftContacts.Length, rightContacts.Length);
                }
                else
                {
                    int cacheCount;

                    if (includeReplacementCache)
                    {
                        cacheCount = _totalReplacementContacts;
                    }
                    else
                    {
                        cacheCount = 0;
                    }

                    List <NodeContact> contactsList = new List <NodeContact>(_totalContacts + cacheCount);

                    foreach (NodeContact contact in _contacts.Values)
                    {
                        if (!contact.IsStale() && !contact.IsCurrentNode)
                        {
                            contactsList.Add(contact);
                        }
                    }

                    if (includeReplacementCache)
                    {
                        foreach (NodeContact contact in _replacementContacts.Values)
                        {
                            if (!contact.IsStale())
                            {
                                contactsList.Add(contact);
                            }
                        }
                    }

                    contacts = contactsList.ToArray();
                }

                return(contacts);
            }
            finally
            {
                _lock.ExitReadLock();
            }
        }
        public bool RemoveContactFromCurrentBucket(NodeContact contact)
        {
            _lock.TryEnterWriteLock(LOCK_TIMEOUT);
            try
            {
                if (_contacts == null)
                {
                    return(false);
                }

                if (_replacementContacts.Count < 1)
                {
                    return(false);
                }

                if (_contacts.Remove(contact.NodeID))
                {
                    if (_replacementContacts.Count > 0)
                    {
                        //add good replacement contact to main contacts
                        NodeContact goodContact = null;

                        foreach (NodeContact replacementContact in _replacementContacts.Values)
                        {
                            if (!replacementContact.IsStale())
                            {
                                if ((goodContact == null) || (replacementContact.LastSeen > goodContact.LastSeen))
                                {
                                    goodContact = replacementContact;
                                }
                            }
                        }

                        if (goodContact == null)
                        {
                            //no good replacement contact available
                            DecrementContactCount();
                        }
                        else
                        {
                            //move good replacement contact to main contacts
                            _replacementContacts.Remove(goodContact.NodeID);
                            _contacts.Add(goodContact.NodeID, goodContact);

                            DecrementReplacementContactCount();
                            _lastChanged = DateTime.UtcNow;
                        }
                    }
                    else
                    {
                        //no replacement contacts available
                        DecrementContactCount();
                    }

                    //check parent bucket contact count and join the parent buckets
                    KBucket parentBucket = this._parentBucket;
                    ReaderWriterLockSlim currentLock;

                    while ((parentBucket != null) && (parentBucket._totalContacts <= DhtClient.KADEMLIA_K))
                    {
                        currentLock = parentBucket._lock;

                        currentLock.TryEnterWriteLock(LOCK_TIMEOUT);
                        try
                        {
                            JoinBucket(parentBucket);

                            parentBucket = parentBucket._parentBucket;
                        }
                        finally
                        {
                            currentLock.ExitWriteLock();
                        }
                    }

                    return(true);
                }
                else
                {
                    if (_replacementContacts.Remove(contact.NodeID))
                    {
                        DecrementReplacementContactCount();
                        return(true);
                    }
                    else
                    {
                        return(false);
                    }
                }
            }
            finally
            {
                _lock.ExitWriteLock();
            }
        }
Beispiel #28
0
 public static DhtRpcPacket CreateAnnouncePeerPacketResponse(NodeContact sourceNode, BinaryNumber networkID, PeerEndPoint[] peers)
 {
     return(new DhtRpcPacket(Convert.ToUInt16(sourceNode.NodeEP.Port), DhtRpcType.ANNOUNCE_PEER, networkID, null, peers, 0));
 }
Beispiel #29
0
        public DhtRpcPacket(Stream s)
        {
            int version = s.ReadByte();

            switch (version)
            {
            case -1:
                throw new EndOfStreamException();

            case 2:
                byte[] buffer = new byte[20];

                OffsetStream.StreamRead(s, buffer, 0, 2);
                _sourceNodePort = BitConverter.ToUInt16(buffer, 0);

                _type = (DhtRpcType)s.ReadByte();

                switch (_type)
                {
                case DhtRpcType.PING:
                    break;

                case DhtRpcType.FIND_NODE:
                {
                    OffsetStream.StreamRead(s, buffer, 0, 20);
                    _networkID = BinaryNumber.Clone(buffer, 0, 20);

                    int count = s.ReadByte();
                    _contacts = new NodeContact[count];

                    for (int i = 0; i < count; i++)
                    {
                        _contacts[i] = new NodeContact(s);
                    }
                }
                break;

                case DhtRpcType.FIND_PEERS:
                {
                    OffsetStream.StreamRead(s, buffer, 0, 20);
                    _networkID = BinaryNumber.Clone(buffer, 0, 20);

                    int count = s.ReadByte();
                    _contacts = new NodeContact[count];

                    for (int i = 0; i < count; i++)
                    {
                        _contacts[i] = new NodeContact(s);
                    }

                    count  = s.ReadByte();
                    _peers = new PeerEndPoint[count];

                    for (int i = 0; i < count; i++)
                    {
                        _peers[i] = new PeerEndPoint(s);
                    }
                }
                break;

                case DhtRpcType.ANNOUNCE_PEER:
                {
                    OffsetStream.StreamRead(s, buffer, 0, 20);
                    _networkID = BinaryNumber.Clone(buffer, 0, 20);

                    OffsetStream.StreamRead(s, buffer, 0, 2);
                    _servicePort = BitConverter.ToUInt16(buffer, 0);

                    int count = s.ReadByte();
                    _peers = new PeerEndPoint[count];

                    for (int i = 0; i < count; i++)
                    {
                        _peers[i] = new PeerEndPoint(s);
                    }
                }
                break;

                default:
                    throw new IOException("Invalid DHT-RPC type.");
                }

                break;

            default:
                throw new IOException("DHT-RPC packet version not supported: " + version);
            }
        }
        public bool AddContactInCurrentBucket(NodeContact contact)
        {
            _lock.TryEnterWriteLock(LOCK_TIMEOUT);
            try
            {
                if (_contacts == null)
                {
                    return(false);
                }

                if (_contacts.ContainsKey(contact.NodeID))
                {
                    _contacts[contact.NodeID].UpdateLastSeenTime();
                    return(true);
                }

                if (_contacts.Count < DhtClient.KADEMLIA_K)
                {
                    _contacts.Add(contact.NodeID, contact);
                    IncrementContactCount();
                    _lastChanged = DateTime.UtcNow;

                    if (contact.IsCurrentNode)
                    {
                        _bucketContainsCurrentNode = true;
                    }

                    return(true);
                }

                if (_bucketContainsCurrentNode)
                {
                    _contacts.Add(contact.NodeID, contact);
                    _lastChanged = DateTime.UtcNow;

                    //remove any stale node contact
                    NodeContact staleContact = null;

                    foreach (NodeContact existingContact in _contacts.Values)
                    {
                        if (existingContact.IsStale())
                        {
                            staleContact = existingContact;
                            break;
                        }
                    }

                    if (staleContact != null)
                    {
                        //remove stale contact
                        _contacts.Remove(staleContact.NodeID);
                        return(true);
                    }

                    //no stale contact found to replace with current contact
                    IncrementContactCount();

                    //split current bucket since count > k
                    SplitBucket(this);

                    return(true);
                }

                //never split buckets that arent on the same side of the tree as the current node

                if (_replacementContacts.ContainsKey(contact.NodeID))
                {
                    _replacementContacts[contact.NodeID].UpdateLastSeenTime();
                    return(true);
                }

                if (_replacementContacts.Count < DhtClient.KADEMLIA_K)
                {
                    //keep the current node contact in replacement cache
                    _replacementContacts.Add(contact.NodeID, contact);
                    IncrementReplacementContactCount();
                    return(true);
                }

                //find stale contact from replacement cache and replace with current contact
                NodeContact staleReplacementContact = null;

                foreach (NodeContact replacementContact in _replacementContacts.Values)
                {
                    if (replacementContact.IsStale())
                    {
                        staleReplacementContact = replacementContact;
                        break;
                    }
                }

                if (staleReplacementContact == null)
                {
                    return(false);
                }

                //remove bad contact & keep the current node contact in replacement cache
                _replacementContacts.Remove(staleReplacementContact.NodeID);
                _replacementContacts.Add(contact.NodeID, contact);
                return(true);
            }
            finally
            {
                _lock.ExitWriteLock();
            }
        }