Beispiel #1
0
        /// <summary>
        /// Find contact's closest nodes to id
        /// </summary>
        /// <param name="node">Node to query</param>
        /// <param name="id">Id to compare</param>
        /// <returns>Closest nodes to id</returns>
        public IEnumerable <ContactNode> FindNode(ContactNode node, Id id)
        {
            Message.MnlMessage msg = new Message.MnlMessage.Builder()
                                     .SetType(MessageType.Query)
                                     .SetQueryType(QueryType.FindNode)
                                     .SetOriginatorId(Id)
                                     .Build();

            msg.Payload.Add("target", id.Value);
            Message.MnlMessage response = _server.SendMessageSync(node, msg, _validateMsgs, TimeoutInMSec).Response;
            List <ContactNode> nodes    = new List <ContactNode>();

            if (response == null)
            {
                return(nodes);
            }

            UpdateLastSeen(node);

            if (response.Payload.ContainsKey("nodes"))
            {
                byte[] nodeString = (byte[])response.Payload["nodes"];
                int    offset     = 0;
                while (offset < nodeString.Length)
                {
                    nodes.Add(new ContactNode(nodeString, ref offset));
                }
            }

            return(nodes);
        }
Beispiel #2
0
        public MnlMessage SendMessageSync(ContactNode toNode, Message.MnlMessage msg, bool validate, int timeout)
        {
            msg.TranId = GenerateTranId();

            ManualResetEventSlim eventReset = new ManualResetEventSlim();

            msg.AddCallback((m) => eventReset.Set());
            ulong msgId = GetMessageId(toNode.EndPoint.Address, BitConverter.ToUInt16(Encoding.ASCII.GetBytes(msg.TranId), 0));

            _messages.AddOrUpdate(msgId,
                                  new PendingMnlMessage()
            {
                RecipientId = toNode.Id,
                SentMessage = msg,
                ValidateId  = validate
            }, (k, v) => v);

            byte[] rawMsg = msg.ToBytes();

            _udpClient.Send(rawMsg, rawMsg.Length, toNode.EndPoint);

            if (eventReset.Wait(timeout))
            {
                PendingMnlMessage msgFromQueue;
                if (_messages.TryRemove(msgId, out msgFromQueue))
                {
                    return(msgFromQueue.SentMessage);
                }
            }

            return(msg);
        }
Beispiel #3
0
        private void UpdateLastSeen(ContactNode node)
        {
            var bucket = BucketList.GetBucket(node.Id);

            if (bucket.Contains(node.Id))
            {
                bucket.SeenNow(node);
            }
        }
Beispiel #4
0
        /// <summary>
        /// Pings other node
        /// </summary>
        /// <param name="node">Node to ping</param>
        /// <returns></returns>
        public MnlMessage Ping(ContactNode node)
        {
            Message.MnlMessage msg = new Message.MnlMessage.Builder()
                                     .SetType(MessageType.Query)
                                     .SetQueryType(QueryType.Ping)
                                     .SetOriginatorId(Id)
                                     .Build();

            UpdateLastSeen(node);
            return(_server.SendMessageSync(node, msg, _validateMsgs, TimeoutInMSec).Response);
        }
Beispiel #5
0
        /// <summary>
        /// Find contact's closest nodes to id
        /// </summary>
        /// <param name="node">Node to query</param>
        /// <param name="id">Id to compare</param>
        /// <returns>Closest nodes to id</returns>
        public bool GetPeers(ContactNode node, Id infohash, out IEnumerable <ContactNode> nodes, out object token)
        {
            Message.MnlMessage msg = new Message.MnlMessage.Builder()
                                     .SetType(MessageType.Query)
                                     .SetQueryType(QueryType.GetPeers)
                                     .SetOriginatorId(Id)
                                     .SetInfohash(infohash)
                                     .Build();

            UpdateLastSeen(node);

            Message.MnlMessage response = _server.SendMessageSync(node, msg, _validateMsgs, TimeoutInMSec).Response;
            List <ContactNode> contacts = new List <ContactNode>();

            nodes = contacts;
            token = null;

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

            if (response.Payload.ContainsKey("token"))
            {
                token = response.Payload["token"];
            }

            if (response.Payload.ContainsKey("values"))
            {
                List <object> valuesStrings = (List <object>)response.Payload["values"];

                foreach (object peerInfo in valuesStrings)
                {
                    contacts.Add(ContactNode.FromPeerInfo(peerInfo as byte[]));
                }

                return(true);
            }
            else if (response.Payload.ContainsKey("nodes"))
            {
                byte[] nodeString = (byte[])response.Payload["nodes"];
                int    offset     = 0;
                while (offset < nodeString.Length)
                {
                    contacts.Add(new ContactNode(nodeString, ref offset));
                }

                return(false);
            }


            return(false);
        }
Beispiel #6
0
        public bool TryReplaceLeastSeenContactFromBucket(ContactNode newContact)
        {
            var bucket    = Owner.BucketList.GetBucket(newContact.Id);
            var leastSeen = bucket.GetLeastSeen();

            Message.MnlMessage pongMsg = Owner.Ping(leastSeen);

            if (pongMsg == null)
            {
                bucket.Replace(leastSeen.Id, newContact);
                return(true);
            }

            return(false);
        }
