예제 #1
0
        public async Task Send(MTProtoRequest request)
        {
            // TODO: refactor
            if (needConfirmation.Any())
            {
                var ackRequest = new TL.MsgsAckRequest(needConfirmation);
                using (var memory = new MemoryStream())
                    using (var writer = new TBinaryWriter(memory))
                    {
                        ackRequest.OnSend(writer);
                        await Send(memory.ToArray(), ackRequest);

                        needConfirmation.Clear();
                    }
            }


            using (var memory = new MemoryStream())
                using (var writer = new TBinaryWriter(memory))
                {
                    request.OnSend(writer);
                    await Send(memory.ToArray(), request);
                }

            _session.Save();
        }
예제 #2
0
        public async Task Send(byte[] packet, MTProtoRequest request)
        {
            request.MessageId = _session.GetNewMessageId();

            byte[] msgKey;
            byte[] ciphertext;
            using (MemoryStream plaintextPacket = makeMemory(8 + 8 + 8 + 4 + 4 + packet.Length))
            {
                using (BinaryWriter plaintextWriter = new BinaryWriter(plaintextPacket))
                {
                    plaintextWriter.Write(_session.Salt);
                    plaintextWriter.Write(_session.Id);
                    plaintextWriter.Write(request.MessageId);
                    plaintextWriter.Write(GenerateSequence(request.Confirmed));
                    plaintextWriter.Write(packet.Length);
                    plaintextWriter.Write(packet);

                    msgKey     = Helpers.CalcMsgKey(plaintextPacket.GetBuffer());
                    ciphertext = AES.EncryptAES(Helpers.CalcKey(_session.AuthKey.Data, msgKey, true), plaintextPacket.GetBuffer());
                }
            }

            using (MemoryStream ciphertextPacket = makeMemory(8 + 16 + ciphertext.Length))
            {
                using (BinaryWriter writer = new BinaryWriter(ciphertextPacket))
                {
                    writer.Write(_session.AuthKey.Id);
                    writer.Write(msgKey);
                    writer.Write(ciphertext);

                    await _transport.Send(ciphertextPacket.GetBuffer());
                }
            }
        }
예제 #3
0
        static void ProcessGzip(BinaryReader messageReader, MTProtoRequest request)
        {
            var packedData = Serializers.Bytes.read(messageReader);

            using (var packedStream = new MemoryStream(packedData, false))
            {
                var zipStream = new GZipStream(packedStream, CompressionMode.Decompress);

                var compressedReader = new BinaryReader(zipStream);

                request.OnResponse(compressedReader);


                // Read to end TODO : measure time taken with exception and without.
                const int bufferSize = 4096;
                using (var ms = new MemoryStream())
                {
                    var buffer = new byte[bufferSize];
                    int count;
                    while ((count = compressedReader.Read(buffer, 0, buffer.Length)) != 0)
                    {
                        ms.Write(buffer, 0, count);
                    }
                }
                // read to end

                //Disposing the binaryreader dispose also: zipStream.Dispose() (Calls Close()); so we get the error before.
                //Exception thrown: 'Ionic.Zlib.ZlibException' in Ionic.ZLib.dll
                //Additional information: Bad CRC32 in GZIP trailer. (actual(8125C157) != expected(6B1145BF))
                compressedReader.Dispose();

                zipStream.Dispose();
            }
        }
        static ITlResponse HandleRpcResult(BinaryReader messageReader, MTProtoRequest request)
        {
            var combinator = new Combinator(messageReader.ReadUInt32());

            var requestId = messageReader.ReadUInt64();

            if (requestId == (ulong)request.MessageId)
            {
                request.ConfirmReceived = true;
            }

            var innerCode = messageReader.ReadUInt32();

            if (innerCode != 0x3072cfa1)
            {
                return(null);
            }

            ITlResponse response = null;

            var packedData = Serializers.Bytes.read(messageReader);

            var packedStream = new MemoryStream(packedData, false);

            var zipStream = new GZipStream(packedStream, CompressionMode.Decompress);

            var compressedReader = new BinaryReader(zipStream);

            var responseHandlerFactory = new ResponseHandlerFactory();

            var handler = responseHandlerFactory.GetHandler <ContactsContacts>();

            if (handler != null)
            {
                response = handler.Populate(compressedReader);
            }

            const int bufferSize = 4096;

            using (var memoryStream = new MemoryStream())
            {
                var buffer = new byte[bufferSize];

                int count;

                while ((count = compressedReader.Read(buffer, 0, buffer.Length)) != 0)
                {
                    memoryStream.Write(buffer, 0, count);
                }
            }

            compressedReader.Dispose();

            zipStream.Dispose();

            packedStream.Dispose();

            return(response);
        }
