public async Task SendMetadataCore(string expectedPath)
        {
            CustomConnection connection = pair.Incoming;

            // 1) Send local handshake. We've already received the remote handshake as part
            // of the Connect method.
            var sendHandshake = new HandshakeMessage(rig.Manager.InfoHash, new string('g', 20), VersionInfo.ProtocolStringV100, true, true);
            await PeerIO.SendMessageAsync(connection, encryptor, sendHandshake);

            ExtendedHandshakeMessage exHand = new ExtendedHandshakeMessage(false, rig.Torrent.Metadata.Length);

            exHand.Supports.Add(LTMetadata.Support);
            await PeerIO.SendMessageAsync(connection, encryptor, exHand);

            // 2) Receive the metadata requests from the other peer and fulfill them
            byte[]      buffer = rig.Torrent.Metadata;
            int         length = (buffer.Length + 16383) / 16384;
            PeerMessage m;

            while (length > 0 && (m = await PeerIO.ReceiveMessageAsync(connection, decryptor)) != null)
            {
                LTMetadata metadata = m as LTMetadata;
                if (metadata != null)
                {
                    if (metadata.MetadataMessageType == LTMetadata.eMessageType.Request)
                    {
                        metadata = new LTMetadata(LTMetadata.Support.MessageId, LTMetadata.eMessageType.Data, metadata.Piece, buffer);
                        await PeerIO.SendMessageAsync(connection, encryptor, metadata);

                        length--;
                    }
                }
            }

            // We've sent all the pieces. Now we just wait for the torrentmanager to process them all.
            while (rig.Manager.Mode is MetadataMode)
            {
                System.Threading.Thread.Sleep(10);
            }

            Assert.IsTrue(File.Exists(expectedPath), "#1");
            Torrent torrent = Torrent.Load(expectedPath);

            Assert.AreEqual(rig.Manager.InfoHash, torrent.InfoHash, "#2");
        }
        public async Task RequestMetadata()
        {
            await Setup(false, "path.torrent");

            CustomConnection connection = pair.Incoming;

            // 1) Send local handshake. We've already received the remote handshake as part
            // of the Connect method.
            var sendHandshake = new HandshakeMessage(rig.Manager.Torrent.InfoHash, new string('g', 20), VersionInfo.ProtocolStringV100, true, true);
            await PeerIO.SendMessageAsync(connection, encryptor, sendHandshake);

            ExtendedHandshakeMessage exHand = new ExtendedHandshakeMessage(false, rig.TorrentDict.LengthInBytes(), 5555);

            exHand.Supports.Add(LTMetadata.Support);
            await PeerIO.SendMessageAsync(connection, encryptor, exHand);

            // 2) Send all our metadata requests
            int length = (rig.TorrentDict.LengthInBytes() + 16383) / 16384;

            for (int i = 0; i < length; i++)
            {
                await PeerIO.SendMessageAsync(connection, encryptor, new LTMetadata(LTMetadata.Support.MessageId, LTMetadata.eMessageType.Request, i, null));
            }
            // 3) Receive all the metadata chunks
            PeerMessage m;
            var         stream = new MemoryStream();

            while (length > 0 && (m = await PeerIO.ReceiveMessageAsync(connection, decryptor)) != null)
            {
                LTMetadata metadata = m as LTMetadata;
                if (metadata != null)
                {
                    if (metadata.MetadataMessageType == LTMetadata.eMessageType.Data)
                    {
                        stream.Write(metadata.MetadataPiece, 0, metadata.MetadataPiece.Length);
                        length--;
                    }
                }
            }

            // 4) Verify the hash is the same.
            stream.Position = 0;
            Assert.AreEqual(rig.Torrent.InfoHash, new InfoHash(new SHA1Managed().ComputeHash(stream)), "#1");
        }
Beispiel #3
0
        protected virtual void HandleExtendedHandshakeMessage(PeerId id, ExtendedHandshakeMessage message)
        {
            // FIXME: Use the 'version' information
            // FIXME: Recreate the uri? Give warning?
            if (message.LocalPort > 0)
            {
                id.Peer.LocalPort = message.LocalPort;
            }
            id.MaxSupportedPendingRequests = Math.Max(1, message.MaxRequests);
            id.ExtensionSupports           = message.Supports;

            if (id.ExtensionSupports.Supports(PeerExchangeMessage.Support.Name))
            {
                if (manager.HasMetadata && !manager.Torrent.IsPrivate)
                {
                    id.PeerExchangeManager = new PeerExchangeManager(id);
                }
            }
        }
