diff --git a/TLSharp.Core/Network/MtProtoSender.cs b/TLSharp.Core/Network/MtProtoSender.cs index e81b5da..f7d9dc9 100644 --- a/TLSharp.Core/Network/MtProtoSender.cs +++ b/TLSharp.Core/Network/MtProtoSender.cs @@ -154,9 +154,9 @@ namespace TLSharp.Core.Network return null; } - public async Task Receive() + public async Task Receive(CancellationToken token) { - var result = DecodeMessage ((await _transport.Receieve ()).Body); + var result = DecodeMessage ((await _transport.Receieve (token)).Body); using (var messageStream = new MemoryStream (result.Item1, false)) using (var messageReader = new BinaryReader (messageStream)) diff --git a/TLSharp.Core/Network/TcpTransport.cs b/TLSharp.Core/Network/TcpTransport.cs index 31bd6b4..39ae672 100644 --- a/TLSharp.Core/Network/TcpTransport.cs +++ b/TLSharp.Core/Network/TcpTransport.cs @@ -1,6 +1,7 @@ using System; using System.Net; using System.Net.Sockets; +using System.Threading; using System.Threading.Tasks; namespace TLSharp.Core.Network @@ -86,6 +87,56 @@ namespace TLSharp.Core.Network return new TcpMessage(seq, body); } + public async Task Receieve(CancellationToken token) + { + var stream = _tcpClient.GetStream(); + + var packetLengthBytes = new byte[4]; + if (await stream.ReadAsync(packetLengthBytes, 0, 4, token) != 4) + throw new InvalidOperationException("Couldn't read the packet length"); + int packetLength = BitConverter.ToInt32(packetLengthBytes, 0); + + var seqBytes = new byte[4]; + if (await stream.ReadAsync(seqBytes, 0, 4) != 4) + throw new InvalidOperationException("Couldn't read the sequence"); + int seq = BitConverter.ToInt32(seqBytes, 0); + + int readBytes = 0; + var body = new byte[packetLength - 12]; + int neededToRead = packetLength - 12; + + do + { + var bodyByte = new byte[packetLength - 12]; + var availableBytes = await stream.ReadAsync(bodyByte, 0, neededToRead); + neededToRead -= availableBytes; + Buffer.BlockCopy(bodyByte, 0, body, readBytes, availableBytes); + readBytes += availableBytes; + } + while (readBytes != packetLength - 12); + + var crcBytes = new byte[4]; + if (await stream.ReadAsync(crcBytes, 0, 4) != 4) + throw new InvalidOperationException("Couldn't read the crc"); + int checksum = BitConverter.ToInt32(crcBytes, 0); + + byte[] rv = new byte[packetLengthBytes.Length + seqBytes.Length + body.Length]; + + Buffer.BlockCopy(packetLengthBytes, 0, rv, 0, packetLengthBytes.Length); + Buffer.BlockCopy(seqBytes, 0, rv, packetLengthBytes.Length, seqBytes.Length); + Buffer.BlockCopy(body, 0, rv, packetLengthBytes.Length + seqBytes.Length, body.Length); + var crc32 = new Ionic.Crc.CRC32(); + crc32.SlurpBlock(rv, 0, rv.Length); + var validChecksum = crc32.Crc32Result; + + if (checksum != validChecksum) + { + throw new InvalidOperationException("invalid checksum! skip"); + } + + return new TcpMessage(seq, body); + } + public bool IsConnected { get diff --git a/TLSharp.Core/TelegramClient.cs b/TLSharp.Core/TelegramClient.cs index 641f8d4..faeedd9 100644 --- a/TLSharp.Core/TelegramClient.cs +++ b/TLSharp.Core/TelegramClient.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using System.Security.Cryptography; using System.Text; +using System.Threading; using System.Threading.Tasks; using TeleSharp.TL; using TeleSharp.TL.Account; @@ -31,8 +32,10 @@ namespace TLSharp.Core private TcpClientConnectionHandler _handler; public delegate void UpdatesEvent (TelegramClient source, TLAbsUpdates updates); + public delegate void ClientEvent(TelegramClient source); public event UpdatesEvent Updates; + public event ClientEvent IdleLoop; public Session Session { get { return _session; } } @@ -113,11 +116,20 @@ namespace TLSharp.Core } } - public async Task MainLoopAsync() + public async Task MainLoopAsync(CancellationTokenSource source) { for (;;) { - await WaitEventAsync(); + try + { + await WaitEventAsync(source.Token); + } catch (OperationCanceledException) + { + } + finally + { + IdleLoop(this); + } } } @@ -146,9 +158,9 @@ namespace TLSharp.Core } } - public async Task WaitEventAsync() + public async Task WaitEventAsync(CancellationToken token) { - await _sender.Receive (); + await _sender.Receive (token); } public bool IsUserAuthorized()