예제 #5
0
        public async Task <byte[]> Receive(MTProtoRequest request)
        {
            while (!request.ConfirmReceived)
            {
                var result = DecodeMessage((await _transport.Receieve()).Body);

                using (MemoryStream messageStream = new MemoryStream(result.Item1, false))
                    using (TBinaryReader messageReader = new TBinaryReader(messageStream))
                    {
                        processMessage(result.Item2, result.Item3, messageReader, request);
                    }
            }

            return(null);
        }
        ITlResponse ProcessMessage(ulong messageId, BinaryReader messageReader, MTProtoRequest request)
        {
            ITlResponse response = null;

            needConfirmation.Add(messageId);

            var code = messageReader.ReadUInt32();

            messageReader.BaseStream.Position -= 4;

            if (code == 0xf35c6d01)
            {
                response = HandleRpcResult(messageReader, request);
            }

            return(response);
        }
        public async Task <T> Receive <T>(MTProtoRequest request) where T : class, ITlResponse
        {
            T response = null;

            while (!request.ConfirmReceived)
            {
                var tcpMessage = await _transport.Receieve();

                var result = DecodeMessage(tcpMessage.Body);

                using (var messageStream = new MemoryStream(result.Item1, false))
                    using (var messageReader = new BinaryReader(messageStream))
                        response = ProcessMessage(result.Item2, messageReader, request) as T;
            }

            return(response);
        }
예제 #8
0
        private bool HandleContainer(long messageId, int sequence, TBinaryReader messageReader, MTProtoRequest request)
        {
            uint code = messageReader.ReadUInt32();
            int  size = messageReader.ReadInt32();

            for (int i = 0; i < size; i++)
            {
                long innerMessageId = messageReader.ReadInt64();
                int  innerSequence  = messageReader.ReadInt32();
                int  innerLength    = messageReader.ReadInt32();
                long beginPosition  = messageReader.BaseStream.Position;
                try
                {
                    if (!processMessage(innerMessageId, sequence, messageReader, request))
                    {
                        messageReader.BaseStream.Position = beginPosition + innerLength;
                    }
                }
                catch (Exception e)
                {
                    //	logger.error("failed to process message in contailer: {0}", e);
                    messageReader.BaseStream.Position = beginPosition + innerLength;
                }
            }

            return(false);
        }
예제 #9
0
        private bool HandleBadServerSalt(long messageId, int sequence, BinaryReader messageReader, MTProtoRequest request)
        {
            uint  code        = messageReader.ReadUInt32();
            ulong badMsgId    = messageReader.ReadUInt64();
            int   badMsgSeqNo = messageReader.ReadInt32();
            int   errorCode   = messageReader.ReadInt32();
            ulong newSalt     = messageReader.ReadUInt64();

            //logger.debug("bad_server_salt: msgid {0}, seq {1}, errorcode {2}, newsalt {3}", badMsgId, badMsgSeqNo, errorCode, newSalt);

            _session.Salt = newSalt;

            //resend
            Send(request);

            /*
             * if(!runningRequests.ContainsKey(badMsgId)) {
             *  logger.debug("bad server salt on unknown message");
             *  return true;
             * }
             */


            //MTProtoRequest request = runningRequests[badMsgId];
            //request.OnException(new MTProtoBadServerSaltException(salt));

            return(true);
        }
