Пример #1
0
        private async Task RunHeartbeatAsync(int interval, CancellationToken token)
        {
            #region Valve sucks at naming enum members

            /*
             * Let me tell you a story about 10/14/2017
             * So I was working on this lib ironing out some kinks, rewriting the connection code
             * when I finally completed it and decided to test it. So I pop open a console just to
             * find obvious bugs like the whole thing exploding for no reason. Suddenly at about 5:08 PM
             * it starts working properly. Stuff starts printing in the console and it's working properly.
             * It works correctly until about 20 seconds later when the console window vanishes and up pops an error
             * "IOException: Unable to transfer data" bla bla bla BASICALLY the connection was aborted.
             * This brought up another bug in my TCP client where I wouldn't actually tell anyone the connection disconnected,
             * but who cares about that. This brought in a more important problem: Steam drops my connection even though my heart is beating
             * So I try a WebSocket. Same thing. Check the headers (because there's nothing the in body), everything lines up.
             * I reference the SteamKit, everything related to serialization is in order. Everything is right except one thing.
             * One small piece that nobody would notice.
             * The correct message type for a heartbeat is "ClientHeartBeat", not "Heartbeat"...
             * I found this out after 3 hours. Please kill me.
             *
             *
             * TLDR: Valve sucks at naming enum members.
             */
            #endregion

            // cache the data so we don't serialize 500 times per session. Our session ID will never change and neither will our Steam ID
            var beat = NetworkMessage.CreateProtobufMessage(MessageType.ClientHeartBeat, new CMsgClientHeartBeat()).WithClientInfo(SteamId, SessionId).Serialize();

            try
            {
                await NetLog.DebugAsync($"Heartbeat started on a {interval} ms interval").ConfigureAwait(false);

                while (!token.IsCancellationRequested)
                {
                    await Task.Delay(interval, token).ConfigureAwait(false);

                    try
                    {
                        await SendAsync(beat).ConfigureAwait(false);
                    }
                    catch (Exception ex)
                    {
                        await NetLog.ErrorAsync($"The heartbeat task encountered an unknown exception while sending the heartbeat message", ex).ConfigureAwait(false);
                    }
                }
            }
            catch (OperationCanceledException)
            {
                await NetLog.DebugAsync("Heartbeat stopped").ConfigureAwait(false);
            }
            catch (Exception ex)
            {
                await NetLog.ErrorAsync($"The heartbeat task encountered an unknown exception", ex).ConfigureAwait(false);
            }
        }
Пример #2
0
        private async Task ProcessEncryptRequest(NetworkMessage message)
        {
            ChannelEncryptRequest encryptRequest = message.Deserialize <ChannelEncryptRequest>();
            await NetLog.VerboseAsync($"Encrypting channel on protocol version {encryptRequest.ProtocolVersion} in universe {encryptRequest.Universe}").ConfigureAwait(false);

            byte[] challange = encryptRequest.Challenge.All(b => b == 0) ? encryptRequest.Challenge : null; // check if all the values were made 0 by the marshal
            byte[] publicKey = UniverseUtils.GetPublicKey(encryptRequest.Universe);
            if (publicKey == null)
            {
                await NetLog.ErrorAsync($"Cannot find public key for universe {encryptRequest.Universe}").ConfigureAwait(false);

                throw new InvalidOperationException($"Public key does not exist for universe {encryptRequest.Universe}");
            }

            byte[] tempSessionKey     = CryptoUtils.GenerateBytes(32);
            byte[] encryptedHandshake = null;

            using (RsaCrypto rsa = new RsaCrypto(publicKey))
            {
                if (challange != null)
                {
                    byte[] handshakeToEncrypt = new byte[tempSessionKey.Length + challange.Length];
                    Array.Copy(tempSessionKey, handshakeToEncrypt, tempSessionKey.Length);
                    Array.Copy(challange, 0, handshakeToEncrypt, tempSessionKey.Length, challange.Length);

                    encryptedHandshake = rsa.Encrypt(handshakeToEncrypt);
                }
                else
                {
                    encryptedHandshake = rsa.Encrypt(tempSessionKey);
                }
            }

            Encryption = challange != null ? (IEncryptor) new HmacEncryptor(tempSessionKey) : new SimpleEncryptor(tempSessionKey);

            var encryptResponse = NetworkMessage.CreateMessage(MessageType.ChannelEncryptResponse, new ChannelEncryptResponse
            {
                KeySize            = 128,
                KeyHash            = CryptoUtils.CrcHash(encryptedHandshake),
                EncryptedHandshake = encryptedHandshake,
                ProtocolVersion    = 1,
            });

            await SendAsync(encryptResponse).ConfigureAwait(false);
        }