/// <summary>
        /// An announcement has been received (via unconnected message); react accordingly.
        /// </summary>
        private void OnAnnounceResponseReceived(AnnounceResponseMessage message, IPEndPoint endpoint)
        {
            // heed only ipv4 for now... TBD what to do about this
            if (endpoint.AddressFamily == AddressFamily.InterNetwork)
            {
                PeerAnnounceResponseCount++;

                logger?.WriteNet(NetLogLevel.Trace, $"DistributedHost.OnAnnounceResponseReceived({endpoint}) -- {ConnectionsStatusString()}");

                // we shouldn't know this peer yet, let's check.
                if (netManager.ConnectedPeerList.Any(peer => peer.EndPoint.Equals(endpoint)))
                {
                    // surprise, we do! must have been a race.
                    return;
                }

                if (AnnouncedEndPoints.Contains(endpoint))
                {
                    return;
                }

                AnnouncedEndPoints.Add(endpoint);

                logger?.WriteNet(NetLogLevel.Info, $"DistributedHost.OnAnnounceResponseReceived({endpoint}) -- sending connect request");

                // So, connect away. (Note this could still race -- Connect is thread-safe but the
                // AddPeer method is not. TODO: look at fixing this.)
                // Deliberately ignore the netPeer return value; we let the OnPeerConnected event carry the ball.
                netManager.Connect(endpoint, RequestKey);
            }
        }
Example #2
0
        /// <summary>
        /// Called when announce is requested.
        /// </summary>
        protected override void OnAnnounce()
        {
            AnnounceResponseMessage message;
            Uri uri;

            this.OnAnnouncing(this, EventArgs.Empty);

            try
            {
                uri = this.GetUri();

                Debug.WriteLine($"{this.TrackerUri} -> {uri}");

                if (AnnounceResponseMessage.TryDecode(uri.ExecuteBinaryRequest(), out message))
                {
                    Debug.WriteLine($"{this.TrackerUri} <- {message}");

                    this.UpdateInterval = message.UpdateInterval;

                    this.OnAnnounced(this, new AnnouncedEventArgs(message.UpdateInterval, message.LeecherCount, message.SeederCount, message.Peers));
                }
            }
            catch (Exception ex)
            {
                Debug.WriteLine($"could not send message to HTTP tracker {this.TrackerUri} for torrent {this.TorrentInfoHash}: {ex.Message}");
            }
        }
Example #3
0
        public static UdpTrackerMessage DecodeMessage(byte[] buffer, int offset, int count, MessageType type)
        {
            UdpTrackerMessage m = null;
            int action          = type == MessageType.Request ? ReadInt(buffer, offset + 8) : ReadInt(buffer, offset);

            switch (action)
            {
            case 0:
                if (type == MessageType.Request)
                {
                    m = new ConnectMessage();
                }
                else
                {
                    m = new ConnectResponseMessage();
                }
                break;

            case 1:
                if (type == MessageType.Request)
                {
                    m = new AnnounceMessage();
                }
                else
                {
                    m = new AnnounceResponseMessage();
                }
                break;

            case 2:
                if (type == MessageType.Request)
                {
                    m = new ScrapeMessage();
                }
                else
                {
                    m = new ScrapeResponseMessage();
                }
                break;

            case 3:
                m = new ErrorMessage();
                break;

            default:
                throw new ProtocolException(string.Format("Invalid udp message received: {0}", buffer[offset]));
            }

            try
            {
                m.Decode(buffer, offset, count);
            }
            catch
            {
                m = new ErrorMessage(0, "Couldn't decode the tracker response");
            }
            return(m);
        }
        //QUICKHACK: format bencoded val and get it back wereas must refactor tracker system to have more generic object...
        protected virtual void ReceiveAnnounce(AnnounceMessage announceMessage)
        {
            UdpTrackerMessage  m;
            BEncodedDictionary dict = Handle(getCollection(announceMessage), endpoint.Address, false);

            if (dict.ContainsKey(RequestParameters.FailureKey))
            {
                m = new ErrorMessage(announceMessage.TransactionId, dict[RequestParameters.FailureKey].ToString());
            }
            else
            {
                TimeSpan interval = TimeSpan.Zero;
                int      leechers = 0;
                int      seeders  = 0;
                List <System.Net.BitTorrent.Client.Peer> peers = new List <System.Net.BitTorrent.Client.Peer>();
                foreach (KeyValuePair <BEncodedString, BEncodedValue> keypair in dict)
                {
                    switch (keypair.Key.Text)
                    {
                    case ("complete"):
                        seeders = Convert.ToInt32(keypair.Value.ToString());    //same as seeder?
                        break;

                    case ("incomplete"):
                        leechers = Convert.ToInt32(keypair.Value.ToString());    //same as leecher?
                        break;

                    case ("interval"):
                        interval = TimeSpan.FromSeconds(int.Parse(keypair.Value.ToString()));
                        break;

                    case ("peers"):
                        if (keypair.Value is BEncodedList)              // Non-compact response
                        {
                            peers.AddRange(System.Net.BitTorrent.Client.Peer.Decode((BEncodedList)keypair.Value));
                        }
                        else if (keypair.Value is BEncodedString)       // Compact response
                        {
                            peers.AddRange(System.Net.BitTorrent.Client.Peer.Decode((BEncodedString)keypair.Value));
                        }
                        break;

                    default:
                        break;
                    }
                }
                m = new AnnounceResponseMessage(announceMessage.TransactionId, interval, leechers, seeders, peers);
            }
            byte[] data = m.Encode();
#if NETSTANDARD1_5
            listener.SendAsync(data, data.Length, endpoint);
#else
            listener.Send(data, data.Length, endpoint);
#endif
        }