예제 #10
0
        private bool HandleRpcResult(long messageId, int sequence, TBinaryReader messageReader, MTProtoRequest request)
        {
            uint  code      = messageReader.ReadUInt32();
            ulong requestId = messageReader.ReadUInt64();

            if (requestId == (ulong)request.MessageId)
            {
                request.ConfirmReceived = true;
            }

            //throw new NotImplementedException();

            /*
             *          lock (runningRequests)
             *          {
             *                  if (!runningRequests.ContainsKey(requestId))
             *                  {
             *                          logger.warning("rpc response on unknown request: {0}", requestId);
             *                          messageReader.BaseStream.Position -= 12;
             *                          return false;
             *                  }
             *                  request = runningRequests[requestId];
             *                  runningRequests.Remove(requestId);
             *          }
             */

            uint innerCode = messageReader.ReadUInt32();

            if (innerCode == 0x2144ca19)
            { // rpc_error
                int    errorCode    = messageReader.ReadInt32();
                string errorMessage = messageReader.ReadString();

                if (errorMessage.StartsWith("FLOOD_WAIT_"))
                {
                    var resultString = Regex.Match(errorMessage, @"\d+").Value;
                    var seconds      = int.Parse(resultString);
                    Debug.WriteLine($"Should wait {seconds} sec.");
                    Thread.Sleep(1000 * seconds);
                }
                else if (errorMessage.StartsWith("PHONE_MIGRATE_"))
                {
                    var resultString = Regex.Match(errorMessage, @"\d+").Value;
                    var dcIdx        = int.Parse(resultString);
                    throw new InvalidOperationException($"Your phone number registered to {dcIdx} dc. Please update settings. See https://github.com/sochix/TeleTurk#i-get-an-error-migrate_x for details.");
                }
                else
                {
                    throw new InvalidOperationException(errorMessage);
                }
            }
            else if (innerCode == 0x3072cfa1)
            {
                // gzip_packed
                byte[] packedData = messageReader.ReadBytes();
                using (MemoryStream packedStream = new MemoryStream(packedData, false))
                    using (System.IO.Compression.GZipStream zipStream = new System.IO.Compression.GZipStream(packedStream, System.IO.Compression.CompressionMode.Decompress))
                        using (TBinaryReader compressedReader = new TBinaryReader(zipStream))
                        {
                            request.OnResponse(compressedReader);
                        }
            }
            else
            {
                messageReader.BaseStream.Position -= 4;

                request.OnResponse(messageReader);
            }

            return(false);
        }
예제 #11
0
        private bool HandleGzipPacked(long messageId, int sequence, TBinaryReader messageReader, MTProtoRequest request)
        {
            uint code = messageReader.ReadUInt32();

            byte[] packedData = GZipStream.UncompressBuffer(messageReader.ReadBytes());
            using (MemoryStream packedStream = new MemoryStream(packedData, false))
                using (TBinaryReader compressedReader = new TBinaryReader(packedStream))
                {
                    processMessage(messageId, sequence, compressedReader, request);
                }

            return(true);
        }
예제 #12
0
        private bool processMessage(long messageId, int sequence, TBinaryReader messageReader, MTProtoRequest request)
        {
            // TODO: check salt
            // TODO: check sessionid
            // TODO: check seqno

            //logger.debug("processMessage: msg_id {0}, sequence {1}, data {2}", BitConverter.ToString(((MemoryStream)messageReader.BaseStream).GetBuffer(), (int) messageReader.BaseStream.Position, (int) (messageReader.BaseStream.Length - messageReader.BaseStream.Position)).Replace("-","").ToLower());
            needConfirmation.Add(messageId);

            uint code = messageReader.ReadUInt32();

            messageReader.BaseStream.Position -= 4;
            switch (code)
            {
            case 0x73f1f8dc:     // container
                                 //logger.debug("MSG container");
                return(HandleContainer(messageId, sequence, messageReader, request));

            case 0x7abe77ec:     // ping
                                 //logger.debug("MSG ping");
                return(HandlePing(messageId, sequence, messageReader));

            case 0x347773c5:     // pong
                                 //logger.debug("MSG pong");
                return(HandlePong(messageId, sequence, messageReader));

            case 0xae500895:     // future_salts
                                 //logger.debug("MSG future_salts");
                return(HandleFutureSalts(messageId, sequence, messageReader));

            case 0x9ec20908:     // new_session_created
                                 //logger.debug("MSG new_session_created");
                return(HandleNewSessionCreated(messageId, sequence, messageReader));

            case 0x62d6b459:     // msgs_ack
                                 //logger.debug("MSG msds_ack");
                return(HandleMsgsAck(messageId, sequence, messageReader));

            case 0xedab447b:     // bad_server_salt
                                 //logger.debug("MSG bad_server_salt");
                return(HandleBadServerSalt(messageId, sequence, messageReader, request));

            case 0xa7eff811:     // bad_msg_notification
                                 //logger.debug("MSG bad_msg_notification");
                return(HandleBadMsgNotification(messageId, sequence, messageReader));

            case 0x276d3ec6:     // msg_detailed_info
                                 //logger.debug("MSG msg_detailed_info");
                return(HandleMsgDetailedInfo(messageId, sequence, messageReader));

            case 0xf35c6d01:     // rpc_result
                                 //logger.debug("MSG rpc_result");
                return(HandleRpcResult(messageId, sequence, messageReader, request));

            case 0x3072cfa1:     // gzip_packed
                                 //logger.debug("MSG gzip_packed");
                return(HandleGzipPacked(messageId, sequence, messageReader, request));

            case 0xe317af7e:
            case 0xd3f45784:
            case 0x2b2fbd4e:
            case 0x78d4dec1:
            case 0x725b04c3:
            case 0x74ae4240:
                return(HandleUpdate(messageId, sequence, messageReader));

            default:
                //logger.debug("unknown message: {0}", code);
                return(false);
            }
        }
