private void EndCheckEncryption(IAsyncResult result)
        {
            var id = (PeerId) result.AsyncState;
            try
            {
                byte[] initialData;
                EncryptorFactory.EndCheckEncryption(result, out initialData);

                if (initialData != null && initialData.Length == HandshakeMessage.HandshakeLength)
                {
                    var message = new HandshakeMessage();
                    message.Decode(initialData, 0, initialData.Length);
                    HandleHandshake(id, message);
                }
                else if (initialData == null || initialData.Length > 0)
                {
                    throw new Exception("Argh. I can't handle this scenario. It also shouldn't happen. Ever.");
                }
                else
                {
                    PeerIO.EnqueueReceiveHandshake(id.Connection, id.Decryptor, _handshakeReceivedCallback, id);
                }
            }
            catch
            {
                id.Connection.Dispose();
            }
        }
Esempio n. 2
0
        private static void HandshakeReceived(bool successful, int transferred, object state)
        {
            var data = (ReceiveMessageState) state;
            PeerMessage message = null;

            if (successful)
            {
                data.Decryptor.Decrypt(data.Buffer, 0, transferred);
                message = new HandshakeMessage();
                message.Decode(data.Buffer, 0, transferred);
            }

            data.Callback(successful, message, data.State);
            ClientEngine.BufferManager.FreeBuffer(data.Buffer);
            ReceiveCache.Enqueue(data);
        }
        private static void HandshakeReceived(bool succeeded, int count, object state)
        {
            var result = (EncryptorAsyncResult) state;
            var connection = result.Id.Connection;

            try
            {
                if (!succeeded)
                    throw new EncryptionException("Couldn't receive the handshake");

                result.Available += count;
                var message = new HandshakeMessage();
                message.Decode(result.Buffer, 0, result.Buffer.Length);
                var valid = message.ProtocolString == VersionInfo.ProtocolStringV100;
                var usable = CheckRc4(result.Id);

                var canUseRc4 = Toolbox.HasEncryption(usable, EncryptionTypes.RC4Header) ||
                                Toolbox.HasEncryption(usable, EncryptionTypes.RC4Full);
                // If encryption is disabled and we received an invalid handshake - abort!
                if (valid)
                {
                    result.InitialData = result.Buffer;
                    result.Complete();
                    return;
                }
                if (!canUseRc4)
                {
                    result.Complete(new EncryptionException("Invalid handshake received and no decryption works"));
                    return;
                }
                // The data we just received was part of an encrypted handshake and was *not* the BitTorrent handshake
                result.EncSocket = new PeerBEncryption(result.SKeys, EncryptionTypes.All);
                result.EncSocket.BeginHandshake(connection, result.Buffer, 0, result.Buffer.Length,
                    CompletedEncryptedHandshakeCallback, result);
            }
            catch (Exception ex)
            {
                result.Complete(ex);
            }
        }
        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)
            {
                Debug.WriteLine(id.Connection, ex.Message);
                id.Connection.Dispose();
                return;
            }

            man = Engine.Torrents.FirstOrDefault(t => message.InfoHash == t.InfoHash);
            ClientEngine.MainLoop.QueueWait(delegate
            {
                foreach (var t in Engine.Torrents.Where(t => message.InfoHash == t.InfoHash))
                    man = t;
            });

            //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
            {
                //Debug.WriteLine("ListenManager - Handshake requested nonexistant torrent");
                id.Connection.Dispose();
                return;
            }
            if (man.State == TorrentState.Stopped)
            {
                Debug.WriteLine("ListenManager - Handshake requested for torrent which is not running");
                id.Connection.Dispose();
                return;
            }
            if (!man.Mode.CanAcceptConnections)
            {
                Debug.WriteLine("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)
            {
                Debug.WriteLine("ListenManager - Encryption is required but was not active");
                id.Connection.Dispose();
                return;
            }

            message.Handle(id);
            Debug.WriteLine("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);
        }