예제 #1
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();
                }
            }
        }
예제 #2
0
        private EndPoint[] QueryAnnounce(NodeContact[] initialContacts, BinaryNumber networkId, EndPoint serviceEP)
        {
            NodeContact[] contacts = QueryFindNode(initialContacts, networkId);

            if ((contacts == null) || (contacts.Length == 0))
            {
                return(null);
            }

            List <EndPoint> peers = new List <EndPoint>();

            lock (peers)
            {
                int respondedContacts = 0;

                foreach (NodeContact contact in contacts)
                {
                    ThreadPool.QueueUserWorkItem(delegate(object state)
                    {
                        DhtRpcPacket response = Query(DhtRpcPacket.CreateAnnouncePeerPacketQuery(_currentNode, networkId, serviceEP), contact);
                        if ((response != null) && (response.Type == DhtRpcType.ANNOUNCE_PEER) && (response.Peers.Length > 0))
                        {
                            lock (peers)
                            {
                                foreach (EndPoint peer in response.Peers)
                                {
                                    if (!peers.Contains(peer))
                                    {
                                        peers.Add(peer);
                                    }
                                }

                                respondedContacts++;

                                if (respondedContacts == contacts.Length)
                                {
                                    Monitor.Pulse(peers);
                                }
                            }
                        }
                    });
                }

                if (Monitor.Wait(peers, _queryTimeout))
                {
                    return(peers.ToArray());
                }

                return(null);
            }
        }
예제 #3
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);
                });
            }
        }
예제 #4
0
        public void AcceptConnection(Stream s, EndPoint remoteNodeEP)
        {
            //set timeout
            s.WriteTimeout = _queryTimeout;
            s.ReadTimeout  = _queryTimeout;

            BinaryReader bR = new BinaryReader(s);
            BinaryWriter bW = new BinaryWriter(s);

            DhtRpcPacket response = ProcessQuery(new DhtRpcPacket(bR), remoteNodeEP);

            if (response == null)
            {
                return;
            }

            response.WriteTo(bW);
            s.Flush();
        }
예제 #5
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));
                        }
                    }
                }
            }
        }
예제 #6
0
        internal bool Ping(NodeContact contact)
        {
            DhtRpcPacket response = Query(DhtRpcPacket.CreatePingPacket(_currentNode), contact);

            return(response != null);
        }
예제 #7
0
        private DhtRpcPacket ProcessQuery(DhtRpcPacket query, EndPoint remoteNodeEP)
        {
            //in case of remote node querying via Tor, remoteNodeEP.Address will be loopback IP. Use the onion address from the query as remote end point

            if (!_currentNode.NodeEP.Equals(remoteNodeEP))
            {
                switch (remoteNodeEP.AddressFamily)
                {
                case AddressFamily.InterNetwork:
                case AddressFamily.InterNetworkV6:
                    IPAddress remoteNodeAddress = (remoteNodeEP as IPEndPoint).Address;

                    if (IPAddress.IsLoopback(remoteNodeAddress) && (query.SourceNodeEP.AddressFamily == AddressFamily.Unspecified) && (query.SourceNodeEP as DomainEndPoint).Address.EndsWith(".onion", StringComparison.OrdinalIgnoreCase))
                    {
                        AddNode(query.SourceNodeEP);     //use the tor hidden end point claimed by remote node
                    }
                    else
                    {
                        AddNode(new IPEndPoint(remoteNodeAddress, query.SourceNodeEP.GetPort()));     //use remote node end point as seen by connection manager and use port from query
                    }
                    break;

                default:
                    throw new NotSupportedException();
                }
            }

            Debug.Write(this.GetType().Name, "query received from: " + remoteNodeEP.ToString() + "; type: " + query.Type.ToString());

            //process query
            switch (query.Type)
            {
            case DhtRpcType.PING:
                return(DhtRpcPacket.CreatePingPacket(_currentNode));

            case DhtRpcType.FIND_NODE:
                return(DhtRpcPacket.CreateFindNodePacketResponse(_currentNode, query.NetworkId, _routingTable.GetKClosestContacts(query.NetworkId, false)));

            case DhtRpcType.FIND_PEERS:
                EndPoint[] peers = _currentNode.GetPeers(query.NetworkId);
                if (peers.Length == 0)
                {
                    return(DhtRpcPacket.CreateFindPeersPacketResponse(_currentNode, query.NetworkId, _routingTable.GetKClosestContacts(query.NetworkId, false), peers));
                }
                else
                {
                    return(DhtRpcPacket.CreateFindPeersPacketResponse(_currentNode, query.NetworkId, new NodeContact[] { }, peers));
                }

            case DhtRpcType.ANNOUNCE_PEER:
                if ((query.Peers != null) && (query.Peers.Length > 0))
                {
                    EndPoint peerEP;

                    if (query.Peers[0].AddressFamily == AddressFamily.Unspecified)
                    {
                        peerEP = query.Peers[0];
                    }
                    else
                    {
                        peerEP = new IPEndPoint((remoteNodeEP as IPEndPoint).Address, query.Peers[0].GetPort());
                    }

                    _currentNode.StorePeer(query.NetworkId, peerEP);
                }

                return(DhtRpcPacket.CreateAnnouncePeerPacketResponse(_currentNode, query.NetworkId, _currentNode.GetPeers(query.NetworkId)));

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