Example #5
0
        public void AnnounceResponseTest()
        {
            var peers = peerEndpoints.Select(t => new Peer("", new Uri($"ipv4://{t.Address}:{t.Port}"))).ToList();
            AnnounceResponseMessage m = new AnnounceResponseMessage(12345, TimeSpan.FromSeconds(10), 43, 65, peers);
            AnnounceResponseMessage d = (AnnounceResponseMessage)UdpTrackerMessage.DecodeMessage(m.Encode(), 0, m.ByteLength, MessageType.Response);

            Check(m, MessageType.Response);

            Assert.AreEqual(1, m.Action);
            Assert.AreEqual(m.Action, d.Action);
            Assert.IsTrue(Toolbox.ByteMatch(m.Encode(), d.Encode()));
            Assert.AreEqual(12345, d.TransactionId);
        }
        //QUICKHACK: format bencoded val and get it back wereas must refactor tracker system to have more generic object...
        protected virtual async Task ReceiveAnnounce(UdpClient client, AnnounceMessage announceMessage, IPEndPoint remotePeer)
        {
            UdpTrackerMessage  m;
            BEncodedDictionary dict = Handle(getCollection(announceMessage), remotePeer.Address, false);

            if (dict.ContainsKey(TrackerRequest.FailureKey))
            {
                m = new ErrorMessage(announceMessage.TransactionId, dict[TrackerRequest.FailureKey].ToString());
            }
            else
            {
                TimeSpan interval = TimeSpan.Zero;
                int      leechers = 0;
                int      seeders  = 0;
                var      peers    = new List <MonoTorrent.Client.Peer> ();
                foreach (KeyValuePair <BEncodedString, BEncodedValue> keypair in dict)
                {
                    switch (keypair.Key.Text)
                    {
                    case ("complete"):
                        seeders = Convert.ToInt32(keypair.Value.ToString());      //same as seeder?
                        break;

                    case ("incomplete"):
                        leechers = Convert.ToInt32(keypair.Value.ToString());      //same as leecher?
                        break;

                    case ("interval"):
                        interval = TimeSpan.FromSeconds(int.Parse(keypair.Value.ToString()));
                        break;

                    case ("peers"):
                        if (keypair.Value is BEncodedList)              // Non-compact response
                        {
                            peers.AddRange(MonoTorrent.Client.Peer.Decode((BEncodedList)keypair.Value));
                        }
                        else if (keypair.Value is BEncodedString)       // Compact response
                        {
                            peers.AddRange(MonoTorrent.Client.Peer.Decode((BEncodedString)keypair.Value));
                        }
                        break;

                    default:
                        break;
                    }
                }
                m = new AnnounceResponseMessage(announceMessage.TransactionId, interval, leechers, seeders, peers);
            }
            byte[] data = m.Encode();
            await client.SendAsync(data, data.Length, remotePeer);
        }
Example #7
0
        private void CompleteAnnounce(UdpTrackerMessage message, object state)
        {
            ErrorMessage error = message as ErrorMessage;

            if (error != null)
            {
                FailureMessage = error.Error;
                DoAnnounceComplete(false, state, new List <Peer>());
            }
            else
            {
                AnnounceResponseMessage response = (AnnounceResponseMessage)message;
                DoAnnounceComplete(true, state, response.Peers);

                //TODO seeders and leechers is not used in event.
            }
        }
