private async Task RequestWithDcMigration(TLMethod request, CancellationToken token = default(CancellationToken)) { if (sender == null) { throw new InvalidOperationException("Not connected!"); } var completed = false; while (!completed) { try { await sender.Send(request, token).ConfigureAwait(false); await sender.Receive(request, token).ConfigureAwait(false); completed = true; } catch (DataCenterMigrationException e) { if (session.DataCenter.DataCenterId.HasValue && session.DataCenter.DataCenterId.Value == e.DC) { throw new Exception($"Telegram server replied requesting a migration to DataCenter {e.DC} when this connection was already using this DataCenter", e); } await ReconnectToDcAsync(e.DC, token).ConfigureAwait(false); // prepare the request for another try request.ConfirmReceived = false; } } }
public async Task Send(TLMethod request, CancellationToken token = default) { token.ThrowIfCancellationRequested(); // TODO: refactor if (needConfirmation.Any()) { var ackRequest = new AckRequest(needConfirmation); using (var memory = new MemoryStream()) using (var writer = new BinaryWriter(memory)) { ackRequest.SerializeBody(writer); await Send(memory.ToArray(), ackRequest, token).ConfigureAwait(false); needConfirmation.Clear(); } } using (var memory = new MemoryStream()) using (var writer = new BinaryWriter(memory)) { request.SerializeBody(writer); await Send(memory.ToArray(), request, token).ConfigureAwait(false); } session.Save(); }
public async Task Send(TLMethod request) { // TODO: refactor if (needConfirmation.Any()) { var ackRequest = new AckRequest(needConfirmation); using (var memory = new MemoryStream()) using (var writer = new BinaryWriter(memory)) { ackRequest.SerializeBody(writer); await Send(memory.ToArray(), ackRequest); needConfirmation.Clear(); } } using (var memory = new MemoryStream()) using (var writer = new BinaryWriter(memory)) { request.SerializeBody(writer); await Send(memory.ToArray(), request); } _session.Save(); }
public async Task Send(byte[] packet, TLMethod 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()); } } }
public async Task <TRecv> ExecuteMethodAsync <TSend, TRecv>(TLMethod <TSend, TRecv> method) where TSend : TLObject, new() where TRecv : TLObject, new() { await SendObjectAsync(method.SendObject).ConfigureAwait(false); int headerLen = _tcpClient.GetStream().ReadByte(); if (headerLen == 0x7F) { headerLen = _tcpClient.GetStream().ReadByte(); headerLen += _tcpClient.GetStream().ReadByte() << 8; headerLen += _tcpClient.GetStream().ReadByte() << 16; } headerLen *= 4; Console.WriteLine("....receiving...."); byte[] recvArr = new byte[headerLen]; await _tcpClient.GetStream().ReadAsync(recvArr, 0, headerLen).ConfigureAwait(false); DebugUtils.DumpBytes(recvArr); Console.WriteLine("\n....done...."); method.ReceiveObject = TLRootSerializer.Deserialize <TRecv>(recvArr.ToList()); return(method.ReceiveObject); }
private async Task RequestWithDcMigration(TLMethod request) { if (_sender == null) { throw new InvalidOperationException("Not connected!"); } var completed = false; while (!completed) { try { await _sender.Send(request); await _sender.Receive(request); completed = true; } catch (DataCenterMigrationException e) { await ReconnectToDcAsync(e.DC); // prepare the request for another try request.ConfirmReceived = false; } } }
public async Task <T> SendRequestAsync <T>(TLMethod methodToExecute, CancellationToken token = default(CancellationToken)) { await RequestWithDcMigration(methodToExecute, token).ConfigureAwait(false); var result = methodToExecute.GetType().GetProperty("Response").GetValue(methodToExecute); return((T)result); }
public async Task <T> SendRequestAsync <T>(TLMethod methodToExecute) { await RequestWithDcMigration(methodToExecute); var result = methodToExecute.GetType().GetProperty("Response").GetValue(methodToExecute); return((T)result); }
private async Task HandleError(TLMethod request) { if (request.Error == RpcRequestError.MigrateDataCenter) { if (request.ErrorMessage.StartsWith("PHONE_MIGRATE_") || request.ErrorMessage.StartsWith("NETWORK_MIGRATE_") || request.ErrorMessage.StartsWith("USER_MIGRATE_")) { var dcIdStr = Regex.Match(request.ErrorMessage, @"\d+").Value; var dcId = int.Parse(dcIdStr); await ReconnectToDcAsync(dcId); // try one more time request.ResetError(); await _sender.Send(request); } } if (request.Error == RpcRequestError.Flood) { if (request.ErrorMessage.StartsWith("FLOOD_WAIT_")) { var secondsToWaitStr = Regex.Match(request.ErrorMessage, @"\d+").Value; var secondsToWait = int.Parse(secondsToWaitStr); if (secondsToWait <= 2) { await Task.Delay(TimeSpan.FromSeconds(secondsToWait)); // try one more time request.ResetError(); await _sender.Send(request); } // otherwise error and exception } } // handle errors that can be fixed without user interaction if (request.Error == RpcRequestError.IncorrectServerSalt) { // assuming that salt was already updated by underlying layer request.ResetError(); await _sender.Send(request); if (request.Error != RpcRequestError.None) { await HandleError(request); } } if (request.Error == RpcRequestError.MessageSeqNoTooLow) { // resync updates state } }
public override void deserializeBody(InputStream stream, TLContext context) { this.apiId = StreamingUtils.readInt(stream); this.deviceModel = StreamingUtils.readTLString(stream); this.systemVersion = StreamingUtils.readTLString(stream); this.appVersion = StreamingUtils.readTLString(stream); this.langCode = StreamingUtils.readTLString(stream); this.query = StreamingUtils.readTLMethod(stream, context); }
public TLRequestInitConnection(int apiId, string deviceModel, string systemVersion, string appVersion, string langCode, TLMethod query) { this.apiId = apiId; this.deviceModel = deviceModel; this.systemVersion = systemVersion; this.appVersion = appVersion; this.langCode = langCode; this.query = query; }
public async Task <T> SendRequestAsync <T>(TLMethod methodToExecute) { logger.Info("Sending Request: {0} {1:x8}", methodToExecute, methodToExecute.Constructor); await RequestWithDcMigration(methodToExecute); var result = methodToExecute.GetType().GetProperty("Response").GetValue(methodToExecute); return((T)result); }
internal async Task <T> SendAuthenticatedRequestAsync <T> (TLMethod methodToExecute, CancellationToken token = default(CancellationToken)) { if (!IsUserAuthorized()) { throw new InvalidOperationException("Authorize user first!"); } return(await SendRequestAsync <T>(methodToExecute, token) .ConfigureAwait(false)); }
public async Task <T> SendRequestAsync <T>(TLMethod methodtoExceute) { await _sender.Send(methodtoExceute); await _sender.Receive(methodtoExceute); var result = methodtoExceute.GetType().GetProperty("Response").GetValue(methodtoExceute); return((T)result); }
public async Task SendRpcRequest(TLMethod request) { await _sender.Send(request); // error handling order is important await HandleError(request); _session.Save(); // escalate to user request.ThrowIfHasError(); }
public new async Task <T> SendRequestAsync <T>(TLMethod methodToExecute) { try { WaitForQueue(Guid.NewGuid()); return(await base.SendRequestAsync <T>(methodToExecute)); } catch (FloodException ex) { Thread.Sleep(ex.TimeToWait); return(await SendRequestAsync <T>(methodToExecute)); } }
public async Task <byte[]> Receive(TLMethod request, CancellationToken token = default) { while (!request.ConfirmReceived) { var result = DecodeMessage((await transport.Receive(token).ConfigureAwait(false)).Body); using (var messageStream = new MemoryStream(result.Item1, false)) using (var messageReader = new BinaryReader(messageStream)) { ProcessMessage(result.Item2, result.Item3, messageReader, request, token); } token.ThrowIfCancellationRequested(); } return(null); }
private async Task MakeRequestAtDataCenterWithTemporarySubClient(TLMethod request, int dataCenter) { var fakeStore = new FakeSessionStore(); var subClient = new TelegramClient(_apiId, _apiHash, fakeStore, "session", null, _useIpV6DataCenters) { _session = Session.FromBytes(_session.ToBytes(), fakeStore, "session"), _transport = new TcpTransport(_session.DataCenter.Address, _session.DataCenter.Port, _handler) }; await subClient.ConnectAsync(); await subClient.ReconnectToDcAsync(dataCenter); request.ConfirmReceived = false; await subClient.RequestWithDcMigration(request); _session.LastMessageId = subClient._session.LastMessageId; _session.Sequence = subClient._session.Sequence; }
private async Task RequestWithDcMigration(TLMethod request) { var completed = false; while (!completed) { try { await _sender.Send(request); await _sender.Receive(request); completed = true; } catch (DataCenterMigrationException e) { await ReconnectToDcAsync(e.DC); } } }
private async Task RequestWithDcMigration(TLMethod request) { if (_sender == null) { throw new InvalidOperationException("Not connected!"); } var completed = false; while (!completed) { try { await _sender.Send(request); await _sender.Receive(request); completed = true; } catch (FileMigrationException ex) { await MakeRequestAtDataCenterWithTemporarySubClient(request, ex.DC); completed = true; } catch (DataCenterMigrationException e) { if (_session.DataCenter.DataCenterId.HasValue && _session.DataCenter.DataCenterId.Value == e.DC) { throw new Exception($"Telegram server replied requesting a migration to DataCenter {e.DC} when this connection was already using this DataCenter", e); } await ReconnectToDcAsync(e.DC); // prepare the request for another try request.ConfirmReceived = false; } } }
public async Task Send(byte[] packet, TLMethod request, CancellationToken token = default) { token.ThrowIfCancellationRequested(); 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(), token).ConfigureAwait(false); } } }
private bool HandlePong(ulong messageId, int sequence, BinaryReader messageReader, TLMethod request) { uint code = messageReader.ReadUInt32(); ulong msgId = messageReader.ReadUInt64(); if (msgId == (ulong)request.MessageId) { request.ConfirmReceived = true; } return(false); }
private bool HandleGzipPacked(ulong messageId, int sequence, BinaryReader messageReader, TLMethod request, CancellationToken token = default(CancellationToken)) { token.ThrowIfCancellationRequested(); 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, token); } return(true); }
private bool ProcessMessage(ulong messageId, int sequence, BinaryReader messageReader, TLMethod request, CancellationToken token = default) { token.ThrowIfCancellationRequested(); // 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, token)); case 0x7abe77ec: // ping //logger.debug("MSG ping"); return(HandlePing(messageId, sequence, messageReader)); case 0x347773c5: // pong //logger.debug("MSG pong"); return(HandlePong(messageId, sequence, messageReader, request)); 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, token)); 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, token)); 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); } }
private bool HandleGzipPacked(ulong messageId, int sequence, BinaryReader messageReader, TLMethod request, CancellationToken token = default) { token.ThrowIfCancellationRequested(); uint code = messageReader.ReadUInt32(); byte[] packedData = Serializers.Bytes.Read(messageReader); using (var ms = new MemoryStream()) { using (var packedStream = new MemoryStream(packedData, false)) using (var zipStream = new GZipStream(packedStream, CompressionMode.Decompress)) { zipStream.CopyTo(ms); ms.Position = 0; } using (BinaryReader compressedReader = new BinaryReader(ms)) { ProcessMessage(messageId, sequence, compressedReader, request, token); } } return(true); }
public override void deserializeBody(InputStream stream, TLContext context) { this.msgId = StreamingUtils.readLong(stream); this.query = StreamingUtils.readTLMethod(stream, context); }
private bool HandleRpcResult(ulong messageId, int sequence, BinaryReader messageReader, TLMethod 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); throw new FloodException(TimeSpan.FromSeconds(seconds)); } else if (errorMessage.StartsWith("PHONE_MIGRATE_")) { var resultString = Regex.Match(errorMessage, @"\d+").Value; var dcIdx = int.Parse(resultString); throw new PhoneMigrationException(dcIdx); } else if (errorMessage.StartsWith("FILE_MIGRATE_")) { var resultString = Regex.Match(errorMessage, @"\d+").Value; var dcIdx = int.Parse(resultString); throw new FileMigrationException(dcIdx); } else if (errorMessage.StartsWith("USER_MIGRATE_")) { var resultString = Regex.Match(errorMessage, @"\d+").Value; var dcIdx = int.Parse(resultString); throw new UserMigrationException(dcIdx); } else if (errorMessage.StartsWith("NETWORK_MIGRATE_")) { var resultString = Regex.Match(errorMessage, @"\d+").Value; var dcIdx = int.Parse(resultString); throw new NetworkMigrationException(dcIdx); } else if (errorMessage == "PHONE_CODE_INVALID") { throw new InvalidPhoneCodeException("The numeric code used to authenticate does not match the numeric code sent by SMS/Telegram"); } else if (errorMessage == "SESSION_PASSWORD_NEEDED") { throw new CloudPasswordNeededException("This Account has Cloud Password !"); } else { throw new InvalidOperationException(errorMessage); } } else if (innerCode == 0x3072cfa1) { // gzip_packed byte[] packedData = Serializers.Bytes.Read(messageReader); using (var ms = new MemoryStream()) { using (var packedStream = new MemoryStream(packedData, false)) using (var zipStream = new GZipStream(packedStream, CompressionMode.Decompress)) { zipStream.CopyTo(ms); ms.Position = 0; } using (var compressedReader = new BinaryReader(ms)) { request.DeserializeResponse(compressedReader); } } } else { messageReader.BaseStream.Position -= 4; request.DeserializeResponse(messageReader); } return(false); }
private bool HandleContainer(ulong messageId, int sequence, BinaryReader messageReader, TLMethod request, CancellationToken token = default) { token.ThrowIfCancellationRequested(); 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, token)) { messageReader.BaseStream.Position = beginPosition + innerLength; } } catch (Exception) { // logger.error("failed to process message in container: {0}", e); messageReader.BaseStream.Position = beginPosition + innerLength; } } return(false); }
private bool HandleBadServerSalt(ulong messageId, int sequence, BinaryReader messageReader, TLMethod request, CancellationToken token = default) { token.ThrowIfCancellationRequested(); 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, token); /* * 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); }
public virtual void setQuery(TLMethod value) { this.query = value; }