/// <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); } }
/// <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); } }
/// <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); } }
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; } }
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; } }