예제 #13
0
        private bool HandleRpcResult(ulong messageId, int sequence, BinaryReader messageReader, MTProtoRequest request)
        {
            uint  code      = messageReader.ReadUInt32();
            ulong requestId = messageReader.ReadUInt64();

            if (requestId == (ulong)request.MessageId)
            {
                request.ConfirmReceived = true;
            }

            //throw new NotImplementedException();

            /*
             *          lock (runningRequests)
             *          {
             *                  if (!runningRequests.ContainsKey(requestId))
             *                  {
             *                          logger.warning("rpc response on unknown request: {0}", requestId);
             *                          messageReader.BaseStream.Position -= 12;
             *                          return false;
             *                  }
             *
             *                  request = runningRequests[requestId];
             *                  runningRequests.Remove(requestId);
             *          }
             */

            uint innerCode = messageReader.ReadUInt32();

            if (innerCode == 0x2144ca19)
            { // rpc_error
                int    errorCode    = messageReader.ReadInt32();
                string errorMessage = Serializers.String.read(messageReader);

                if (errorMessage.StartsWith("FLOOD_WAIT_"))
                {
                    var resultString = Regex.Match(errorMessage, @"\d+").Value;
                    var seconds      = int.Parse(resultString);
                    Debug.WriteLine($"Should wait {seconds} sec.");
                    Thread.Sleep(1000 * seconds);
                }
                else if (errorMessage.StartsWith("PHONE_MIGRATE_"))
                {
                    var resultString = Regex.Match(errorMessage, @"\d+").Value;
                    var dcIdx        = int.Parse(resultString);
                    var exception    = new InvalidOperationException($"Your phone number registered to {dcIdx} dc. Please update settings. See https://github.com/sochix/TLSharp#i-get-an-error-migrate_x for details.");
                    exception.Data.Add("dcId", dcIdx);
                    throw exception;
                }
                else
                {
                    throw new InvalidOperationException(errorMessage);
                }
            }
            else if (innerCode == 0x3072cfa1)
            {
                try
                {
                    // gzip_packed
                    var packedData = Serializers.Bytes.read(messageReader);
                    using (var packedStream = new MemoryStream(packedData, false))
                    {
                        var zipStream = new GZipStream(packedStream, CompressionMode.Decompress);

                        var compressedReader = new BinaryReader(zipStream);

                        request.OnResponse(compressedReader);


                        // Read to end TODO : measure time taken with exception and without.
                        const int bufferSize = 4096;
                        using (var ms = new MemoryStream())
                        {
                            var buffer = new byte[bufferSize];
                            int count;
                            while ((count = compressedReader.Read(buffer, 0, buffer.Length)) != 0)
                            {
                                ms.Write(buffer, 0, count);
                            }
                        }
                        // read to end

                        //Disposing the binaryreader dispose also: zipStream.Dispose() (Calls Close()); so we get the error before.
                        //Exception thrown: 'Ionic.Zlib.ZlibException' in Ionic.ZLib.dll
                        //Additional information: Bad CRC32 in GZIP trailer. (actual(8125C157) != expected(6B1145BF))
                        compressedReader.Dispose();

                        zipStream.Dispose();
                    }
                }
                catch (ZlibException ex)
                {
                }
            }
            else
            {
                messageReader.BaseStream.Position -= 4;

                request.OnResponse(messageReader);
            }

            return(false);
        }