Beispiel #7
0
        /// <summary>
        /// Find contact's closest nodes to id
        /// </summary>
        /// <param name="node">Node to query</param>
        /// <param name="id">Id to compare</param>
        /// <returns></returns>
        public MnlMessage AnnouncePeer(ContactNode node, Id infohash, int port, object token, int?impliedPort)
        {
            Message.MnlMessage msg = new Message.MnlMessage.Builder()
                                     .SetType(MessageType.Query)
                                     .SetQueryType(QueryType.AnnouncePeer)
                                     .SetOriginatorId(Id)
                                     .SetInfohash(infohash)
                                     .Build();

            msg.Payload.Add("port", port);
            msg.Payload.Add("implied_port", impliedPort ?? 0);
            msg.Payload.Add("token", token ?? new byte[0]);

            UpdateLastSeen(node);

            return(_server.SendMessageSync(node, msg, _validateMsgs, TimeoutInMSec).Response);
        }
Beispiel #8
0
        private void LookupNodes(Id nodeId, CancellationToken cancelToken)
        {
            SortedSet <Id> queriedNodes = new SortedSet <Id>(new Id.IdComparer());

            List <Task> tasks          = new List <Task>(MaxConcurrentThreads);
            int         triesCount     = 0;
            ContactNode closestContact = Owner.BucketList.GetClosestContactToId(nodeId);

            if (closestContact == null)
            {
                return;
            }

            Id prevClosestId = closestContact.Id ^ nodeId;

            while (queriedNodes.Count < 256)
            {
                var shortListSnapshot = Owner.BucketList.GetClosestNodes(nodeId, MaxConcurrentThreads).Where((n) => !queriedNodes.Contains(n.Id)).ToList();
                foreach (var node in shortListSnapshot)
                {
                    tasks.Add(Task.Run(() => {
                        IEnumerable <ContactNode> contacts = Owner.FindNode(node, nodeId);
                        foreach (var contact in contacts)
                        {
                            if (Owner.BucketList.Put(contact) == Buckets.BucketList.BucketPutResult.BucketIsFull)
                            {
                                TryReplaceLeastSeenContactFromBucket(contact);
                            }
                        }

                        Debug.WriteLine($"Added {contacts.Count()} contacts");
                    }));

                    queriedNodes.Add(node.Id);

                    if (tasks.Count >= MaxConcurrentThreads)
                    {
                        break;
                    }

                    Debug.WriteLine($"Queried nodes count - {queriedNodes.Count}");
                }
                try {
                    Task.WaitAll(tasks.ToArray(), cancelToken);
                    tasks.Clear();
                } catch (OperationCanceledException) {
                    return;
                }
                ContactNode closestNode = Owner.BucketList.GetClosestContactToId(nodeId);

                Id currentMin = closestNode.Id ^ nodeId;
                if (currentMin >= prevClosestId)
                {
                    if (triesCount < ReplicationCount)
                    {
                        triesCount++;
                        continue;
                    }

                    //Can't get any closer, stopping.
                    Debug.WriteLine($"Can't get any closer, breaking search");
                    break;
                }

                prevClosestId = currentMin;
            }
        }
Beispiel #9
0
        /// <summary>
        /// Processes request from other node. Used by NodeServer class
        /// </summary>
        /// <param name="msg">Request to process</param>
        /// <param name="origAddress">Request originator adress</param>
        public void ProcessQuery(Message.MnlMessage msg, IPEndPoint origAddress)
        {
            switch (msg.QueryType)
            {
            case QueryType.Ping: {
                _server.SendMessage(origAddress, PrepareResponse(msg));
                break;
            }

            case QueryType.FindNode: {
                Message.MnlMessage response = PrepareResponse(msg);

                Id  targetId     = new Id((byte[])msg.Payload["target"]);
                var closestNodes = BucketList.GetClosestNodes(targetId, NodesPerQuery);
                response.Payload.Add("nodes", closestNodes.Select((n) => n.ToBytes()).ToList());

                _server.SendMessage(origAddress, response);
                break;
            }

            case QueryType.GetPeers: {
                Message.MnlMessage response = PrepareResponse(msg);

                Id targetId = new Id((byte[])msg.Payload["info_hash"]);

                if (Storage.ContainsPeersFor(targetId))
                {
                    response.Payload.Add("values", Storage.GetForinfoHash(targetId)
                                         .Select((n) => n.ToBytes(true)).ToList());
                    response.Payload.Add("token", _tokenStorage.AcquireNewToken(origAddress.Address).AsBytes());
                }
                else
                {
                    response.Payload.Add("nodes", BucketList.GetClosestNodes(targetId, NodesPerQuery)
                                         .Select((n) => n.ToBytes()).ToList());
                }

                _server.SendMessage(origAddress, response);
                break;
            }

            case QueryType.AnnouncePeer: {
                Message.MnlMessage response = PrepareResponse(msg);

                Token token = Token.FromBytes((byte[])msg.Payload["token"]);
                if (_tokenStorage.Validate(origAddress.Address, token))
                {
                    Id          infoHash         = new Id((byte[])msg.Payload["info_hash"]);
                    Id          originatorId     = new Id((byte[])msg.Payload["id"]);
                    Bucket      originatorBucket = BucketList.GetBucket(originatorId);
                    ContactNode originatorNode   = originatorBucket.GetNode(originatorId);
                    bool        isImpliedPort    = !msg.Payload.ContainsKey("port") || (int)msg.Payload["port"] > 0;
                    originatorNode.UtpPort = isImpliedPort ? originatorNode.EndPoint.Port : (int)msg.Payload["port"];

                    Storage.Put(originatorNode, infoHash);

                    _server.SendMessage(origAddress, response);
                }
                else
                {
                    _server.SendBadToken(origAddress);
                }

                break;
            }
            }

            Id msgOrigId = new Id((byte[])msg.Payload["id"]);

            var bucket = BucketList.GetBucket(msgOrigId);
            //UpdateLastSeen(bucket.GetNode(msgOrigId));
        }