Beispiel #4
0
        protected override void HandleExtendedHandshakeMessage(PeerId id, ExtendedHandshakeMessage message)
        {
            base.HandleExtendedHandshakeMessage(id, message);

            if (!id.ExtensionSupports.Supports(LTMetadata.Support.Name))
            {
                return;
            }
            Stream = new MemoryStream(new byte[message.MetadataSize], 0, message.MetadataSize, true, true);
            var size = message.MetadataSize % LTMetadata.BlockSize;

            if (size > 0)
            {
                size = 1;
            }
            size     += message.MetadataSize / LTMetadata.BlockSize;
            _bitField = new BitField(size);
            RequestNextNeededPiece(id);
        }
Beispiel #5
0
        protected virtual void HandleExtendedHandshakeMessage (PeerId id, ExtendedHandshakeMessage message)
        {
            // FIXME: Use the 'version' information
            // FIXME: Recreate the uri? Give warning?
            if (message.LocalPort > 0)
                id.Peer.LocalPort = message.LocalPort;

            // If MaxRequests is zero, or negative, ignore it.
            if (message.MaxRequests > 0)
                id.MaxSupportedPendingRequests = message.MaxRequests;
            else
                Logger.Log (id.Connection, "Invalid value for libtorrent extension handshake 'MaxRequests'.");

            // Bugfix for MonoTorrent older than 1.0.19
            if (id.ClientApp.Client == ClientApp.MonoTorrent)
                id.MaxSupportedPendingRequests = Math.Max (id.MaxSupportedPendingRequests, 192);

            id.ExtensionSupports = message.Supports;

            if (id.ExtensionSupports.Supports (PeerExchangeMessage.Support.Name)) {
                if (Manager.HasMetadata && !Manager.Torrent.IsPrivate)
                    id.PeerExchangeManager = new PeerExchangeManager (Manager, id);
            }
        }
Beispiel #6
0
        internal async Task SendMetadataCore(string expectedPath, PeerMessage sendAfterHandshakeMessage, bool metadataOnly = false)
        {
            CustomConnection connection = pair.Incoming;
            var metadataTcs             = new TaskCompletionSource <byte[]> ();

            rig.Manager.MetadataReceived += (o, e) => metadataTcs.TrySetResult(e);

            // 1) Send local handshake. We've already received the remote handshake as part
            // of the Connect method.
            var sendHandshake = new HandshakeMessage(rig.Manager.InfoHash, new string ('g', 20), VersionInfo.ProtocolStringV100, true, true);
            await PeerIO.SendMessageAsync(connection, encryptor, sendHandshake);

            ExtendedHandshakeMessage exHand = new ExtendedHandshakeMessage(false, rig.Torrent.InfoMetadata.Length, 5555);

            exHand.Supports.Add(LTMetadata.Support);
            await PeerIO.SendMessageAsync(connection, encryptor, exHand);

            await PeerIO.SendMessageAsync(connection, encryptor, sendAfterHandshakeMessage);

            bool receivedHaveNone = false;

            // 2) Receive the metadata requests from the other peer and fulfill them
            byte[]      buffer            = rig.Torrent.InfoMetadata;
            var         unrequestedPieces = new HashSet <int> (Enumerable.Range(0, (buffer.Length + 16383) / 16384));
            PeerMessage m;

            while (unrequestedPieces.Count > 0 && (m = await PeerIO.ReceiveMessageAsync(connection, decryptor)) != null)
            {
                if (m is ExtendedHandshakeMessage ex)
                {
                    Assert.IsNull(ex.MetadataSize);
                    Assert.AreEqual(ClientEngine.DefaultMaxPendingRequests, ex.MaxRequests);
                }
                else if (m is HaveNoneMessage)
                {
                    receivedHaveNone = true;
                }
                else if (m is LTMetadata metadata)
                {
                    if (metadata.MetadataMessageType == LTMetadata.eMessageType.Request)
                    {
                        metadata = new LTMetadata(LTMetadata.Support.MessageId, LTMetadata.eMessageType.Data, metadata.Piece, buffer);
                        await PeerIO.SendMessageAsync(connection, encryptor, metadata);

                        unrequestedPieces.Remove(metadata.Piece);

                        // Hack this in because testing is... awkward... for most of this library.
                        // The purpose here is to ensure that duplicate pieces don't reset our data or cause the event
                        // to be emitted multiple times.
                        if (unrequestedPieces.Count > 0)
                        {
                            metadata = new LTMetadata(LTMetadata.Support.MessageId, LTMetadata.eMessageType.Data, 0, buffer);
                            await PeerIO.SendMessageAsync(connection, encryptor, metadata);
                        }

                        // And let's receive many handshake messages from other peers. Ensure we process this on the correct
                        // thread. It needs to be on the main loop as it's run in the context of the ClientEngine loop.
                        if (rig.Manager.Mode is MetadataMode mode)
                        {
                            ClientEngine.MainLoop.Post(state => mode.HandleMessage(PeerId.CreateNull(12389), exHand), null);
                        }
                    }
                }
            }

            // We've sent all the pieces. Now we just wait for the torrentmanager to process them all.
            Torrent torrent;

            if (metadataOnly)
            {
                torrent = Torrent.Load(await metadataTcs.Task.WithTimeout());
            }
            else
            {
                await rig.Manager.WaitForState(TorrentState.Downloading).WithTimeout();

                Assert.IsTrue(File.Exists(expectedPath), "#1");
                torrent = Torrent.Load(expectedPath);
            }

            Assert.AreEqual(rig.Manager.InfoHash, torrent.InfoHash, "#2");
            Assert.AreEqual(1, torrent.AnnounceUrls.Count, "#3");
            Assert.AreEqual(2, torrent.AnnounceUrls[0].Count, "#4");

            Assert.IsTrue(receivedHaveNone, "#6");

            if (!metadataOnly)
            {
                var peer = PeerId.CreateNull(rig.Manager.Bitfield.Length, true, false, true);
                Assert.DoesNotThrow(() => rig.Manager.PieceManager.AddPieceRequests(peer));
            }
        }