예제 #14
0
        private bool HandleRpcResult(ulong messageId, int sequence, BinaryReader messageReader, MTProtoRequest request)
        {
            var code      = new Combinator(messageReader.ReadUInt32());
            var requestId = messageReader.ReadUInt64();

            if (requestId == (ulong)request.MessageId)
            {
                request.ConfirmReceived = true;
            }

            //throw new NotImplementedException();

            /*
             *          lock (runningRequests)
             *          {
             *                  if (!runningRequests.ContainsKey(requestId))
             *                  {
             *                          logger.warning("rpc response on unknown request: {0}", requestId);
             *                          messageReader.BaseStream.Position -= 12;
             *                          return false;
             *                  }
             *
             *                  request = runningRequests[requestId];
             *                  runningRequests.Remove(requestId);
             *          }
             */

            var combinator = new Combinator(messageReader.ReadUInt32());


            if (combinator.Name == 0x2144ca19)
            {
                // rpc_error
                ParseError(messageReader);
            }
            else if (combinator.Name == Gzip)
            {
                // gzip_packed
                ProcessGzip(messageReader, request);
            }
            else
            {
                messageReader.BaseStream.Position -= 4;

                request.OnResponse(messageReader);
            }

            return(false);
        }
        bool HandleRpcResult(ulong messageId, int sequence, BinaryReader messageReader, MTProtoRequest request)
        {
            uint  code      = messageReader.ReadUInt32();
            ulong requestId = messageReader.ReadUInt64();

            if (requestId == (ulong)request.MessageId)
            {
                request.ConfirmReceived = true;
            }

            //throw new NotImplementedException();

            /*
             * lock (runningRequests)
             * {
             *      if (!runningRequests.ContainsKey(requestId))
             *      {
             *              logger.warning("rpc response on unknown request: {0}", requestId);
             *              messageReader.BaseStream.Position -= 12;
             *              return false;
             *      }
             *
             *      request = runningRequests[requestId];
             *      runningRequests.Remove(requestId);
             * }
             */

            uint innerCode = messageReader.ReadUInt32();

            if (innerCode == 0x2144ca19)
            {             // rpc_error
                int    errorCode    = messageReader.ReadInt32();
                string errorMessage = Serializers.String.Read(messageReader);

                if (errorMessage.StartsWith("FLOOD_WAIT_"))
                {
                    var resultString = Regex.Match(errorMessage, @"\d+").Value;
                    var seconds      = int.Parse(resultString);
                    Debug.WriteLine($"Should wait {seconds} sec.");
                    Thread.Sleep(1000 * seconds);
                }
                else if (errorMessage.StartsWith("PHONE_MIGRATE_"))
                {
                    var resultString = Regex.Match(errorMessage, @"\d+").Value;
                    var dcIdx        = int.Parse(resultString);
                    TcpTransport.UpdateDC(dcIdx);
                }
                else if (errorMessage.StartsWith("FILE_MIGRATE_"))
                {
                    // no need to worry! file is in another dc
                }
                else if (errorMessage.StartsWith("CHANNEL_INVALID"))
                {
                    // no need to worry! just skip this message
                }
                else
                {
                    throw new InvalidOperationException(errorMessage);
                }
            }
            else if (innerCode == 0x3072cfa1)
            {
                // gzip_packed
                byte[] packedData = Serializers.Bytes.Read(messageReader);
                using (MemoryStream packedStream = new MemoryStream(packedData, false))
                    using (GZipStream zipStream = new GZipStream(packedStream, CompressionMode.Decompress))
                        using (BinaryReader compressedReader = new BinaryReader(zipStream))
                        {
                            request.OnResponse(compressedReader);
                        }
            }
            else
            {
                messageReader.BaseStream.Position -= 4;

                request.OnResponse(messageReader);
            }

            return(false);
        }