コード例 #1
0
        /// <summary>
        /// This method is called when the ClientEngine recieves a valid incoming connection
        /// </summary>
        /// <param name="manager">The torrent which the peer is associated with.</param>
        /// <param name="id">The peer who just conencted</param>
        internal void IncomingConnectionAccepted(TorrentManager manager, PeerId id)
        {
            try
            {
                bool maxAlreadyOpen = OpenConnections >= Math.Min(MaxOpenConnections, manager.Settings.MaximumConnections);
                if (LocalPeerId.Equals(id.Peer.PeerId) || maxAlreadyOpen)
                {
                    CleanupSocket(manager, id);
                    return;
                }

                if (manager.Peers.ActivePeers.Contains(id.Peer))
                {
                    Logger.Log(id.Connection, "ConnectionManager - Already connected to peer");
                    id.Connection.Dispose();
                    return;
                }

                Logger.Log(id.Connection, "ConnectionManager - Incoming connection fully accepted");
                manager.Peers.AvailablePeers.Remove(id.Peer);
                manager.Peers.ActivePeers.Add(id.Peer);
                id.WhenConnected.Restart();
                // Baseline the time the last block was received
                id.LastBlockReceived.Restart();

                manager.HandlePeerConnected(id);

                // We've sent our handshake so begin our looping to receive incoming message
                ReceiveMessagesAsync(id.Connection, id.Decryptor, manager.DownloadLimiters, id.Monitor, manager, id);
            }
            catch
            {
                CleanupSocket(manager, id);
            }
        }
コード例 #2
0
        /// <summary>
        /// This method is called when the ClientEngine recieves a valid incoming connection
        /// </summary>
        /// <param name="manager">The torrent which the peer is associated with.</param>
        /// <param name="id">The peer who just conencted</param>
        internal async ReusableTask <bool> IncomingConnectionAcceptedAsync(TorrentManager manager, PeerId id)
        {
            try {
                bool maxAlreadyOpen = OpenConnections >= Settings.MaximumConnections ||
                                      manager.OpenConnections >= manager.Settings.MaximumConnections;

                if (LocalPeerId.Equals(id.Peer.PeerId))
                {
                    logger.Info("Connected to self - disconnecting");
                    CleanupSocket(manager, id);
                    return(false);
                }
                if (manager.Peers.ActivePeers.Contains(id.Peer))
                {
                    logger.Info(id.Connection, "Already connected to peer");
                    id.Connection.Dispose();
                    return(false);
                }
                if (maxAlreadyOpen)
                {
                    logger.Info("Connected to too many peers - disconnecting");
                    CleanupSocket(manager, id);
                    return(false);
                }

                // Add the PeerId to the lists *before* doing anything asynchronous. This ensures that
                // all PeerIds are tracked in 'ConnectedPeers' as soon as they're created.
                logger.Info(id.Connection, "Incoming connection fully accepted");
                manager.Peers.AvailablePeers.Remove(id.Peer);
                manager.Peers.ActivePeers.Add(id.Peer);
                manager.Peers.ConnectedPeers.Add(id);
                Interlocked.Increment(ref openConnections);

                id.WhenConnected.Restart();
                // Baseline the time the last block was received
                id.LastBlockReceived.Restart();

                // Send our handshake now that we've decided to keep the connection
                var handshake = new HandshakeMessage(manager.InfoHashes.V1OrV2, manager.Engine !.PeerId, Constants.ProtocolStringV100);
                await PeerIO.SendMessageAsync(id.Connection, id.Encryptor, handshake, manager.UploadLimiters, id.Monitor, manager.Monitor);

                manager.HandlePeerConnected(id);
                id.MessageQueue.SetReady();
                TryProcessQueue(manager, id);

                // We've sent our handshake so begin our looping to receive incoming message
                ReceiveMessagesAsync(id.Connection, id.Decryptor, manager.DownloadLimiters, id.Monitor, manager, id);
                logger.InfoFormatted("Incoming connection fully accepted", id.Uri);
                return(true);
            } catch (Exception ex) {
                logger.Exception(ex, "Error handling incoming connection");
                CleanupSocket(manager, id);
                return(false);
            }
        }
