/// <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); } }
internal void CleanupSocket(TorrentManager manager, PeerId id) { if (id == null || id.Disposed) // Sometimes onEncryptoError will fire with a null id { return; } try { // We can reuse this peer if the connection says so and it's not marked as inactive bool canReuse = (id.Connection?.CanReconnect ?? false) && !manager.InactivePeerManager.InactivePeerList.Contains(id.Uri) && id.Peer.AllowedEncryption != EncryptionTypes.None; manager.PieceManager.Picker.CancelRequests(id); id.Peer.CleanedUpCount++; if (id.PeerExchangeManager != null) { id.PeerExchangeManager.Dispose(); } if (!id.AmChoking) { manager.UploadingTo--; } manager.Peers.ConnectedPeers.Remove(id); manager.Peers.HandshakingPeers.Remove(id); manager.Peers.ActivePeers.Remove(id.Peer); // If we get our own details, this check makes sure we don't try connecting to ourselves again if (canReuse && !LocalPeerId.Equals(id.Peer.PeerId)) { if (!manager.Peers.AvailablePeers.Contains(id.Peer) && id.Peer.CleanedUpCount < 5) { manager.Peers.AvailablePeers.Insert(0, id.Peer); } else if (manager.Peers.BannedPeers.Contains(id.Peer) && id.Peer.CleanedUpCount >= 5) { manager.Peers.BannedPeers.Add(id.Peer); } } } catch (Exception ex) { Logger.Log(null, "CleanupSocket Error " + ex.Message); } finally { manager.RaisePeerDisconnected(new PeerDisconnectedEventArgs(manager, id)); } id.Dispose(); }
internal void CleanupSocket(TorrentManager manager, PeerId id) { if (id == null || id.Disposed) // Sometimes onEncryptoError will fire with a null id { return; } try { // We can reuse this peer if the connection says so and it's not marked as inactive bool canReuse = (id.Connection?.CanReconnect ?? false) && !manager.InactivePeerManager.InactivePeerList.Contains(id.Uri) && id.Peer.AllowedEncryption.Count > 0 && !manager.Engine.PeerId.Equals(id.PeerID); manager.PieceManager.Picker.CancelRequests(id); id.Peer.CleanedUpCount++; id.PeerExchangeManager?.Dispose(); if (!id.AmChoking) { manager.UploadingTo--; } if (manager.Peers.ConnectedPeers.Remove(id)) { Interlocked.Decrement(ref openConnections); } manager.Peers.ActivePeers.Remove(id.Peer); // If we get our own details, this check makes sure we don't try connecting to ourselves again if (canReuse && !LocalPeerId.Equals(id.Peer.PeerId)) { if (!manager.Peers.AvailablePeers.Contains(id.Peer) && id.Peer.CleanedUpCount < 5) { manager.Peers.AvailablePeers.Insert(0, id.Peer); } else if (manager.Peers.BannedPeers.Contains(id.Peer) && id.Peer.CleanedUpCount >= 5) { manager.Peers.BannedPeers.Add(id.Peer); } } } catch (Exception ex) { logger.Exception(ex, "An unexpected error occured cleaning up a connection"); } finally { manager.RaisePeerDisconnected(new PeerDisconnectedEventArgs(manager, id)); } id.Dispose(); }
/// <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); } }