Example #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);
        }
Example #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);
        }
Example #3
0
            public Builder(byte[] msg)
            {
                Bencoder bencoder   = new Bencoder();
                var      decodedMsg = bencoder.DecodeElement(msg);
                Dictionary <string, object> msgFields = (Dictionary <string, object>)decodedMsg;

                _msg = new MnlMessage();

                try {
                    _msg.TranId = Bencoder.DefEncoding.GetString((byte[])msgFields["t"]);
                } catch (KeyNotFoundException) {
                    throw new MalformedPacketException("t");
                }
                try {
                    _msg.Type = (MessageType)(Bencoder.DefEncoding.GetString((byte[])msgFields["y"])[0]);
                } catch (KeyNotFoundException) {
                    throw new MalformedPacketException("y");
                }

                if (msgFields.ContainsKey("q"))
                {
                    _msg.QueryType = Bencoder.DefEncoding.GetString((byte[])msgFields["q"]);
                }

                switch (_msg.Type)
                {
                case MessageType.Query:
                    try {
                        _msg.Payload = (Dictionary <string, object>)msgFields["a"];
                    } catch (KeyNotFoundException) {
                        throw new MalformedPacketException("a");
                    }
                    break;

                case MessageType.Response:
                    try {
                        _msg.Payload = (Dictionary <string, object>)msgFields["r"];
                    } catch (KeyNotFoundException) {
                        throw new MalformedPacketException("r");
                    }
                    break;

                case MessageType.Error:
                    try {
                        List <object> errList = (List <object>)msgFields["e"];
                        int           codeIdx = errList[0] is int? 0 : 1;
                        _msg.ErrorCode = (ErrorType)errList[codeIdx];
                        if (errList.Count > 1)
                        {
                            _msg.ErrorMessage = Bencoder.DefEncoding.GetString((byte[])errList[codeIdx == 0 ? 1 : 0]); //TODO: ???
                        }
                    } catch (KeyNotFoundException) {
                        throw new MalformedPacketException("e");
                    }
                    return;
                }

                _msg.OriginatorId = new Id((byte[])_msg.Payload["id"]);
            }
Example #4
0
 private MnlMessage PrepareResponse(Message.MnlMessage toMsg)
 {
     return(new Message.MnlMessage.Builder()
            .SetTranId(toMsg.TranId)
            .SetType(MessageType.Response)
            .SetOriginatorId(Id)
            .Build());
 }
Example #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);
        }
Example #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);
        }
Example #7
0
 public void SetResponse(MnlMessage response)
 {
     Response = response;
     OnResponse?.Invoke(response);
 }
Example #8
0
 public Builder()
 {
     _msg = new MnlMessage();
 }
Example #9
0
        private void ListenIncoming(Node ownerNode)
        {
            while (!_stopped)
            {
                try {
                    IPEndPoint incomingIpEndPoint = new IPEndPoint(IPAddress.Any, EndPoint.Port);

                    byte[] rawMsg = _udpClient.Receive(ref incomingIpEndPoint);
                    if (!IsLegitMnlDhtMessage(rawMsg))
                    {
                        continue;
                    }

                    Message.MnlMessage incomingMsg = null;
                    try {
                        incomingMsg = new Message.MnlMessage.Builder(rawMsg).Build();
                    } catch (Bittorrent.InvalidFieldException ife) {
                        MnlMessage errMessage = new MnlMessage.Builder()
                                                .SetTranId(GenerateTranId())
                                                .SetType(MessageType.Error)
                                                .SetErrorCode(ErrorType.ProtocolError)
                                                .SetErrorMessage(ife.Message)
                                                .Build();

                        Debug.WriteLine($"Sending incorrect field message {ife.Message}");
                        SendMessage(incomingIpEndPoint, errMessage);
                        continue;
                    } catch (MalformedPacketException mpe) {
                        MnlMessage errMessage = new MnlMessage.Builder()
                                                .SetTranId(GenerateTranId())
                                                .SetType(MessageType.Error)
                                                .SetErrorCode(ErrorType.ProtocolError)
                                                .SetErrorMessage(mpe.Message)
                                                .Build();

                        Debug.WriteLine($"Sending malformed packet message {mpe.Message}");
                        SendMessage(incomingIpEndPoint, errMessage);
                        continue;
                    }

                    ulong msgIdx = GetMessageId(incomingIpEndPoint.Address, BitConverter.ToUInt16(Encoding.ASCII.GetBytes(incomingMsg.TranId.PadLeft(2, '\0')), 0));
                    if (_messages.ContainsKey(msgIdx))
                    {
                        PendingMnlMessage rqMsg;
                        if (_messages.TryRemove(msgIdx, out rqMsg))
                        {
                            if (incomingMsg.Type == MessageType.Error)
                            {
                                Debug.WriteLine($"Recieved error {incomingMsg.ErrorMessage}");
                                switch (incomingMsg.ErrorCode)
                                {
                                case ErrorType.ProtocolError:
                                case ErrorType.MethodUnknown:
                                    Debug.WriteLine($"!!!Error {incomingMsg.ErrorMessage}");
                                    break;

                                default:
                                    continue;
                                }
                            }

                            if (rqMsg.ValidateId)
                            {
                                if (rqMsg.RecipientId != incomingMsg.OriginatorId)
                                {
                                    Debug.WriteLine($"Node {incomingIpEndPoint} id mismatch!");
                                    OnMaliciousMessage?.Invoke(incomingIpEndPoint, rqMsg.RecipientId, rqMsg.SentMessage);
                                    continue;
                                }
                            }

                            rqMsg.SentMessage.SetResponse(incomingMsg);
                        }
                    }
                    else
                    {
                        if (incomingMsg.Type == MessageType.Query)
                        {
                            ownerNode.ProcessQuery(incomingMsg, incomingIpEndPoint);
                        }
                    }
                } catch (SocketException se) {
                    if (se.SocketErrorCode != SocketError.Interrupted)
                    {
                        throw;
                    }
                }
            }
        }
Example #10
0
 public void SendMessage(IPEndPoint toEndPoint, Message.MnlMessage msg)
 {
     byte[] rawMsg = msg.ToBytes();
     _udpClient.Send(rawMsg, rawMsg.Length, toEndPoint);
 }
Example #11
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));
        }