コード例 #3
0
        /// <summary>
        /// This method is called when the ClientEngine recieves a valid incoming connection
        /// </summary>
        /// <param name="manager">The torrent which the peer is associated with.</param>
        /// <param name="id">The peer who just conencted</param>
        internal async ReusableTask <bool> IncomingConnectionAcceptedAsync(TorrentManager manager, PeerId id)
        {
            try {
                bool maxAlreadyOpen = OpenConnections >= Math.Min(MaxOpenConnections, manager.Settings.MaximumConnections);
                if (LocalPeerId.Equals(id.Peer.PeerId) || maxAlreadyOpen)
                {
                    CleanupSocket(manager, id);
                    return(false);
                }

                if (manager.Peers.ActivePeers.Contains(id.Peer))
                {
                    Logger.Log(id.Connection, "ConnectionManager - Already connected to peer");
                    id.Connection.Dispose();
                    return(false);
                }

                // Add the PeerId to the lists *before* doing anything asynchronous. This ensures that
                // all PeerIds are tracked in 'ConnectedPeers' as soon as they're created.
                Logger.Log(id.Connection, "ConnectionManager - Incoming connection fully accepted");
                manager.Peers.AvailablePeers.Remove(id.Peer);
                manager.Peers.ActivePeers.Add(id.Peer);
                manager.Peers.ConnectedPeers.Add(id);

                id.WhenConnected.Restart();
                // Baseline the time the last block was received
                id.LastBlockReceived.Restart();

                // Send our handshake now that we've decided to keep the connection
                var handshake = new HandshakeMessage(manager.InfoHash, manager.Engine.PeerId, VersionInfo.ProtocolStringV100);
                await PeerIO.SendMessageAsync(id.Connection, id.Encryptor, handshake, manager.UploadLimiters, id.Monitor, manager.Monitor);

                manager.HandlePeerConnected(id);

                // We've sent our handshake so begin our looping to receive incoming message
                ReceiveMessagesAsync(id.Connection, id.Decryptor, manager.DownloadLimiters, id.Monitor, manager, id);
                return(true);
            } catch {
                CleanupSocket(manager, id);
                return(false);
            }
        }
コード例 #4
0
        internal async void ProcessNewOutgoingConnection(TorrentManager manager, PeerId id)
        {
            // If we have too many open connections, close the connection
            if (OpenConnections > MaxOpenConnections)
            {
                CleanupSocket(manager, id);
                return;
            }

            id.ProcessingQueue = true;
            manager.Peers.ActivePeers.Add(id.Peer);
            manager.Peers.HandshakingPeers.Add(id);

            try {
                // Create a handshake message to send to the peer
                var handshake = new HandshakeMessage(manager.InfoHash, LocalPeerId, VersionInfo.ProtocolStringV100);
                var result    = await EncryptorFactory.CheckOutgoingConnectionAsync(id.Connection, id.Peer.AllowedEncryption, Settings, manager.InfoHash, handshake);

                id.Decryptor = result.Decryptor;
                id.Encryptor = result.Encryptor;
            } catch {
                // If an exception is thrown it's because we tried to establish an encrypted connection and something went wrong
                id.Peer.AllowedEncryption &= ~(EncryptionTypes.RC4Full | EncryptionTypes.RC4Header);

                manager.RaiseConnectionAttemptFailed(new ConnectionAttemptFailedEventArgs(id.Peer, ConnectionFailureReason.EncryptionNegiotiationFailed, manager));
                CleanupSocket(manager, id);
                return;
            }

            try {
                // Receive their handshake
                var handshake = await PeerIO.ReceiveHandshakeAsync(id.Connection, id.Decryptor);

                handshake.Handle(manager, id);
            } catch {
                // If we choose plaintext and it resulted in the connection being closed, remove it from the list.
                id.Peer.AllowedEncryption &= ~id.EncryptionType;

                manager.RaiseConnectionAttemptFailed(new ConnectionAttemptFailedEventArgs(id.Peer, ConnectionFailureReason.HandshakeFailed, manager));
                CleanupSocket(manager, id);
                return;
            }

            try {
                manager.Peers.HandshakingPeers.Remove(id);
                manager.HandlePeerConnected(id);

                // If there are any pending messages, send them otherwise set the queue
                // processing as finished.
                if (id.QueueLength > 0)
                {
                    ProcessQueue(manager, id);
                }
                else
                {
                    id.ProcessingQueue = false;
                }

                ReceiveMessagesAsync(id.Connection, id.Decryptor, manager.DownloadLimiters, id.Monitor, manager, id);

                id.WhenConnected.Restart();
                id.LastBlockReceived.Restart();
            } catch {
                manager.RaiseConnectionAttemptFailed(new ConnectionAttemptFailedEventArgs(id.Peer, ConnectionFailureReason.Unknown, manager));
                CleanupSocket(manager, id);
                return;
            }
        }
