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);
        }
Exemple #2
0
        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");
            }
        }
Exemple #4
0
        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);
        }
Exemple #7
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.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;
            }
        }