From db362a0ea3c77a7c8ffe8565ef25d52dbc7a7b4f Mon Sep 17 00:00:00 2001 From: "Andres G. Aragoneses" Date: Sun, 10 Feb 2019 13:53:46 +0100 Subject: [PATCH] Core: avoid possible infinite loop if switching to same DC People are reporting that under some circumstances, an infinite loop could happen when TLSharp tries to handle a reconnection to a different DC, if the DC instructed to be used is the same as the one that was used in the last connection. Not sure how could this happen (although the analysis present in this github issue [1] might help understand it), but this commit helps to make TLSharp fail fast (with an exception) instead of an infinite loop from now on, which will help avoiding people file issues such as [2] and [3] and instead maybe file a proper bug report easier to understand, to try to fix the underlying root cause. [1] https://github.com/sochix/TLSharp/issues/719 [2] https://github.com/sochix/TLSharp/issues/803 [3] https://github.com/sochix/TLSharp/issues/839 --- TLSharp.Core/DataCenter.cs | 21 +++++++++++++++++++++ TLSharp.Core/Session.cs | 16 ++++++++-------- TLSharp.Core/TLSharp.Core.csproj | 1 + TLSharp.Core/TelegramClient.cs | 12 +++++++++--- 4 files changed, 39 insertions(+), 11 deletions(-) create mode 100644 TLSharp.Core/DataCenter.cs diff --git a/TLSharp.Core/DataCenter.cs b/TLSharp.Core/DataCenter.cs new file mode 100644 index 0000000..96e6898 --- /dev/null +++ b/TLSharp.Core/DataCenter.cs @@ -0,0 +1,21 @@ + +namespace TLSharp.Core +{ + internal class DataCenter + { + internal DataCenter (int? dcId, string address, int port) + { + DataCenterId = dcId; + Address = address; + Port = port; + } + + internal DataCenter (string address, int port) : this (null, address, port) + { + } + + internal int? DataCenterId { get; private set; } + internal string Address { get; private set; } + internal int Port { get; private set; } + } +} diff --git a/TLSharp.Core/Session.cs b/TLSharp.Core/Session.cs index 987c5d2..6264770 100644 --- a/TLSharp.Core/Session.cs +++ b/TLSharp.Core/Session.cs @@ -59,8 +59,7 @@ namespace TLSharp.Core private const int defaultConnectionPort = 443; public string SessionUserId { get; set; } - public string ServerAddress { get; set; } - public int Port { get; set; } + internal DataCenter DataCenter { get; set; } public AuthKey AuthKey { get; set; } public ulong Id { get; set; } public int Sequence { get; set; } @@ -89,8 +88,8 @@ namespace TLSharp.Core writer.Write(Salt); writer.Write(LastMessageId); writer.Write(TimeOffset); - Serializers.String.write(writer, ServerAddress); - writer.Write(Port); + Serializers.String.write(writer, DataCenter.Address); + writer.Write(DataCenter.Port); if (TLUser != null) { @@ -132,6 +131,7 @@ namespace TLSharp.Core } var authData = Serializers.Bytes.read(reader); + var defaultDataCenter = new DataCenter (serverAddress, port); return new Session(store) { @@ -144,8 +144,7 @@ namespace TLSharp.Core SessionExpires = sessionExpires, TLUser = TLUser, SessionUserId = sessionUserId, - ServerAddress = serverAddress, - Port = port + DataCenter = defaultDataCenter, }; } } @@ -157,12 +156,13 @@ namespace TLSharp.Core public static Session TryLoadOrCreateNew(ISessionStore store, string sessionUserId) { + var defaultDataCenter = new DataCenter (defaultConnectionAddress, defaultConnectionPort); + return store.Load(sessionUserId) ?? new Session(store) { Id = GenerateRandomUlong(), SessionUserId = sessionUserId, - ServerAddress = defaultConnectionAddress, - Port = defaultConnectionPort + DataCenter = defaultDataCenter, }; } diff --git a/TLSharp.Core/TLSharp.Core.csproj b/TLSharp.Core/TLSharp.Core.csproj index fbef942..74efe73 100644 --- a/TLSharp.Core/TLSharp.Core.csproj +++ b/TLSharp.Core/TLSharp.Core.csproj @@ -68,6 +68,7 @@ + diff --git a/TLSharp.Core/TelegramClient.cs b/TLSharp.Core/TelegramClient.cs index 6880313..d9f0454 100644 --- a/TLSharp.Core/TelegramClient.cs +++ b/TLSharp.Core/TelegramClient.cs @@ -45,7 +45,7 @@ namespace TLSharp.Core _handler = handler; _session = Session.TryLoadOrCreateNew(store, sessionUserId); - _transport = new TcpTransport(_session.ServerAddress, _session.Port, _handler); + _transport = new TcpTransport(_session.DataCenter.Address, _session.DataCenter.Port, _handler); } public async Task ConnectAsync(bool reconnect = false) @@ -90,10 +90,10 @@ namespace TLSharp.Core } var dc = dcOptions.First(d => d.Id == dcId); + var dataCenter = new DataCenter (dcId, dc.IpAddress, dc.Port); _transport = new TcpTransport(dc.IpAddress, dc.Port, _handler); - _session.ServerAddress = dc.IpAddress; - _session.Port = dc.Port; + _session.DataCenter = dataCenter; await ConnectAsync(true); @@ -121,6 +121,12 @@ namespace TLSharp.Core } 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;