private DhtRpcPacket(int transactionID, NodeContact sourceNode, RpcPacketType type, RpcQueryType queryType)
 {
     _transactionID = transactionID;
     _sourceNode    = sourceNode;
     _type          = type;
     _queryType     = queryType;
 }
Beispiel #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;
                            }
                        }
                    }
                }
            }
        }
Beispiel #3
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
            { }
        }
        public DhtRpcPacket(Stream s, IPAddress nodeIP)
        {
            int version = s.ReadByte();

            switch (version)
            {
            case 1:
                byte[] buffer = new byte[20];

                OffsetStream.StreamRead(s, buffer, 0, 4);
                _transactionID = BitConverter.ToInt32(buffer, 0);

                OffsetStream.StreamRead(s, buffer, 0, 20);
                BinaryID nodeID = BinaryID.Clone(buffer, 0, 20);

                OffsetStream.StreamRead(s, buffer, 0, 2);
                _sourceNode = new NodeContact(nodeID, new IPEndPoint(nodeIP, BitConverter.ToUInt16(buffer, 0)));

                _type      = (RpcPacketType)s.ReadByte();
                _queryType = (RpcQueryType)s.ReadByte();

                switch (_queryType)
                {
                case RpcQueryType.FIND_NODE:
                    OffsetStream.StreamRead(s, buffer, 0, 20);
                    _networkID = BinaryID.Clone(buffer, 0, 20);

                    if (_type == RpcPacketType.Response)
                    {
                        int count = s.ReadByte();
                        _contacts = new NodeContact[count];

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

                case RpcQueryType.FIND_PEERS:
                    OffsetStream.StreamRead(s, buffer, 0, 20);
                    _networkID = BinaryID.Clone(buffer, 0, 20);

                    if (_type == RpcPacketType.Response)
                    {
                        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);
                        }

                        OffsetStream.StreamRead(s, buffer, 0, 20);
                        _token = new BinaryID(buffer);
                    }
                    break;

                case RpcQueryType.ANNOUNCE_PEER:
                    OffsetStream.StreamRead(s, buffer, 0, 20);
                    _networkID = BinaryID.Clone(buffer, 0, 20);

                    if (_type == RpcPacketType.Query)
                    {
                        OffsetStream.StreamRead(s, buffer, 0, 2);
                        _servicePort = BitConverter.ToUInt16(buffer, 0);

                        OffsetStream.StreamRead(s, buffer, 0, 20);
                        _token = new BinaryID(buffer);
                    }
                    break;
                }

                break;

            default:
                throw new IOException("DHT-RPC packet version not supported: " + version);
            }
        }