Example #8
0
        public void AnnounceResponseTest()
        {
            List <Peer> peers = new List <Peer>();

            peers.Add(new Peer(new string('1', 20), new Uri("tcp://127.0.0.1:1")));
            peers.Add(new Peer(new string('2', 20), new Uri("tcp://127.0.0.1:2")));
            peers.Add(new Peer(new string('3', 20), new Uri("tcp://127.0.0.1:3")));

            AnnounceResponseMessage m = new AnnounceResponseMessage(12345, TimeSpan.FromSeconds(10), 43, 65, peers);
            AnnounceResponseMessage d = (AnnounceResponseMessage)UdpTrackerMessage.DecodeMessage(m.Encode(), 0, m.ByteLength, MessageType.Response);

            Check(m, MessageType.Response);

            Assert.AreEqual(1, m.Action);
            Assert.AreEqual(m.Action, d.Action);
            Assert.IsTrue(Toolbox.ByteMatch(m.Encode(), d.Encode()));
            Assert.AreEqual(12345, d.TransactionId);
        }
        /// <summary>
        /// An announcement has been received (via broadcast); react accordingly.
        /// </summary>
        private void OnAnnounceReceived(AnnounceMessage message, IPEndPoint endpoint)
        {
            // heed only ipv4 for now... TBD what to do about this
            if (endpoint.AddressFamily == AddressFamily.InterNetwork)
            {
                // is this actually our own announcement!?
                SerializedSocketAddress incomingAddress = new SerializedSocketAddress(endpoint.Serialize());
                if (incomingAddress == this.SocketAddress)
                {
                    // ignore this, we're talking to ourselves
                    return;
                }

                PeerAnnounceCount++;

                // do we know this peer already?
                // (could happen in race scenario)
                if (netManager.ConnectedPeerList.Any(peer => peer.EndPoint.Equals(endpoint)))
                {
                    return;
                }

                // did we already respond to this peer?
                if (AnnouncedEndPoints.Contains(endpoint))
                {
                    return;
                }

                // did this peer know us already? (typical scenario given re-announcements)
                if (message.KnownPeers.Contains(SocketAddress))
                {
                    return;
                }

                logger?.WriteNet(NetLogLevel.Trace, $"DistributedHost.OnAnnounceReceived({endpoint}) -- responding. {ConnectionsStatusString()}]");

                // send announce response
                AnnounceResponseMessage response = new AnnounceResponseMessage {
                };
                SendUnconnectedMessage(response, endpoint);
            }
        }
        public static UdpTrackerMessage DecodeMessage(byte[] buffer, int offset, int count, MessageType type)
        {
            UdpTrackerMessage m = null;
            var action = type == MessageType.Request ? ReadInt(buffer, offset + 8) : ReadInt(buffer, offset);
            switch (action)
            {
                case 0:
                    if (type == MessageType.Request)
                        m = new ConnectMessage();
                    else
                        m = new ConnectResponseMessage();
                    break;
                case 1:
                    if (type == MessageType.Request)
                        m = new AnnounceMessage();
                    else
                        m = new AnnounceResponseMessage();
                    break;
                case 2:
                    if (type == MessageType.Request)
                        m = new ScrapeMessage();
                    else
                        m = new ScrapeResponseMessage();
                    break;
                case 3:
                    m = new ErrorMessage();
                    break;
                default:
                    throw new ProtocolException(string.Format("Invalid udp message received: {0}", buffer[offset]));
            }

            try
            {
                m.Decode(buffer, offset, count);
            }
            catch
            {
                m = new ErrorMessage(0, "Couldn't decode the tracker response");
            }
            return m;
        }
        public void AnnounceResponseMessage_TryDecode()
        {
            AnnounceResponseMessage message;

            byte[] data = "00000001 00003300 00000002 00000003 00000004 09080706 2002 01020304 3003".Replace(" ", string.Empty).ToByteArray();

            if (AnnounceResponseMessage.TryDecode(data, 0, out message))
            {
                Assert.AreEqual(32, message.Length);
                Assert.AreEqual(1, (int)message.Action);
                Assert.AreEqual(13056, message.TransactionId);
                Assert.AreEqual(2, message.Interval.TotalSeconds);
                Assert.AreEqual(3, message.LeecherCount);
                Assert.AreEqual(4, message.SeederCount);
                Assert.AreEqual(2, message.Peers.Count());
                Assert.AreEqual(new IPEndPoint(IPAddress.Parse("9.8.7.6"), 8194), message.Peers.ElementAt(0));
                Assert.AreEqual(new IPEndPoint(IPAddress.Parse("1.2.3.4"), 12291), message.Peers.ElementAt(1));
                CollectionAssert.AreEqual(data, message.Encode());
            }
            else
            {
                Assert.Fail();
            }
        }
Example #12
0
        public void AnnounceResponseTest()
        {
            var peers = new List<Peer>
                            {
                                new Peer(new string('1', 20), new Uri("tcp://127.0.0.1:1")),
                                new Peer(new string('2', 20), new Uri("tcp://127.0.0.1:2")),
                                new Peer(new string('3', 20), new Uri("tcp://127.0.0.1:3"))
                            };

            var m = new AnnounceResponseMessage(12345, TimeSpan.FromSeconds(10), 43, 65, peers);
            var d =
                (AnnounceResponseMessage)
                UdpTrackerMessage.DecodeMessage(m.Encode(), 0, m.ByteLength, MessageType.Response);
            Check(m, MessageType.Response);

            Assert.AreEqual(1, m.Action);
            Assert.AreEqual(m.Action, d.Action);
            Assert.IsTrue(Toolbox.ByteMatch(m.Encode(), d.Encode()));
            Assert.AreEqual(12345, d.TransactionId);
        }