internal async void ConnectToPeer(TorrentManager manager, Peer peer) { // Connect to the peer. IConnection connection = ConnectionFactory.Create(peer.ConnectionUri); if (connection == null) { return; } var state = new AsyncConnectState(manager, connection, ValueStopwatch.StartNew()); PendingConnects.Add(state); manager.Peers.ConnectingToPeers.Add(peer); bool succeeded; try { await NetworkIO.ConnectAsync(connection); succeeded = true; } catch { succeeded = false; } PendingConnects.Remove(state); manager.Peers.ConnectingToPeers.Remove(peer); if (manager.Engine == null || !manager.Mode.CanAcceptConnections) { manager.Peers.AvailablePeers.Add(peer); connection.Dispose(); return; } try { if (!succeeded) { peer.FailedConnectionAttempts++; connection.Dispose(); manager.Peers.BusyPeers.Add(peer); manager.RaiseConnectionAttemptFailed(new ConnectionAttemptFailedEventArgs(peer, ConnectionFailureReason.Unreachable, manager)); } else { PeerId id = new PeerId(peer, connection, manager.Bitfield?.Clone().SetAll(false)); id.LastMessageReceived.Restart(); id.LastMessageSent.Restart(); Logger.Log(id.Connection, "ConnectionManager - Connection opened"); ProcessNewOutgoingConnection(manager, id); } } catch { // FIXME: Do nothing now? } finally { // Try to connect to another peer TryConnect(); } }
async void ConnectToPeer(TorrentManager manager, Peer peer) { // Connect to the peer. var connection = Factories.CreatePeerConnection(peer.ConnectionUri); if (connection == null || peer.AllowedEncryption.Count == 0) { return; } var state = new AsyncConnectState(manager, connection, ValueStopwatch.StartNew()); PendingConnects.Add(state); manager.Peers.ConnectingToPeers.Add(peer); bool succeeded; try { await NetworkIO.ConnectAsync(connection); succeeded = true; } catch { succeeded = false; } PendingConnects.Remove(state); manager.Peers.ConnectingToPeers.Remove(peer); if (manager.Disposed || !manager.Mode.CanAcceptConnections) { manager.Peers.AvailablePeers.Add(peer); connection.Dispose(); return; } try { if (!succeeded) { peer.FailedConnectionAttempts++; connection.Dispose(); manager.RaiseConnectionAttemptFailed(new ConnectionAttemptFailedEventArgs(peer, ConnectionFailureReason.Unreachable, manager)); } else { var id = new PeerId(peer, connection, new MutableBitField(manager.Bitfield.Length).SetAll(false)); id.LastMessageReceived.Restart(); id.LastMessageSent.Restart(); logger.Info(id.Connection, "Connection opened"); ProcessNewOutgoingConnection(manager, id); } } catch { // FIXME: Do nothing now? } finally { // Try to connect to another peer TryConnect(); } }
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; } }
internal async void ConnectToPeer(TorrentManager manager, Peer peer) { // Connect to the peer. IConnection connection = ConnectionFactory.Create(peer.ConnectionUri); if (connection == null) { return; } var state = new AsyncConnectState(manager, connection, Stopwatch.StartNew()); PendingConnects.Add(state); manager.Peers.ConnectingToPeers.Add(peer); bool succeeded; try { await NetworkIO.ConnectAsync(connection); succeeded = true; } catch { succeeded = false; } PendingConnects.Remove(state); if (manager.Engine == null || !manager.Mode.CanAcceptConnections) { connection.Dispose(); return; } try { manager.Peers.ConnectingToPeers.Remove(peer); if (!succeeded) { Logger.Log(null, "ConnectionManager - Failed to connect{0}", peer); manager.RaiseConnectionAttemptFailed( new PeerConnectionFailedEventArgs(manager, peer, Direction.Outgoing, "EndCreateConnection")); peer.FailedConnectionAttempts++; connection.Dispose(); manager.Peers.BusyPeers.Add(peer); } else { PeerId id = new PeerId(peer, manager); id.Connection = connection; manager.Peers.ActivePeers.Add(peer); Logger.Log(id.Connection, "ConnectionManager - Connection opened"); ProcessFreshConnection(id); } } catch (Exception) { // FIXME: Do nothing now? } finally { // Try to connect to another peer TryConnect(); } }