コード例 #5
0
        internal async void ProcessNewOutgoingConnection(TorrentManager manager, PeerId id)
        {
            // If we have too many open connections, close the connection
            if (OpenConnections > MaxOpenConnections)
            {
                CleanupSocket(manager, id);
                return;
            }

            manager.Peers.ActivePeers.Add(id.Peer);
            manager.Peers.ConnectedPeers.Add(id);
            Interlocked.Increment(ref openConnections);

            try {
                // Create a handshake message to send to the peer
                var handshake           = new HandshakeMessage(manager.InfoHash, LocalPeerId, VersionInfo.ProtocolStringV100);
                var preferredEncryption = EncryptionTypes.GetPreferredEncryption(id.Peer.AllowedEncryption, Settings.AllowedEncryption);
                EncryptorFactory.EncryptorResult result = await EncryptorFactory.CheckOutgoingConnectionAsync(id.Connection, preferredEncryption, manager.InfoHash, handshake);

                id.Decryptor = result.Decryptor;
                id.Encryptor = result.Encryptor;
            } catch {
                // If an exception is thrown it's because we tried to establish an encrypted connection and something went wrong
                if (id.Peer.AllowedEncryption.Contains(EncryptionType.PlainText))
                {
                    id.Peer.AllowedEncryption = EncryptionTypes.PlainText;
                }
                else
                {
                    id.Peer.AllowedEncryption = EncryptionTypes.None;
                }

                manager.RaiseConnectionAttemptFailed(new ConnectionAttemptFailedEventArgs(id.Peer, ConnectionFailureReason.EncryptionNegiotiationFailed, manager));
                CleanupSocket(manager, id);

                // CleanupSocket will contain the peer only if AllowedEncryption is not set to None. If
                // the peer was re-added, then we should try to reconnect to it immediately to try an
                // unencrypted connection.
                if (manager.Peers.AvailablePeers.Remove(id.Peer))
                {
                    ConnectToPeer(manager, id.Peer);
                }
                return;
            }

            try {
                // Receive their handshake
                HandshakeMessage handshake = await PeerIO.ReceiveHandshakeAsync(id.Connection, id.Decryptor);

                manager.Mode.HandleMessage(id, handshake);
            } catch {
                // If we choose plaintext and it resulted in the connection being closed, remove it from the list.
                id.Peer.AllowedEncryption = EncryptionTypes.Remove(id.Peer.AllowedEncryption, id.EncryptionType);

                manager.RaiseConnectionAttemptFailed(new ConnectionAttemptFailedEventArgs(id.Peer, ConnectionFailureReason.HandshakeFailed, manager));
                CleanupSocket(manager, id);

                // CleanupSocket will contain the peer only if AllowedEncryption is not set to None. If
                // the peer was re-added, then we should try to reconnect to it immediately to try an
                // encrypted connection, assuming the previous connection was unencrypted and it failed.
                if (manager.Peers.AvailablePeers.Remove(id.Peer))
                {
                    ConnectToPeer(manager, id.Peer);
                }

                return;
            }

            try {
                if (id.BitField.Length != manager.Bitfield.Length)
                {
                    throw new TorrentException($"The peer's bitfield was of length {id.BitField.Length} but the TorrentManager's bitfield was of length {manager.Bitfield.Length}.");
                }

                manager.HandlePeerConnected(id);
                id.MessageQueue.SetReady();
                TryProcessQueue(manager, id);

                ReceiveMessagesAsync(id.Connection, id.Decryptor, manager.DownloadLimiters, id.Monitor, manager, id);

                id.WhenConnected.Restart();
                id.LastBlockReceived.Restart();
            } catch {
                manager.RaiseConnectionAttemptFailed(new ConnectionAttemptFailedEventArgs(id.Peer, ConnectionFailureReason.Unknown, manager));
                CleanupSocket(manager, id);
                return;
            }
        }