async Task <bool> HandleHandshake(Peer peer, IConnection connection, HandshakeMessage message, IEncryption decryptor, IEncryption encryptor) { TorrentManager man = null; if (message.ProtocolString != VersionInfo.ProtocolStringV100) { return(false); } // If we're forcing encrypted connections and this is in plain-text, close it! if (encryptor is PlainTextEncryption && !Engine.Settings.AllowedEncryption.HasFlag(EncryptionTypes.PlainText)) { return(false); } for (int i = 0; i < Engine.Torrents.Count; i++) { if (message.InfoHash == Engine.Torrents[i].InfoHash) { man = Engine.Torrents[i]; } } // We're not hosting that torrent if (man == null) { return(false); } if (man.State == TorrentState.Stopped) { return(false); } if (!man.Mode.CanAcceptConnections) { return(false); } peer.PeerId = message.PeerId; var id = new PeerId(peer, connection, man.Bitfield?.Clone().SetAll(false)) { Decryptor = decryptor, Encryptor = encryptor }; message.Handle(man, id); Logger.Log(id.Connection, "ListenManager - Handshake successful handled"); id.ClientApp = new Software(message.PeerId); message = new HandshakeMessage(man.InfoHash, Engine.PeerId, VersionInfo.ProtocolStringV100); await PeerIO.SendMessageAsync(id.Connection, id.Encryptor, message, man.UploadLimiters, id.Monitor, man.Monitor); Engine.ConnectionManager.IncomingConnectionAccepted(man, id); return(true); }
private async Task <bool> HandleHandshake(PeerId id, HandshakeMessage message) { TorrentManager man = null; if (message.ProtocolString != VersionInfo.ProtocolStringV100) { return(false); } // If we're forcing encrypted connections and this is in plain-text, close it! if (id.Encryptor is PlainTextEncryption && !engine.Settings.AllowedEncryption.HasFlag(EncryptionTypes.PlainText)) { return(false); } for (int i = 0; i < engine.Torrents.Count; i++) { if (message.infoHash == engine.Torrents[i].InfoHash) { man = engine.Torrents[i]; } } // We're not hosting that torrent if (man == null) { return(false); } if (man.State == TorrentState.Stopped) { return(false); } if (!man.Mode.CanAcceptConnections) { return(false); } id.Peer.PeerId = message.PeerId; id.TorrentManager = man; message.Handle(id); Logger.Log(id.Connection, "ListenManager - Handshake successful handled"); id.ClientApp = new Software(message.PeerId); message = new HandshakeMessage(id.TorrentManager.InfoHash, engine.PeerId, VersionInfo.ProtocolStringV100); await PeerIO.SendMessageAsync(id.Connection, id.Encryptor, message, id.TorrentManager.UploadLimiter, id.Monitor, id.TorrentManager.Monitor); engine.ConnectionManager.IncomingConnectionAccepted(id); return(true); }
private async void EndCheckEncryption(PeerId id, byte[] initialData) { try { if (initialData != null && initialData.Length > 0) { throw new EncryptionException("unhandled initial data"); } EncryptionTypes e = engine.Settings.AllowedEncryption; if (id.Encryptor is RC4 && !Toolbox.HasEncryption(e, EncryptionTypes.RC4Full) || id.Encryptor is RC4Header && !Toolbox.HasEncryption(e, EncryptionTypes.RC4Header) || id.Encryptor is PlainTextEncryption && !Toolbox.HasEncryption(e, EncryptionTypes.PlainText)) { CleanupSocket(id, id.Encryptor.GetType().Name + " encryption is not enabled"); } else { // Create a handshake message to send to the peer var handshake = new HandshakeMessage(id.TorrentManager.InfoHash, engine.PeerId, VersionInfo.ProtocolStringV100); await PeerIO.SendMessageAsync(id.Connection, id.Encryptor, handshake, id.TorrentManager.UploadLimiter, id.Monitor, id.TorrentManager.Monitor); // Receive their handshake handshake = await PeerIO.ReceiveHandshakeAsync(id.Connection, id.Decryptor); handshake.Handle(id); // If there are any pending messages, send them otherwise set the queue // processing as finished. if (id.QueueLength > 0) { ProcessQueue(id); } else { id.ProcessingQueue = false; } ReceiveMessagesAsync(id.Connection, id.Decryptor, id.TorrentManager.DownloadLimiter, id.Monitor, id.TorrentManager, id); // Alert the engine that there is a new usable connection id.TorrentManager.HandlePeerConnected(id, Direction.Outgoing); } } catch { id.Peer.Encryption &= ~EncryptionTypes.RC4Full; id.Peer.Encryption &= ~EncryptionTypes.RC4Header; CleanupSocket(id, "Failed encryptor check"); } }
internal async void ProcessNewOutgoingConnection(PeerId id) { // If we have too many open connections, close the connection if (OpenConnections > MaxOpenConnections) { CleanupSocket(id); return; } // The peer is no longer in the 'ConnectingToPeers' list, so we should // add it immediately to the 'Connected' list so it is always in one of // the lists. id.ProcessingQueue = true; id.TorrentManager.Peers.ActivePeers.Add(id.Peer); id.TorrentManager.Peers.ConnectedPeers.Add(id); try { // Increase the count of the "open" connections var result = await EncryptorFactory.CheckOutgoingConnectionAsync(id.Connection, id.Peer.AllowedEncryption, engine.Settings, id.TorrentManager.InfoHash); 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); id.TorrentManager.RaiseConnectionAttemptFailed(new ConnectionAttemptFailedEventArgs(id.Peer, ConnectionFailureReason.EncryptionNegiotiationFailed, id.TorrentManager)); CleanupSocket(id); return; } try { // Create a handshake message to send to the peer var handshake = new HandshakeMessage(id.TorrentManager.InfoHash, engine.PeerId, VersionInfo.ProtocolStringV100); await PeerIO.SendMessageAsync(id.Connection, id.Encryptor, handshake, id.TorrentManager.UploadLimiter, id.Monitor, id.TorrentManager.Monitor); // Receive their handshake handshake = await PeerIO.ReceiveHandshakeAsync(id.Connection, id.Decryptor); handshake.Handle(id); } catch { // If we choose plaintext and it resulted in the connection being closed, remove it from the list. id.Peer.AllowedEncryption &= ~id.EncryptionType; id.TorrentManager.RaiseConnectionAttemptFailed(new ConnectionAttemptFailedEventArgs(id.Peer, ConnectionFailureReason.HandshakeFailed, id.TorrentManager)); CleanupSocket(id); return; } try { id.TorrentManager.HandlePeerConnected(id); // If there are any pending messages, send them otherwise set the queue // processing as finished. if (id.QueueLength > 0) { ProcessQueue(id); } else { id.ProcessingQueue = false; } ReceiveMessagesAsync(id.Connection, id.Decryptor, id.TorrentManager.DownloadLimiter, id.Monitor, id.TorrentManager, id); id.WhenConnected.Restart(); id.LastBlockReceived.Restart(); } catch { id.TorrentManager.RaiseConnectionAttemptFailed(new ConnectionAttemptFailedEventArgs(id.Peer, ConnectionFailureReason.Unknown, id.TorrentManager)); CleanupSocket(id); return; } }
private void handleHandshake(PeerId id, HandshakeMessage message) { TorrentManager man = null; try { if (message.ProtocolString != VersionInfo.ProtocolStringV100) { throw new ProtocolException("Invalid protocol string in handshake"); } } catch (Exception ex) { Logger.Log(id.Connection, ex.Message); id.Connection.Dispose(); return; } ClientEngine.MainLoop.QueueWait((MainLoopTask) delegate { for (int i = 0; i < engine.Torrents.Count; i++) { if (message.infoHash == engine.Torrents[i].InfoHash) { man = engine.Torrents[i]; } } }); //FIXME: #warning FIXME: Don't stop the message loop until Dispose() and track all incoming connections if (man == null) // We're not hosting that torrent { Logger.Log(id.Connection, "ListenManager - Handshake requested nonexistant torrent"); id.Connection.Dispose(); return; } if (man.State == TorrentState.Stopped) { Logger.Log(id.Connection, "ListenManager - Handshake requested for torrent which is not running"); id.Connection.Dispose(); return; } if (!man.Mode.CanAcceptConnections) { Logger.Log(id.Connection, "ListenManager - Current mode does not support connections"); id.Connection.Dispose(); return; } id.Peer.PeerId = message.PeerId; id.TorrentManager = man; // If the handshake was parsed properly without encryption, then it definitely was not encrypted. If this is not allowed, abort if ((id.Encryptor is PlainTextEncryption && !Toolbox.HasEncryption(engine.Settings.AllowedEncryption, EncryptionTypes.PlainText)) && ClientEngine.SupportsEncryption) { Logger.Log(id.Connection, "ListenManager - Encryption is required but was not active"); id.Connection.Dispose(); return; } message.Handle(id); Logger.Log(id.Connection, "ListenManager - Handshake successful handled"); id.ClientApp = new Software(message.PeerId); message = new HandshakeMessage(id.TorrentManager.InfoHash, engine.PeerId, VersionInfo.ProtocolStringV100); var callback = engine.ConnectionManager.incomingConnectionAcceptedCallback; PeerIO.EnqueueSendMessage(id.Connection, id.Encryptor, message, id.TorrentManager.UploadLimiter, id.Monitor, id.TorrentManager.Monitor, callback, id); }
private void HandleHandshake(PeerId id, HandshakeMessage message) { TorrentManager man = null; try { if (message.ProtocolString != VersionInfo.ProtocolStringV100) throw new ProtocolException("Invalid protocol string in handshake"); } catch (Exception ex) { Logger.Log(id.Connection, ex.Message); id.Connection.Dispose(); return; } ClientEngine.MainLoop.QueueWait(() => { foreach (var torrentManager in _engine.Torrents.Where(tm => message.InfoHash == tm.InfoHash)) man = torrentManager; }); //FIXME: #warning FIXME: Don't stop the message loop until Dispose() and track all incoming connections if (man == null) // We're not hosting that torrent { Logger.Log(id.Connection, "ListenManager - Handshake requested nonexistant torrent"); id.Connection.Dispose(); return; } if (man.State == TorrentState.Stopped) { Logger.Log(id.Connection, "ListenManager - Handshake requested for torrent which is not running"); id.Connection.Dispose(); return; } if (!man.Mode.CanAcceptConnections) { Logger.Log(id.Connection, "ListenManager - Current mode does not support connections"); id.Connection.Dispose(); return; } id.Peer.PeerId = message.PeerId; id.TorrentManager = man; // If the handshake was parsed properly without encryption, then it definitely was not encrypted. If this is not allowed, abort if ((id.Encryptor is PlainTextEncryption && !Toolbox.HasEncryption(_engine.Settings.AllowedEncryption, EncryptionTypes.PlainText)) && ClientEngine.SupportsEncryption) { Logger.Log(id.Connection, "ListenManager - Encryption is required but was not active"); id.Connection.Dispose(); return; } message.Handle(id); Logger.Log(id.Connection, "ListenManager - Handshake successful handled"); id.ClientApp = new Software(message.PeerId); message = new HandshakeMessage(id.TorrentManager.InfoHash, _engine.PeerId, VersionInfo.ProtocolStringV100); var callback = _engine.ConnectionManager.IncomingConnectionAcceptedCallback; PeerIO.EnqueueSendMessage(id.Connection, id.Encryptor, message, id.TorrentManager.UploadLimiter, id.Monitor, id.TorrentManager.Monitor, callback, id); }
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.ConnectedPeers.Add(id); try { // Create a handshake message to send to the peer var handshake = new HandshakeMessage(manager.InfoHash, LocalPeerId, VersionInfo.ProtocolStringV100); EncryptorFactory.EncryptorResult 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); // 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); 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); // 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); // 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; } }