TLSharp/src/TgSharp.Core/Session.cs
Andres G. Aragoneses 79ad0fc21e Core: make MtProtoSender.GenerateSequence() thread-safe
Even if you're not supposed to use multiple threads with TLSharp,
it might be worth it to try to make this sequence increment in
a thread-safe way. Race conditions are always bad even if you know
you are not supposed to use something in a certain way...

@Laituex was having a ErrCode=32 'msg_seqno too low' problem and this
is the first thing we looked at (even if he swore that he was not
using different threads to access the telegram network).

(Backported from 881bdd27a5 )

# Conflicts:
#	src/TgSharp.Core/Session.cs
2020-10-14 20:48:43 +02:00

104 lines
3.1 KiB
C#

using System;
using System.IO;
using TgSharp.TL;
using TgSharp.Core.MTProto;
using TgSharp.Core.MTProto.Crypto;
namespace TgSharp.Core
{
public interface ISessionStore
{
void Save(Session session);
Session Load(string sessionUserId);
}
public class FakeSessionStore : ISessionStore
{
public void Save(Session session)
{
}
public Session Load(string sessionUserId)
{
return null;
}
}
internal static class SessionFactory
{
internal static Session TryLoadOrCreateNew (ISessionStore store, string sessionUserId)
{
var session = store.Load (sessionUserId);
if (null == session) {
var defaultDataCenter = new DataCenter ();
session = new Session {
Id = GenerateRandomUlong (),
SessionUserId = sessionUserId,
DataCenter = defaultDataCenter,
};
}
return session;
}
private static ulong GenerateRandomUlong ()
{
var random = new Random ();
ulong rand = (((ulong)random.Next ()) << 32) | ((ulong)random.Next ());
return rand;
}
}
public class Session
{
internal object Lock = new object ();
public int Sequence { get; set; }
#if CI
// see the same CI-wrapped assignment in .FromBytes(), but this one will become useful
// when we generate a new session.dat for CI again
= CurrentTime ();
// this is similar to the unixTime but rooted on the worst year of humanity instead of 1970
internal static int CurrentTime ()
{
return (int)DateTime.UtcNow.Subtract (new DateTime (2020, 1, 1)).TotalSeconds;
}
#endif
public string SessionUserId { get; set; }
internal DataCenter DataCenter { get; set; }
public AuthKey AuthKey { get; set; }
public ulong Id { get; set; }
public ulong Salt { get; set; }
public int TimeOffset { get; set; }
public long LastMessageId { get; set; }
public int SessionExpires { get; set; }
public TLUser TLUser { get; set; }
private Random random;
public Session()
{
random = new Random();
}
public long GetNewMessageId()
{
long time = Convert.ToInt64((DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalMilliseconds);
long newMessageId = ((time / 1000 + TimeOffset) << 32) |
((time % 1000) << 22) |
(random.Next(524288) << 2); // 2^19
// [ unix timestamp : 32 bit] [ milliseconds : 10 bit ] [ buffer space : 1 bit ] [ random : 19 bit ] [ msg_id type : 2 bit ] = [ msg_id : 64 bit ]
if (LastMessageId >= newMessageId)
{
newMessageId = LastMessageId + 4;
}
LastMessageId = newMessageId;
return newMessageId;
}
}
}