public async Task Send(MTProtoRequest request) { // TODO: refactor if (needConfirmation.Any()) { var ackRequest = new AckRequest(needConfirmation); using (var memory = new MemoryStream()) using (var writer = new BinaryWriter(memory)) { ackRequest.OnSend(writer); await Send(memory.ToArray(), ackRequest); needConfirmation.Clear(); } } using (var memory = new MemoryStream()) using (var writer = new BinaryWriter(memory)) { request.OnSend(writer); await Send(memory.ToArray(), request); } _session.Save(); }
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()); } } }
private bool HandleContainer(ulong messageId, int sequence, BinaryReader messageReader, MTProtoRequest request) { uint code = messageReader.ReadUInt32(); int size = messageReader.ReadInt32(); for (int i = 0; i < size; i++) { ulong innerMessageId = messageReader.ReadUInt64(); 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; }
private bool HandleBadServerSalt(ulong 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; }
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 byte[] packedData = Serializers.Bytes.read(messageReader); using (var packedStream = new MemoryStream(packedData, false)) using (var zipStream = new GZipStream(packedStream, CompressionMode.Decompress)) using (var compressedReader = new BinaryReader(zipStream)) { request.OnResponse(compressedReader); } } catch (ZlibException ex) { } } else { messageReader.BaseStream.Position -= 4; request.OnResponse(messageReader); } return false; }
private bool HandleGzipPacked(ulong messageId, int sequence, BinaryReader messageReader, MTProtoRequest request) { uint code = messageReader.ReadUInt32(); byte[] packedData = GZipStream.UncompressBuffer(Serializers.Bytes.read(messageReader)); using (MemoryStream packedStream = new MemoryStream(packedData, false)) using (BinaryReader compressedReader = new BinaryReader(packedStream)) { processMessage(messageId, sequence, compressedReader, request); } return true; }
private bool processMessage(ulong messageId, int sequence, BinaryReader 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; } }
public async Task<byte[]> Recieve(MTProtoRequest request) { while (!request.ConfirmReceived) { var result = DecodeMessage((await _transport.Receieve()).Body); using (var messageStream = new MemoryStream(result.Item1, false)) using (var messageReader = new BinaryReader(messageStream)) { processMessage(result.Item2, result.Item3, messageReader, request); } } return null; }
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 { 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; }