Beispiel #7
0
        internal async Task SendMetadataCore(string expectedPath, PeerMessage sendAfterHandshakeMessage)
        {
            CustomConnection connection = pair.Incoming;

            // 1) Send local handshake. We've already received the remote handshake as part
            // of the Connect method.
            var sendHandshake = new HandshakeMessage(rig.Manager.InfoHash, new string ('g', 20), VersionInfo.ProtocolStringV100, true, true);
            await PeerIO.SendMessageAsync(connection, encryptor, sendHandshake);

            ExtendedHandshakeMessage exHand = new ExtendedHandshakeMessage(false, rig.Torrent.InfoMetadata.Length, 5555);

            exHand.Supports.Add(LTMetadata.Support);
            await PeerIO.SendMessageAsync(connection, encryptor, exHand);

            await PeerIO.SendMessageAsync(connection, encryptor, sendAfterHandshakeMessage);

            bool receivedHaveNone = false;

            // 2) Receive the metadata requests from the other peer and fulfill them
            byte[]      buffer = rig.Torrent.InfoMetadata;
            int         length = (buffer.Length + 16383) / 16384;
            PeerMessage m;

            while (length > 0 && (m = await PeerIO.ReceiveMessageAsync(connection, decryptor)) != null)
            {
                if (m is ExtendedHandshakeMessage ex)
                {
                    Assert.AreEqual(ClientEngine.DefaultMaxPendingRequests, ex.MaxRequests);
                }
                else if (m is HaveNoneMessage)
                {
                    receivedHaveNone = true;
                }
                else if (m is LTMetadata metadata)
                {
                    if (metadata.MetadataMessageType == LTMetadata.eMessageType.Request)
                    {
                        metadata = new LTMetadata(LTMetadata.Support.MessageId, LTMetadata.eMessageType.Data, metadata.Piece, buffer);
                        await PeerIO.SendMessageAsync(connection, encryptor, metadata);

                        length--;
                    }
                }
            }

            // We've sent all the pieces. Now we just wait for the torrentmanager to process them all.
            await rig.Manager.WaitForState(TorrentState.Downloading).WithTimeout();

            Assert.IsTrue(File.Exists(expectedPath), "#1");
            Torrent torrent = Torrent.Load(expectedPath);

            Assert.AreEqual(rig.Manager.InfoHash, torrent.InfoHash, "#2");
            Assert.AreEqual(2, rig.Manager.Torrent.AnnounceUrls.Count, "#3");
            Assert.AreEqual(2, rig.Manager.Torrent.AnnounceUrls[0].Count, "#4");
            Assert.AreEqual(3, rig.Manager.Torrent.AnnounceUrls[1].Count, "#5");
            Assert.IsTrue(receivedHaveNone, "#6");

            var peer = PeerId.CreateNull(rig.Manager.Bitfield.Length, true, false, true);

            Assert.DoesNotThrow(() => rig.Manager.PieceManager.AddPieceRequests(peer));
        }
Beispiel #8
0
        protected virtual void HandleExtendedHandshakeMessage(PeerId id, ExtendedHandshakeMessage message)
        {
            // FIXME: Use the 'version' information
            // FIXME: Recreate the uri? Give warning?
            if (message.LocalPort > 0)
                id.Peer.LocalPort = message.LocalPort;
            id.MaxSupportedPendingRequests = Math.Max(1, message.MaxRequests);
            id.ExtensionSupports = message.Supports;

            if (id.ExtensionSupports.Supports(PeerExchangeMessage.Support.Name))
            {
                if (_manager.HasMetadata && !_manager.Torrent.IsPrivate)
                    id.PeerExchangeManager = new PeerExchangeManager(id);
            }
        }