diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml index a73cc8bc..674320dd 100644 --- a/.github/workflows/dotnet.yml +++ b/.github/workflows/dotnet.yml @@ -16,7 +16,7 @@ jobs: - name: Setup .NET uses: actions/setup-dotnet@v1 with: - dotnet-version: 5.0.x + dotnet-version: 7.0.x - name: Restore dependencies run: dotnet restore - name: Build diff --git a/Rasa.NET.sln b/Rasa.NET.sln index 685b5bff..40870d46 100644 --- a/Rasa.NET.sln +++ b/Rasa.NET.sln @@ -1,6 +1,6 @@ Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.31105.61 +# Visual Studio Version 17 +VisualStudioVersion = 17.4.33213.308 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{B8E6F56E-FC5A-40E5-A0B7-38A1073647FB}" EndProject @@ -8,15 +8,13 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Rasa.Auth", "src\Rasa.Auth\ EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Rasa.DBL", "src\Rasa.DBL\Rasa.DBL.csproj", "{5114F5F3-F51F-4F05-AAD2-5806AAE2B737}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Rasa.Shared", "src\Rasa.Shared\Rasa.Shared.csproj", "{CC99C7B9-534F-4D7A-B6A5-A1B52D66EDE8}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Rasa.Utils", "src\Rasa.Utils\Rasa.Utils.csproj", "{46370C5D-4E11-4546-9DC7-D6934F506192}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Rasa.Game", "src\Rasa.Game\Rasa.Game.csproj", "{EB59A12A-04D6-44B2-A414-8D25DAFD565D}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Rasa.Test", "src\Rasa.Test\Rasa.Test.csproj", "{42A96BBC-A86C-44F4-BD31-93685CEB773F}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Rasa.Communicator", "src\Rasa.Communicator\Rasa.Communicator.csproj", "{A7C35087-0201-456B-9AB3-0F8B1626075E}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Rasa.Communicator", "src\Rasa.Communicator\Rasa.Communicator.csproj", "{A7C35087-0201-456B-9AB3-0F8B1626075E}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -52,18 +50,6 @@ Global {5114F5F3-F51F-4F05-AAD2-5806AAE2B737}.Release|x64.Build.0 = Release|Any CPU {5114F5F3-F51F-4F05-AAD2-5806AAE2B737}.Release|x86.ActiveCfg = Release|Any CPU {5114F5F3-F51F-4F05-AAD2-5806AAE2B737}.Release|x86.Build.0 = Release|Any CPU - {CC99C7B9-534F-4D7A-B6A5-A1B52D66EDE8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {CC99C7B9-534F-4D7A-B6A5-A1B52D66EDE8}.Debug|Any CPU.Build.0 = Debug|Any CPU - {CC99C7B9-534F-4D7A-B6A5-A1B52D66EDE8}.Debug|x64.ActiveCfg = Debug|Any CPU - {CC99C7B9-534F-4D7A-B6A5-A1B52D66EDE8}.Debug|x64.Build.0 = Debug|Any CPU - {CC99C7B9-534F-4D7A-B6A5-A1B52D66EDE8}.Debug|x86.ActiveCfg = Debug|Any CPU - {CC99C7B9-534F-4D7A-B6A5-A1B52D66EDE8}.Debug|x86.Build.0 = Debug|Any CPU - {CC99C7B9-534F-4D7A-B6A5-A1B52D66EDE8}.Release|Any CPU.ActiveCfg = Release|Any CPU - {CC99C7B9-534F-4D7A-B6A5-A1B52D66EDE8}.Release|Any CPU.Build.0 = Release|Any CPU - {CC99C7B9-534F-4D7A-B6A5-A1B52D66EDE8}.Release|x64.ActiveCfg = Release|Any CPU - {CC99C7B9-534F-4D7A-B6A5-A1B52D66EDE8}.Release|x64.Build.0 = Release|Any CPU - {CC99C7B9-534F-4D7A-B6A5-A1B52D66EDE8}.Release|x86.ActiveCfg = Release|Any CPU - {CC99C7B9-534F-4D7A-B6A5-A1B52D66EDE8}.Release|x86.Build.0 = Release|Any CPU {46370C5D-4E11-4546-9DC7-D6934F506192}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {46370C5D-4E11-4546-9DC7-D6934F506192}.Debug|Any CPU.Build.0 = Debug|Any CPU {46370C5D-4E11-4546-9DC7-D6934F506192}.Debug|x64.ActiveCfg = Debug|Any CPU @@ -119,7 +105,6 @@ Global GlobalSection(NestedProjects) = preSolution {33A8C17A-375E-4474-B8F5-44ED7833BF79} = {B8E6F56E-FC5A-40E5-A0B7-38A1073647FB} {5114F5F3-F51F-4F05-AAD2-5806AAE2B737} = {B8E6F56E-FC5A-40E5-A0B7-38A1073647FB} - {CC99C7B9-534F-4D7A-B6A5-A1B52D66EDE8} = {B8E6F56E-FC5A-40E5-A0B7-38A1073647FB} {46370C5D-4E11-4546-9DC7-D6934F506192} = {B8E6F56E-FC5A-40E5-A0B7-38A1073647FB} {EB59A12A-04D6-44B2-A414-8D25DAFD565D} = {B8E6F56E-FC5A-40E5-A0B7-38A1073647FB} {42A96BBC-A86C-44F4-BD31-93685CEB773F} = {B8E6F56E-FC5A-40E5-A0B7-38A1073647FB} diff --git a/src/Rasa.Auth/Auth/Client.cs b/src/Rasa.Auth/Auth/Client.cs index aae23241..cfe72486 100644 --- a/src/Rasa.Auth/Auth/Client.cs +++ b/src/Rasa.Auth/Auth/Client.cs @@ -1,289 +1,300 @@ using System; -using System.Net.Sockets; - -namespace Rasa.Auth +using System.Buffers; +using System.IO; +using System.Net; + +namespace Rasa.Auth; + +using Rasa.Communicator; +using Rasa.Cryptography; +using Rasa.Data; +using Rasa.Extensions; +using Rasa.Memory; +using Rasa.Networking; +using Rasa.Packets; +using Rasa.Packets.Auth.Client; +using Rasa.Packets.Auth.Server; +using Rasa.Repositories; +using Rasa.Repositories.Auth.Account; +using Rasa.Repositories.UnitOfWork; +using Rasa.Structures.Auth; +using Rasa.Timer; + +public class Client { - using Cryptography; - using Data; - using Extensions; - using Memory; - using Networking; - using Packets; - using Packets.Auth.Client; - using Packets.Auth.Server; - using Repositories; - using Repositories.Auth.Account; - using Repositories.UnitOfWork; - using Structures; - using Structures.Auth; - using Timer; - - public class Client - { - private readonly IAuthUnitOfWorkFactory _authUnitOfWorkFactory; + public const int SendBufferSize = 512; + public const int SendBufferCryptoPadding = 8; + public const int SendBufferChecksumPadding = 8; - public const int LengthSize = 2; + private readonly IAuthUnitOfWorkFactory _authUnitOfWorkFactory; - public LengthedSocket Socket { get; } - public Server Server { get; } + public AsyncLengthedSocket Socket { get; } + public Server Server { get; } - public uint OneTimeKey { get; } - public uint SessionId1 { get; } - public uint SessionId2 { get; } - public AuthAccountEntry AccountEntry { get; private set; } - public ClientState State { get; private set; } - public Timer Timer { get; } + public uint OneTimeKey { get; } + public uint SessionId1 { get; } + public uint SessionId2 { get; } + public AuthAccountEntry AccountEntry { get; private set; } + public ClientState State { get; private set; } + public Timer Timer { get; } - private PacketQueue _packetQueue = new(); + private readonly PacketQueue _packetQueue = new(); - public Client(LengthedSocket socket, Server server, IAuthUnitOfWorkFactory authUnitOfWorkFactory) - { - _authUnitOfWorkFactory = authUnitOfWorkFactory; + public Client(AsyncLengthedSocket socket, Server server, IAuthUnitOfWorkFactory authUnitOfWorkFactory) + { + _authUnitOfWorkFactory = authUnitOfWorkFactory; - Socket = socket; - Server = server; - State = ClientState.Connected; + Server = server; + State = ClientState.Connected; - Timer = new Timer(); + Timer = new Timer(); - Socket.OnError += OnError; - Socket.OnReceive += OnReceive; - Socket.OnDecrypt += OnDecrypt; + Socket = socket; + Socket.OnError += OnError; + Socket.OnReceive += OnReceive; + Socket.Start(); - Socket.ReceiveAsync(); + var rnd = new Random(); - var rnd = new Random(); + OneTimeKey = rnd.NextUInt(); + SessionId1 = rnd.NextUInt(); + SessionId2 = rnd.NextUInt(); - OneTimeKey = rnd.NextUInt(); - SessionId1 = rnd.NextUInt(); - SessionId2 = rnd.NextUInt(); + SendPacket(new ProtocolVersionPacket(OneTimeKey)); - SendPacket(new ProtocolVersionPacket(OneTimeKey)); + Timer.Add("timeout", Server.Config.AuthConfig.ClientTimeout * 1000, false, () => + { + Logger.WriteLog(LogType.Network, "*** Client timed out! Ip: {0}", Socket.RemoteAddress); - // This is here (after ProtocolVersionPacket), so it won't get encrypted - Socket.OnEncrypt += OnEncrypt; + Close(); + }); - Timer.Add("timeout", Server.Config.AuthConfig.ClientTimeout * 1000, false, () => - { - Logger.WriteLog(LogType.Network, "*** Client timed out! Ip: {0}", Socket.RemoteAddress); + Logger.WriteLog(LogType.Network, "*** Client connected from {0}", Socket.RemoteAddress); + } - Close(); - }); + public void Update(long delta) + { + Timer.Update(delta); - Logger.WriteLog(LogType.Network, "*** Client connected from {0}", Socket.RemoteAddress); - } + if (State == ClientState.Disconnected) + return; - public void Update(long delta) - { - Timer.Update(delta); + IBasePacket packet; - if (State == ClientState.Disconnected) - return; + while ((packet = _packetQueue.PopIncoming()) != null) + HandlePacket(packet); - IBasePacket packet; + while ((packet = _packetQueue.PopOutgoing()) != null) + SendPacket(packet); + } + + public void Close() + { + if (State == ClientState.Disconnected) + return; - while ((packet = _packetQueue.PopIncoming()) != null) - HandlePacket(packet); + Logger.WriteLog(LogType.Network, "*** Client disconnected! Ip: {0}", Socket.RemoteAddress); - while ((packet = _packetQueue.PopOutgoing()) != null) - SendPacket(packet); - } - - public void Close() - { - if (State == ClientState.Disconnected) - return; + Timer.Remove("timeout"); + + State = ClientState.Disconnected; - Logger.WriteLog(LogType.Network, "*** Client disconnected! Ip: {0}", Socket.RemoteAddress); + Socket.Close(); - Timer.Remove("timeout"); + Server.Disconnect(this); + } - State = ClientState.Disconnected; + public void SendPacket(IBasePacket packet) + { + var buffer = ArrayPool.Shared.Rent(SendBufferSize + SendBufferCryptoPadding + SendBufferChecksumPadding); + var writer = new BinaryWriter(new MemoryStream(buffer, true)); - Socket.Close(); + packet.Write(writer); - Server.Disconnect(this); - } + var length = (int)writer.BaseStream.Position; + if (packet is not ProtocolVersionPacket) + AuthCryptManager.Encrypt(buffer, 0, ref length, buffer.Length); - public void SendPacket(IBasePacket packet) - { - Socket.Send(packet); - } + Socket.Send(buffer, 0, length); - public void HandlePacket(IBasePacket packet) + ArrayPool.Shared.Return(buffer); + } + + public void HandlePacket(IBasePacket packet) + { + if (packet is not IOpcodedPacket authPacket) + return; + + switch (authPacket.Opcode) { - if (packet is not IOpcodedPacket authPacket) - return; - - switch (authPacket.Opcode) - { - case ClientOpcode.Login: - MsgLogin(authPacket as LoginPacket); - break; - - case ClientOpcode.Logout: - MsgLogout(authPacket as LogoutPacket); - break; - - case ClientOpcode.AboutToPlay: - MsgAboutToPlay(authPacket as AboutToPlayPacket); - break; - - case ClientOpcode.ServerListExt: - MsgServerListExt(authPacket as ServerListExtPacket); - break; - } + case ClientOpcode.Login: + MsgLogin(authPacket as LoginPacket); + break; + + case ClientOpcode.Logout: + MsgLogout(authPacket as LogoutPacket); + break; + + case ClientOpcode.AboutToPlay: + MsgAboutToPlay(authPacket as AboutToPlayPacket); + break; + + case ClientOpcode.ServerListExt: + MsgServerListExt(authPacket as ServerListExtPacket); + break; } + } - public void RedirectionResult(RedirectResult result, ServerInfo info) + public void RedirectionResult(CommunicatorActionResult result, ServerInfo info) + { + switch (result) { - switch (result) - { - case RedirectResult.Fail: - SendPacket(new PlayFailPacket(FailReason.UnexpectedError)); + case CommunicatorActionResult.Failure: + SendPacket(new PlayFailPacket(FailReason.UnexpectedError)); - Close(); + Close(); - Logger.WriteLog(LogType.Error, $"Account ({AccountEntry.Username}, {AccountEntry.Id}) couldn't be redirected to server: {info.ServerId}!"); - break; + Logger.WriteLog(LogType.Error, $"Account ({AccountEntry.Username}, {AccountEntry.Id}) couldn't be redirected to server: {info.ServerId}!"); + break; - case RedirectResult.Success: - HandleSuccessfulRedirect(info); - break; + case CommunicatorActionResult.Success: + HandleSuccessfulRedirect(info); + break; - default: - throw new ArgumentOutOfRangeException(nameof(result)); - } + default: + throw new ArgumentOutOfRangeException(nameof(result)); } + } - private void HandleSuccessfulRedirect(ServerInfo info) + private void HandleSuccessfulRedirect(ServerInfo info) + { + SendPacket(new HandoffToQueuePacket { - SendPacket(new HandoffToQueuePacket - { - OneTimeKey = OneTimeKey, - ServerId = info.ServerId, - AccountId = AccountEntry.Id - }); - - using var unitOfWork = _authUnitOfWorkFactory.Create(); - unitOfWork.AuthAccountRepository.UpdateLastServer(AccountEntry.Id, info.ServerId); - unitOfWork.Complete(); - - Logger.WriteLog(LogType.Network, $"Account ({AccountEntry.Username}, {AccountEntry.Id}) was redirected to the queue of the server: {info.ServerId}!"); - } + OneTimeKey = OneTimeKey, + ServerId = info.ServerId, + AccountId = AccountEntry.Id + }); - private void OnError(SocketAsyncEventArgs args) - { - Close(); - } + using var unitOfWork = _authUnitOfWorkFactory.Create(); + unitOfWork.AuthAccountRepository.UpdateLastServer(AccountEntry.Id, info.ServerId); + unitOfWork.Complete(); - private static void OnEncrypt(BufferData data, ref int length) - { - AuthCryptManager.Encrypt(data.Buffer, data.BaseOffset + data.Offset, ref length, data.RemainingLength); - } + Logger.WriteLog(LogType.Network, $"Account ({AccountEntry.Username}, {AccountEntry.Id}) was redirected to the queue of the server: {info.ServerId}!"); + } - private static bool OnDecrypt(BufferData data) - { - return AuthCryptManager.Decrypt(data.Buffer, data.BaseOffset + data.Offset, data.RemainingLength); - } + private void OnError() => Close(); - private void OnReceive(BufferData data) - { - // Reset the timeout after every action - Timer.ResetTimer("timeout"); + private void OnReceive(NonContiguousMemoryStream incomingStream, int length) + { + var data = ArrayPool.Shared.Rent(length); - using var br = data.GetReader(); + incomingStream.Read(data, 0, length); - var packet = CreatePacket((ClientOpcode)br.ReadByte()); + AuthCryptManager.Decrypt(data, 0, length); - packet.Read(br); + using var br = new BinaryReader(new MemoryStream(data, 0, length, false)); - _packetQueue.EnqueueIncoming(packet); - } + var packet = CreatePacket((ClientOpcode)br.ReadByte()); - private IBasePacket CreatePacket(ClientOpcode opcode) - { - return opcode switch - { - ClientOpcode.AboutToPlay => new AboutToPlayPacket(), - ClientOpcode.Login => new LoginPacket(), - ClientOpcode.Logout => new LogoutPacket(), - ClientOpcode.ServerListExt => new ServerListExtPacket(), - ClientOpcode.SCCheck => new SCCheckPacket(), - - _ => throw new ArgumentOutOfRangeException(nameof(opcode)), - }; - } + packet.Read(br); - #region Handlers - private void MsgLogin(LoginPacket packet) - { - using var unitOfWork = _authUnitOfWorkFactory.Create(); - - try - { - AccountEntry = unitOfWork.AuthAccountRepository.GetByUserName(packet.UserName, packet.Password); - } - catch (EntityNotFoundException) - { - SendPacket(new LoginFailPacket(FailReason.UserNameOrPassword)); - Close(); - Logger.WriteLog(LogType.Security, $"User ({packet.UserName}) tried to log in with an invalid username!"); - return; - } - catch (PasswordCheckFailedException e) - { - SendPacket(new LoginFailPacket(FailReason.UserNameOrPassword)); - Close(); - Logger.WriteLog(LogType.Security, e.Message); - return; - } - catch (AccountLockedException e) - { - SendPacket(new BlockedAccountPacket()); - Close(); - Logger.WriteLog(LogType.Security, e.Message); - return; - } + ArrayPool.Shared.Return(data); - unitOfWork.AuthAccountRepository.UpdateLoginData(AccountEntry.Id, Socket.RemoteAddress); - unitOfWork.Complete(); + _packetQueue.EnqueueIncoming(packet); - State = ClientState.LoggedIn; + // Reset the timeout after every action + Timer.ResetTimer("timeout"); + } - SendPacket(new LoginOkPacket - { - SessionId1 = SessionId1, - SessionId2 = SessionId2 - }); + private static IBasePacket CreatePacket(ClientOpcode opcode) + { + return opcode switch + { + ClientOpcode.AboutToPlay => new AboutToPlayPacket(), + ClientOpcode.Login => new LoginPacket(), + ClientOpcode.Logout => new LogoutPacket(), + ClientOpcode.ServerListExt => new ServerListExtPacket(), + ClientOpcode.SCCheck => new SCCheckPacket(), + _ => throw new ArgumentOutOfRangeException(nameof(opcode)), + }; + } - Logger.WriteLog(LogType.Network, "*** Client logged in from {0}", Socket.RemoteAddress); - } + private void MsgLogin(LoginPacket packet) + { + using var unitOfWork = _authUnitOfWorkFactory.Create(); -#pragma warning disable IDE0060 // Remove unused parameter - private void MsgLogout(LogoutPacket packet) + try + { + AccountEntry = unitOfWork.AuthAccountRepository.GetByUserName(packet.UserName, packet.Password); + } + catch (EntityNotFoundException) + { + SendPacket(new LoginFailPacket(FailReason.UserNameOrPassword)); + Close(); + Logger.WriteLog(LogType.Security, $"User ({packet.UserName}) tried to log in with an invalid username!"); + return; + } + catch (PasswordCheckFailedException e) { + SendPacket(new LoginFailPacket(FailReason.UserNameOrPassword)); Close(); + Logger.WriteLog(LogType.Security, e.Message); + return; } + catch (AccountLockedException e) + { + SendPacket(new BlockedAccountPacket()); + Close(); + Logger.WriteLog(LogType.Security, e.Message); + return; + } + + unitOfWork.AuthAccountRepository.UpdateLoginData(AccountEntry.Id, (Socket.RemoteAddress as IPEndPoint).Address); + unitOfWork.Complete(); - private void MsgServerListExt(ServerListExtPacket packet) + State = ClientState.LoggedIn; + + SendPacket(new LoginOkPacket { - State = ClientState.ServerList; + SessionId1 = SessionId1, + SessionId2 = SessionId2 + }); + + Logger.WriteLog(LogType.Network, "*** Client logged in from {0}", Socket.RemoteAddress); + } - SendPacket(new SendServerListExtPacket(Server.ServerList, AccountEntry.LastServerId)); + private void MsgLogout(LogoutPacket packet) + { + if (SessionId1 != packet.SessionId1 || SessionId2 != packet.SessionId2) + { + Logger.WriteLog(LogType.Security, $"Account ({AccountEntry.Username}, {AccountEntry.Id}) has sent an LogoutPacket with invalid session data!"); + return; } -#pragma warning restore IDE0060 // Remove unused parameter - private void MsgAboutToPlay(AboutToPlayPacket packet) + Close(); + } + + private void MsgServerListExt(ServerListExtPacket packet) + { + if (SessionId1 != packet.SessionId1 || SessionId2 != packet.SessionId2) { - if (SessionId1 != packet.SessionId1 || SessionId2 != packet.SessionId2) - { - Logger.WriteLog(LogType.Security, $"Account ({AccountEntry.Username}, {AccountEntry.Id}) has sent an AboutToPlay packet with invalid session data!"); - return; - } + Logger.WriteLog(LogType.Security, $"Account ({AccountEntry.Username}, {AccountEntry.Id}) has sent an ServerListExtPacket with invalid session data!"); + return; + } + + State = ClientState.ServerList; - Server.RequestRedirection(this, packet.ServerId); + SendPacket(new SendServerListExtPacket(Server.ServerList, AccountEntry.LastServerId)); + } + + private void MsgAboutToPlay(AboutToPlayPacket packet) + { + if (SessionId1 != packet.SessionId1 || SessionId2 != packet.SessionId2) + { + Logger.WriteLog(LogType.Security, $"Account ({AccountEntry.Username}, {AccountEntry.Id}) has sent an AboutToPlay packet with invalid session data!"); + return; } - #endregion + + Server.RequestRedirection(this, packet.ServerId); } } diff --git a/src/Rasa.Auth/Auth/CommunicatorClient.cs b/src/Rasa.Auth/Auth/CommunicatorClient.cs deleted file mode 100644 index 9e5b11ef..00000000 --- a/src/Rasa.Auth/Auth/CommunicatorClient.cs +++ /dev/null @@ -1,122 +0,0 @@ -using System; -using System.Net; -using System.Net.Sockets; - -namespace Rasa.Auth -{ - using Data; - using Memory; - using Networking; - using Packets; - using Packets.Communicator; - - public class CommunicatorClient - { - public LengthedSocket Socket { get; } - public Server Server { get; } - public byte ServerId { get; set; } - public int QueuePort { get; set; } - public int GamePort { get; set; } - public byte AgeLimit { get; set; } - public byte PKFlag { get; set; } - public ushort CurrentPlayers { get; set; } - public ushort MaxPlayers { get; set; } - public DateTime LastRequestTime { get; set; } - public IPAddress PublicAddress { get; set; } - - private readonly PacketRouter _router = new PacketRouter(); - - public bool Connected => Socket.Connected; - - public CommunicatorClient(LengthedSocket socket, Server server) - { - Server = server; - Socket = socket; - - Socket.OnReceive += OnReceive; - Socket.OnError += OnError; - - Socket.ReceiveAsync(); - } - - private void OnReceive(BufferData data) - { - var opcode = (CommOpcode) data.Buffer[data.BaseOffset + data.Offset++]; - - var packetType = _router.GetPacketType(opcode); - if (packetType == null) - return; - - var packet = Activator.CreateInstance(packetType) as IOpcodedPacket; - if (packet == null) - return; - - packet.Read(data.GetReader()); - - _router.RoutePacket(this, packet); - } - - private void OnError(SocketAsyncEventArgs args) - { - Socket.Close(); - - Server.DisconnectCommunicator(this); - } - - public void RequestServerInfo() - { - LastRequestTime = DateTime.Now; - - Socket.Send(new ServerInfoRequestPacket()); - } - - public void RequestRedirection(Client client) - { - Socket.Send(new RedirectRequestPacket - { - AccountId = client.AccountEntry.Id, - Email = client.AccountEntry.Email, - Username = client.AccountEntry.Username, - OneTimeKey = client.OneTimeKey - }); - } - - // ReSharper disable once UnusedMember.Local - [PacketHandler(CommOpcode.LoginRequest)] - private void MsgLoginRequest(LoginRequestPacket packet) - { - if (!Server.AuthenticateGameServer(packet, this)) - { - Socket.Send(new LoginResponsePacket - { - Response = CommLoginReason.Failure - }); - return; - } - - Socket.Send(new LoginResponsePacket - { - Response = CommLoginReason.Success - }); - - ServerId = packet.ServerId; - PublicAddress = packet.PublicAddress; - - RequestServerInfo(); - } - - // ReSharper disable once UnusedMember.Local - [PacketHandler(CommOpcode.ServerInfoResponse)] - private void MsgGameInfoResponse(ServerInfoResponsePacket packet) - { - Server.UpdateServerInfo(this, packet); - } - - // ReSharper disable once UnusedMember.Local - [PacketHandler(CommOpcode.RedirectResponse)] - private void MsgRedirectResponse(RedirectResponsePacket packet) - { - Server.RedirectResponse(this, packet); - } - } -} diff --git a/src/Rasa.Auth/Auth/Server.cs b/src/Rasa.Auth/Auth/Server.cs index d2519451..fadef939 100644 --- a/src/Rasa.Auth/Auth/Server.cs +++ b/src/Rasa.Auth/Auth/Server.cs @@ -2,490 +2,397 @@ using System.Collections.Generic; using System.Linq; using System.Net; -using System.Net.Sockets; using Microsoft.Extensions.Hosting; -namespace Rasa.Auth +namespace Rasa.Auth; + +using Rasa.Commands; +using Rasa.Communicator; +using Rasa.Communicator.Packets; +using Rasa.Config; +using Rasa.Data; +using Rasa.Hosting; +using Rasa.Memory; +using Rasa.Networking; +using Rasa.Packets.Auth.Server; +using Rasa.Repositories.UnitOfWork; +using Rasa.Threading; +using Rasa.Timer; + +public class Server : ILoopable, IRasaServer { - using Commands; - using Config; - using Data; - using Hosting; - using Memory; - using Networking; - using Packets.Communicator; - using Packets.Auth.Server; - using Repositories.UnitOfWork; - using Structures; - using Threading; - using Timer; - - public class Server : ILoopable, IRasaServer - { - private readonly IHostApplicationLifetime _hostApplicationLifetime; - private readonly IAuthUnitOfWorkFactory _authUnitOfWorkFactory; + private readonly IHostApplicationLifetime _hostApplicationLifetime; + private readonly IAuthUnitOfWorkFactory _authUnitOfWorkFactory; - public string ServerType { get; } = "Authentication"; + public string ServerType { get; } = "Authentication"; - public const int MainLoopTime = 100; // Milliseconds + public const int MainLoopTime = 100; // Milliseconds - public Config Config { get; private set; } - public LengthedSocket AuthCommunicator { get; private set; } - public LengthedSocket ListenerSocket { get; private set; } - public List Clients { get; } = new List(); - - public List ServerList { get; } = new List(); - public MainLoop Loop { get; } - public Timer Timer { get; } - public bool Running => Loop != null && Loop.Running; + public Config Config { get; private set; } + public Communicator Communicator { get; } = new(CommunicatorType.Server); + public AsyncLengthedSocket ListenerSocket { get; } = new(AsyncLengthedSocket.HeaderSizeType.Word); + public List Clients { get; } = new(); + public List ServerList { get; } = new(); + public MainLoop Loop { get; } + public Timer Timer { get; } + public bool Running => Loop != null && Loop.Running; - private readonly List _clientsToRemove = new List(); - private List GameServerQueue { get; } = new List(); - private Dictionary GameServers { get; } = new Dictionary(); + private readonly List _clientsToRemove = new(); - public Server(IHostApplicationLifetime hostApplicationLifetime, IAuthUnitOfWorkFactory authUnitOfWorkFactory) - { - _hostApplicationLifetime = hostApplicationLifetime; - _authUnitOfWorkFactory = authUnitOfWorkFactory; + public Server(IHostApplicationLifetime hostApplicationLifetime, IAuthUnitOfWorkFactory authUnitOfWorkFactory) + { + _hostApplicationLifetime = hostApplicationLifetime; + _authUnitOfWorkFactory = authUnitOfWorkFactory; - Configuration.OnLoad += ConfigLoaded; - Configuration.OnReLoad += ConfigReLoaded; - Configuration.Load(); + Configuration.OnLoad += ConfigLoaded; + Configuration.OnReLoad += ConfigReLoaded; + Configuration.Load(); - Loop = new MainLoop(this, MainLoopTime); - Timer = new Timer(); + if (Config is null) + throw new Exception("Unable to load configuration!"); - SetupServerList(); + Loop = new MainLoop(this, MainLoopTime); + Timer = new Timer(); - LengthedSocket.InitializeEventArgsPool(Config.SocketAsyncConfig.MaxClients * Config.SocketAsyncConfig.ConcurrentOperationsByClient); + SetupServerList(); - BufferManager.Initialize(Config.SocketAsyncConfig.BufferSize, Config.SocketAsyncConfig.MaxClients, Config.SocketAsyncConfig.ConcurrentOperationsByClient); - - CommandProcessor.RegisterCommand("exit", ProcessExitCommand); - CommandProcessor.RegisterCommand("reload", ProcessReloadCommand); - CommandProcessor.RegisterCommand("create", ProcessCreateCommand); - } + RegisterConsoleCommands(); - ~Server() - { - Shutdown(); - } + Logger.WriteLog(LogType.Initialize, "The Auth server has been initialized!"); + } - #region Configuration - private static void ConfigReLoaded() - { - Logger.WriteLog(LogType.Initialize, "Config file reloaded by external change!"); + ~Server() + { + Shutdown(); + } - // Totally reload the configuration, because it's automatic reload case can only handle one reload. Our code's bug? - Configuration.Load(); - } + #region Configuration + private static void ConfigReLoaded() + { + Logger.WriteLog(LogType.Initialize, "Config file reloaded by external change!"); - private void ConfigLoaded() - { - var oldConfig = Config; + // Totally reload the configuration, because it's automatic reload case can only handle one reload. Our code's bug? + Configuration.Load(); + } - Config = new Config(); - Configuration.Bind(Config); + private void ConfigLoaded() + { + var oldConfig = Config; - Logger.UpdateConfig(Config.LoggerConfig); + Config = new Config(); + Configuration.Bind(Config); - // Handle reloading the config and updating the list visibility - if (oldConfig == null || oldConfig.AuthListType == Config.AuthListType) - return; + Logger.UpdateConfig(Config.LoggerConfig); - lock (ServerList) - { - ServerList.Clear(); - SetupServerList(); - GenerateServerList(); - } - } - #endregion + // Handle reloading the config and updating the list visibility + if (oldConfig == null || oldConfig.AuthListType == Config.AuthListType) + return; - public void Disconnect(Client client) + lock (ServerList) { - lock (_clientsToRemove) - _clientsToRemove.Add(client); + ServerList.Clear(); + SetupServerList(); + GenerateServerList(); } + } + #endregion - private void SetupServerList() - { - if (Config.AuthListType != AuthListType.All) - return; - - foreach (var s in Config.Servers) - { - if (!byte.TryParse(s.Key, out byte id)) - continue; + public void Disconnect(Client client) + { + lock (_clientsToRemove) + _clientsToRemove.Add(client); + } - ServerList.Add(new ServerInfo - { - AgeLimit = 0, - CurrentPlayers = 0, - GamePort = 0, - Ip = IPAddress.None, - MaxPlayers = 0, - PKFlag = 0, - QueuePort = 0, - ServerId = id, - Status = 0 - }); - } - } + private void SetupServerList() + { + if (Config.AuthListType != AuthListType.All) + return; - #region Socketing - public bool Start() + foreach (var s in Config.Servers) { - // If no config file has been found, these values are 0 by default - if (Config.AuthConfig.Port == 0 || Config.AuthConfig.Backlog == 0) - { - Logger.WriteLog(LogType.Error, "Invalid config values!"); - return false; - } + if (!byte.TryParse(s.Key, out byte id)) + continue; - try - { - ListenerSocket = new LengthedSocket(SizeType.Word); - ListenerSocket.OnError += OnError; - ListenerSocket.OnAccept += OnAccept; - ListenerSocket.Bind(new IPEndPoint(IPAddress.Any, Config.AuthConfig.Port)); - ListenerSocket.Listen(Config.AuthConfig.Backlog); - } - catch (Exception e) + ServerList.Add(new ServerInfo { - Logger.WriteLog(LogType.Error, "Unable to create or start listening on the client socket! Exception:"); - Logger.WriteLog(LogType.Error, e); - - return false; - } - - Loop.Start(); - - if (!SetupCommunicator()) - return false; - - Logger.WriteLog(LogType.Network, "*** Listening for clients on port {0}", Config.AuthConfig.Port); - - ListenerSocket.AcceptAsync(); - - // TODO: Set up timed events (query stuff, internal communication, etc...) - - return true; + AgeLimit = 0, + CurrentPlayers = 0, + GamePort = 0, + Ip = IPAddress.None, + MaxPlayers = 0, + PKFlag = 0, + QueuePort = 0, + ServerId = id, + Status = 0 + }); } + } - private static void OnError(SocketAsyncEventArgs args) + #region Socketing + public bool Start() + { + // Check the server configuration + if (Config.AuthConfig.Port == 0 || Config.AuthConfig.Backlog == 0) { - if (args.LastOperation == SocketAsyncOperation.Accept && args.AcceptSocket != null && - args.AcceptSocket.Connected) - args.AcceptSocket.Shutdown(SocketShutdown.Both); + Logger.WriteLog(LogType.Error, "Invalid config values!"); + return false; } - private void OnAccept(LengthedSocket newSocket) + // Check the communicator configuration + if (Config.CommunicatorConfig.Port == 0 || Config.CommunicatorConfig.Address == null || Config.CommunicatorConfig.Backlog == 0) { - ListenerSocket.AcceptAsync(); - - if (newSocket == null) - return; - - lock (Clients) - Clients.Add(new Client(newSocket, this, _authUnitOfWorkFactory)); + Logger.WriteLog(LogType.Error, "Invalid Communicator config data!"); + return false; } - #endregion - #region Communicator - private bool SetupCommunicator() + // Set up the listener socket + try { - if (Config.CommunicatorConfig.Port == 0 || Config.CommunicatorConfig.Address == null || Config.CommunicatorConfig.Backlog == 0) - { - Logger.WriteLog(LogType.Error, "Invalid Communicator config data! Can't connect!"); - return false; - } - - try - { - AuthCommunicator = new LengthedSocket(SizeType.Word); - AuthCommunicator.OnAccept += OnCommunicatorAccept; - AuthCommunicator.Bind(new IPEndPoint(IPAddress.Parse(Config.CommunicatorConfig.Address), Config.CommunicatorConfig.Port)); - AuthCommunicator.Listen(Config.CommunicatorConfig.Backlog); - } - catch (Exception e) - { - Logger.WriteLog(LogType.Error, "Unable to create or start listening on the communicator socket! Exception:"); - Logger.WriteLog(LogType.Error, e); - - return false; - } + ListenerSocket.OnError += OnError; + ListenerSocket.OnAccept += OnAccept; + ListenerSocket.StartListening(new IPEndPoint(IPAddress.Any, Config.AuthConfig.Port), Config.AuthConfig.Backlog); - AuthCommunicator.AcceptAsync(); - - Timer.Add("ServerInfoUpdate", 1000, true, () => - { - lock (GameServers) - foreach (var server in GameServers) - if ((DateTime.Now - server.Value.LastRequestTime).TotalMilliseconds > 30000) - server.Value.RequestServerInfo(); - }); - - Logger.WriteLog(LogType.Network, $"*** Listening for Game servers on port {Config.CommunicatorConfig.Port}"); - - return true; + Logger.WriteLog(LogType.Network, "*** Listening for clients on port {0}", Config.AuthConfig.Port); } - - private void OnCommunicatorAccept(LengthedSocket socket) + catch (Exception e) { - AuthCommunicator.AcceptAsync(); - - lock (GameServers) - GameServerQueue.Add(new CommunicatorClient(socket, this)); + Logger.WriteLog(LogType.Error, "Unable to create or start listening on the client socket! Exception:"); + Logger.WriteLog(LogType.Error, e); - Logger.WriteLog(LogType.Network, $"A Game server has connected! Remote: {socket.RemoteAddress}"); + return false; } - public bool AuthenticateGameServer(LoginRequestPacket packet, CommunicatorClient client) - { - lock (GameServers) - { - if (GameServers.ContainsKey(packet.ServerId)) - { - DisconnectCommunicator(client); - Logger.WriteLog(LogType.Debug, $"A server tried to connect to an already in use server slot! Remote Address: {client.Socket.RemoteAddress}"); - return false; - } + // Set up communicator + Communicator.OnLoginRequest += AuthenticateGameServer; + Communicator.OnRedirectResponse += RedirectResponse; + Communicator.OnServerInfoResponse += UpdateServerInfo; + Communicator.Start(IPAddress.Parse(Config.CommunicatorConfig.Address), Config.CommunicatorConfig.Port, Config.CommunicatorConfig.Backlog); - if (!Config.Servers.ContainsKey(packet.ServerId.ToString())) - { - DisconnectCommunicator(client); - Logger.WriteLog(LogType.Debug, $"A server tried to connect to a non-defined server slot! Remote Address: {client.Socket.RemoteAddress}"); - return false; - } + Logger.WriteLog(LogType.Network, "*** Listening for gameservers on port {0}", Config.CommunicatorConfig.Port); - if (Config.Servers[packet.ServerId.ToString()] != packet.Password) - { - DisconnectCommunicator(client); - Logger.WriteLog(LogType.Error, $"A server tried to log in with an invalid password! Remote Address: {client.Socket.RemoteAddress}"); - return false; - } + // Add the repeating server info request timed event + Timer.Add("ServerInfoUpdate", 1000, true, () => + { + Communicator.RequestServerInfo(); + }); - GameServerQueue.Remove(client); - GameServers.Add(packet.ServerId, client); + // Start the main loop + Loop.Start(); - Logger.WriteLog(LogType.Network, $"The Game server (Id: {packet.ServerId}, Address: {client.Socket.RemoteAddress}, Public Address: {packet.PublicAddress}) has authenticated! Requesting info..."); + // TODO: Set up timed events (query stuff, internal communication, etc...) - return true; - } - } + return true; + } - public void UpdateServerInfo(CommunicatorClient client, ServerInfoResponsePacket packet) - { - GenerateServerList(); - BroadcastServerList(); - } + private static void OnError() + { + } - public void RedirectResponse(CommunicatorClient client, RedirectResponsePacket packet) - { - Client authClient; - lock (Clients) - authClient = Clients.FirstOrDefault(c => c.AccountEntry.Id == packet.AccountId); + private void OnAccept(AsyncLengthedSocket newSocket) + { + if (newSocket == null) + return; - ServerInfo info; - lock (ServerList) - info = ServerList.FirstOrDefault(i => i.ServerId == client.ServerId); + lock (Clients) + Clients.Add(new Client(newSocket, this, _authUnitOfWorkFactory)); + } + #endregion - if (authClient != null && info != null) - authClient.RedirectionResult(packet.Response, info); + #region Communicator + public bool AuthenticateGameServer(Communicator client, LoginRequestPacket packet) + { + if (Communicator.Clients!.ContainsKey(packet.Data.Id)) + { + Logger.WriteLog(LogType.Debug, $"A server tried to connect to an already in use server slot! Remote Address: {client.Socket.RemoteAddress}"); + return false; } - public void RequestRedirection(Client client, byte serverId) + if (!Config.Servers!.ContainsKey(packet.Data.Id.ToString())) { - lock (GameServers) - if (GameServers.ContainsKey(serverId)) - GameServers[serverId].RequestRedirection(client); + Logger.WriteLog(LogType.Debug, $"A server tried to connect to a non-defined server slot! Remote Address: {client.Socket.RemoteAddress}"); + return false; } - public void DisconnectCommunicator(CommunicatorClient client) + if (Config.Servers[packet.Data.Id.ToString()] != packet.Data.Password) { - if (client == null) - return; + Logger.WriteLog(LogType.Error, $"A server tried to log in with an invalid password! Remote Address: {client.Socket.RemoteAddress}"); + return false; + } - lock (GameServers) - { - GameServerQueue.Remove(client); + Logger.WriteLog(LogType.Communicator, $"The Game server (Id: {packet.Data.Id}, Address: {client.Socket.RemoteAddress}, Public Address: {packet.Data.Address}) has authenticated!"); + return true; + } - if (client.ServerId != 0) - GameServers.Remove(client.ServerId); + public void UpdateServerInfo() + { + GenerateServerList(); + BroadcastServerList(); + } - GenerateServerList(); - } + public void RedirectResponse(Communicator client, RedirectResponsePacket packet) + { + Client authClient; + lock (Clients) + authClient = Clients.FirstOrDefault(c => c.AccountEntry.Id == packet.AccountId); - Timer.Add($"Disconnect-comm-{DateTime.Now.Ticks}", 1000, false, () => - { - client.Socket?.Close(); - }); + ServerInfo info; + lock (ServerList) + info = ServerList.FirstOrDefault(i => i.ServerId == client.ServerData.Id); - Logger.WriteLog(LogType.Network, $"The game server (Id: {client.ServerId}, Address: {client.Socket.RemoteAddress}) has disconnected!"); - } + if (authClient != null && info != null) + authClient.RedirectionResult(packet.Result, info); + } - private void GenerateServerList() + public void RequestRedirection(Client client, byte serverId) + { + Communicator.RequestRedirection(serverId, new() { - lock (ServerList) - { - var toRemove = new List(); + AccountId = client.AccountEntry.Id, + Email = client.AccountEntry.Email, + OneTimeKey = client.OneTimeKey, + Username = client.AccountEntry.Username + }); + } - lock (GameServers) - { - foreach (var sInfo in ServerList) - { - if (GameServers.TryGetValue(sInfo.ServerId, out CommunicatorClient client)) - { - sInfo.Setup(client.PublicAddress, client.QueuePort, client.GamePort, client.AgeLimit, client.PKFlag, client.CurrentPlayers, client.MaxPlayers); - continue; - } - - if (Config.AuthListType == AuthListType.Online) - { - toRemove.Add(sInfo); - continue; - } - - sInfo.Clear(); - } - - foreach (var server in GameServers) - { - if (ServerList.All(s => s.ServerId != server.Key)) - { - ServerList.Add(new ServerInfo - { - AgeLimit = server.Value.AgeLimit, - PKFlag = server.Value.PKFlag, - CurrentPlayers = server.Value.CurrentPlayers, - MaxPlayers = server.Value.MaxPlayers, - QueuePort = server.Value.QueuePort, - GamePort = server.Value.GamePort, - Ip = server.Value.PublicAddress, - ServerId = server.Key, - Status = 1 - }); - } - } - } + private void GenerateServerList() + { + lock (ServerList) + { + var toRemove = new List(); - if (toRemove.Count == 0) - return; + ServerList.Clear(); - foreach (var rem in toRemove) - ServerList.Remove(rem); + foreach (var client in Communicator.Clients!) + { + ServerList.Add(new ServerInfo + { + AgeLimit = client.Value.ServerInfo!.AgeLimit, + PKFlag = client.Value.ServerInfo.PKFlag, + CurrentPlayers = client.Value.ServerInfo.CurrentPlayers, + MaxPlayers = client.Value.ServerInfo.MaxPlayers, + GamePort = client.Value.ServerInfo.GamePort, + QueuePort = client.Value.ServerInfo.QueuePort, + Ip = client.Value.ServerData!.Address, + ServerId = client.Key, + Status = 1 + }); } } - #endregion + } + #endregion - public void Shutdown() - { - ListenerSocket?.Close(); - ListenerSocket = null; + public void Shutdown() + { + ListenerSocket.Close(); - Loop.Stop(); - } + Loop.Stop(); - public void MainLoop(long delta) - { - Timer.Update(delta); + _hostApplicationLifetime.StopApplication(); + } - if (Clients.Count == 0) - return; + public void MainLoop(long delta) + { + Communicator.Update(); - lock (Clients) - { - foreach (var c in Clients) - c.Update(delta); + Timer.Update(delta); - if (_clientsToRemove.Count > 0) + if (Clients.Count == 0) + return; + + lock (Clients) + { + foreach (var c in Clients) + c.Update(delta); + + if (_clientsToRemove.Count > 0) + { + lock (_clientsToRemove) { - lock (_clientsToRemove) - { - foreach (var client in _clientsToRemove) - Clients.Remove(client); + foreach (var client in _clientsToRemove) + Clients.Remove(client); - _clientsToRemove.Clear(); - } + _clientsToRemove.Clear(); } } } + } - public void BroadcastServerList() - { - lock (Clients) - foreach (var c in Clients) - if (c.State == ClientState.ServerList) - c.SendPacket(new SendServerListExtPacket(ServerList, c.AccountEntry.LastServerId)); - } + public void BroadcastServerList() + { + lock (Clients) + foreach (var c in Clients) + if (c.State == ClientState.ServerList) + c.SendPacket(new SendServerListExtPacket(ServerList, c.AccountEntry.LastServerId)); + } - #region Commands - private void ProcessExitCommand(string[] parts) - { - var minutes = 0; + #region Commands + private void RegisterConsoleCommands() + { + CommandProcessor.RegisterCommand("exit", ProcessExitCommand); + CommandProcessor.RegisterCommand("reload", ProcessReloadCommand); + CommandProcessor.RegisterCommand("create", ProcessCreateCommand); + } - if (parts.Length > 1) - minutes = int.Parse(parts[1]); + private void ProcessExitCommand(string[] parts) + { + var minutes = 0; - Timer.Add("exit", minutes * 60000, false, () => - { - Shutdown(); - _hostApplicationLifetime.StopApplication(); - }); + if (parts.Length > 1) + minutes = int.Parse(parts[1]); - Logger.WriteLog(LogType.Command, $"Exiting the server in {minutes} minute(s)."); - } + Timer.Add("exit", minutes * 60000, false, Shutdown); - private static void ProcessReloadCommand(string[] parts) - { - if (parts.Length > 1 && parts[1] == "config") - { - Configuration.Load(); - return; - } + Logger.WriteLog(LogType.Command, $"Exiting the server in {minutes} minute(s)."); + } - Logger.WriteLog(LogType.Command, "Invalid reload command!"); + private static void ProcessReloadCommand(string[] parts) + { + if (parts.Length > 1 && parts[1] == "config") + { + Configuration.Load(); + return; } - private void ProcessCreateCommand(string[] parts) + Logger.WriteLog(LogType.Command, "Invalid reload command!"); + } + + private void ProcessCreateCommand(string[] parts) + { + if (parts.Length < 4) { - if (parts.Length < 4) - { - Logger.WriteLog(LogType.Command, "Invalid create account command! Usage: create "); - return; - } + Logger.WriteLog(LogType.Command, "Invalid create account command! Usage: create "); + return; + } - var email = parts[1]; - var userName = parts[2]; - var password = parts[3]; + var email = parts[1]; + var userName = parts[2]; + var password = parts[3]; - try - { - using var unitOfWork = _authUnitOfWorkFactory.Create(); - unitOfWork.AuthAccountRepository.Create(email, userName, password); - unitOfWork.Complete(); + try + { + using var unitOfWork = _authUnitOfWorkFactory.Create(); + unitOfWork.AuthAccountRepository.Create(email, userName, password); + unitOfWork.Complete(); - Logger.WriteLog(LogType.Command, $"Created account: {parts[2]}! (Password: {parts[3]})"); - } - catch - { - Logger.WriteLog(LogType.Error, "Username or email is already taken!"); - } + Logger.WriteLog(LogType.Command, $"Created account: {parts[2]}! (Password: {parts[3]})"); } - - /*private void ProcessRestartCommand(string[] parts) + catch { - // TODO: delayed restart, with contacting globals, so they can warn players not to leave the server, or they won't be able to reconnect + Logger.WriteLog(LogType.Error, "Username or email is already taken!"); } + } - private void ProcessShutdownCommand(string[] parts) - { - // TODO: delayed shutdown, with contacting globals, so they can warn players not to leave the server, or they won't be able to reconnect - // TODO: add timer to report the remaining time until shutdown? - // TODO: add timer to contact global servers to tell them periodically that we're getting shut down? - }*/ - #endregion + /*private void ProcessRestartCommand(string[] parts) + { + // TODO: delayed restart, with contacting globals, so they can warn players not to leave the server, or they won't be able to reconnect } + + private void ProcessShutdownCommand(string[] parts) + { + // TODO: delayed shutdown, with contacting globals, so they can warn players not to leave the server, or they won't be able to reconnect + // TODO: add timer to report the remaining time until shutdown? + // TODO: add timer to contact global servers to tell them periodically that we're getting shut down? + }*/ + #endregion } diff --git a/src/Rasa.Auth/AuthHost.cs b/src/Rasa.Auth/AuthHost.cs index 51c8e22d..8430a796 100644 --- a/src/Rasa.Auth/AuthHost.cs +++ b/src/Rasa.Auth/AuthHost.cs @@ -1,11 +1,10 @@ -namespace Rasa -{ - using Hosting; +namespace Rasa; + +using Rasa.Hosting; - public class AuthHost : RasaHost +public class AuthHost : RasaHost +{ + public AuthHost(IRasaServer server) : base(server) { - public AuthHost(IRasaServer server) : base(server) - { - } } } \ No newline at end of file diff --git a/src/Rasa.Auth/AuthProgram.cs b/src/Rasa.Auth/AuthProgram.cs index 16f5c10d..5fdfc3d3 100644 --- a/src/Rasa.Auth/AuthProgram.cs +++ b/src/Rasa.Auth/AuthProgram.cs @@ -5,84 +5,85 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; -namespace Rasa +namespace Rasa; + +using Rasa.Auth; +using Rasa.Binding; +using Rasa.Configuration; +using Rasa.Context.Auth; +using Rasa.Hosting; +using Rasa.Initialization; +using Rasa.Repositories.Auth; +using Rasa.Repositories.Auth.Account; +using Rasa.Repositories.UnitOfWork; +using Rasa.Services.Random; + +public class AuthProgram { - using Auth; - using Binding; - using Configuration; - using Context.Auth; - using Hosting; - using Initialization; - using Repositories.Auth; - using Repositories.Auth.Account; - using Repositories.UnitOfWork; - using Services.Random; - - public class AuthProgram + public static async Task Main(string[] args) { - public static async Task Main(string[] args) + var hostBuilder = new HostBuilder() + .ConfigureAppConfiguration(ConfigureApp) + .ConfigureServices(ConfigureServices); + var host = hostBuilder.Build(); + + try { - var hostBuilder = new HostBuilder() - .ConfigureAppConfiguration(ConfigureApp) - .ConfigureServices(ConfigureServices); - var host = hostBuilder.Build(); - - try - { - host.Services.GetService().Execute(); - await host.RunAsync(); - return 0; - } - catch (Exception e) - { - Logger.WriteLog(LogType.Error, "Auth server ended unexpectedly. Exception:"); - Logger.WriteLog(LogType.Error, e); - return e.HResult; - } + host.Services.GetService().Execute(); + await host.RunAsync(); + return 0; } - - private static void ConfigureApp(HostBuilderContext context, IConfigurationBuilder configurationBuilder) + catch (Exception e) { - configurationBuilder - .AddJsonFile("databasesettings.json", false, false) - .AddJsonFile("databasesettings.env.json", true, false); + Logger.WriteLog(LogType.Error, "Auth server ended unexpectedly. Exception:"); + Logger.WriteLog(LogType.Error, e); + return e.HResult; } + } - private static void ConfigureServices(HostBuilderContext context, IServiceCollection services) - { - services.AddHostedService(); - services.AddSingleton(); + private static void ConfigureApp(HostBuilderContext context, IConfigurationBuilder configurationBuilder) + { + configurationBuilder + .AddJsonFile("databasesettings.json", false, false) + .AddJsonFile("databasesettings.env.json", true, false); + } + + private static void ConfigureServices(HostBuilderContext context, IServiceCollection services) + { + services.AddHostedService(); + services.AddSingleton(); - services.AddSingleton(); + services.AddSingleton(); - AddDatabase(context, services); + AddDatabase(context, services); - services.AddSingleton(); - services.AddScoped(); - services.AddScoped(); - services.AddSingleton(); - } + services.AddSingleton(); + services.AddScoped(); + services.AddScoped(); + services.AddSingleton(); + } + + private static void AddDatabase(HostBuilderContext context, IServiceCollection services) + { + var databaseConfigSection = context.Configuration + .GetSection("Databases"); - private static void AddDatabase(HostBuilderContext context, IServiceCollection services) + var databaseProvider = services.AddDatabaseProviderSpecificBindings(databaseConfigSection); + + switch (databaseProvider) { - var databaseConfigSection = context.Configuration - .GetSection("Databases"); - - var databaseProvider = services.AddDatabaseProviderSpecificBindings(databaseConfigSection); - - switch (databaseProvider) - { - - case DatabaseProvider.MySql: - services.AddDbContext(); - break; - case DatabaseProvider.Sqlite: - services.AddDbContext(); - services.AddSingleton(ctx => ctx.GetService()); - break; - default: - throw new ArgumentOutOfRangeException(); - } + + case DatabaseProvider.MySql: + services.AddDbContext(); + break; + + case DatabaseProvider.Sqlite: + services.AddDbContext(); + services.AddSingleton(ctx => ctx.GetService()); + break; + + default: + throw new Exception("Invalid database provider specified!"); } } } diff --git a/src/Rasa.Auth/Config/AuthConfig.cs b/src/Rasa.Auth/Config/AuthConfig.cs index 13bd2302..607cbe8b 100644 --- a/src/Rasa.Auth/Config/AuthConfig.cs +++ b/src/Rasa.Auth/Config/AuthConfig.cs @@ -1,9 +1,8 @@ -namespace Rasa.Config +namespace Rasa.Config; + +public class AuthConfig { - public class AuthConfig - { - public int Port { get; set; } - public int Backlog { get; set; } - public int ClientTimeout { get; set; } - } + public int Port { get; set; } + public int Backlog { get; set; } + public int ClientTimeout { get; set; } } diff --git a/src/Rasa.Auth/Config/CommunicatorConfig.cs b/src/Rasa.Auth/Config/CommunicatorConfig.cs index e57f3e9b..7b34320b 100644 --- a/src/Rasa.Auth/Config/CommunicatorConfig.cs +++ b/src/Rasa.Auth/Config/CommunicatorConfig.cs @@ -1,9 +1,8 @@ -namespace Rasa.Config +namespace Rasa.Config; + +public class CommunicatorConfig { - public class CommunicatorConfig - { - public int Port { get; set; } - public int Backlog { get; set; } - public string Address { get; set; } - } + public int Port { get; set; } + public int Backlog { get; set; } + public string Address { get; set; } } diff --git a/src/Rasa.Auth/Config/Config.cs b/src/Rasa.Auth/Config/Config.cs index bb44d79e..d7f4bcb2 100644 --- a/src/Rasa.Auth/Config/Config.cs +++ b/src/Rasa.Auth/Config/Config.cs @@ -1,16 +1,15 @@ using System.Collections.Generic; -namespace Rasa.Config -{ - using Data; +namespace Rasa.Config; + +using Rasa.Data; - public class Config - { - public AuthListType AuthListType { get; set; } - public Dictionary Servers { get; set; } - public SocketAsyncConfig SocketAsyncConfig { get; set; } - public AuthConfig AuthConfig { get; set; } - public CommunicatorConfig CommunicatorConfig { get; set; } - public Logger.LoggerConfig LoggerConfig { get; set; } - } +public class Config +{ + public AuthListType AuthListType { get; set; } + public Dictionary Servers { get; set; } + public SocketAsyncConfig SocketAsyncConfig { get; set; } + public AuthConfig AuthConfig { get; set; } + public CommunicatorConfig CommunicatorConfig { get; set; } + public Logger.LoggerConfig LoggerConfig { get; set; } } diff --git a/src/Rasa.Auth/Data/AuthListType.cs b/src/Rasa.Auth/Data/AuthListType.cs index ae229946..5280a23e 100644 --- a/src/Rasa.Auth/Data/AuthListType.cs +++ b/src/Rasa.Auth/Data/AuthListType.cs @@ -1,9 +1,8 @@ -namespace Rasa.Data +namespace Rasa.Data; + +public enum AuthListType { - public enum AuthListType - { - All = 0, - Online = 1, - OnceOnline = 2 - } + All = 0, + Online = 1, + OnceOnline = 2 } diff --git a/src/Rasa.Auth/Data/ClientOpcode.cs b/src/Rasa.Auth/Data/ClientOpcode.cs index a4fb84f4..a342fbd7 100644 --- a/src/Rasa.Auth/Data/ClientOpcode.cs +++ b/src/Rasa.Auth/Data/ClientOpcode.cs @@ -1,11 +1,10 @@ -namespace Rasa.Data +namespace Rasa.Data; + +public enum ClientOpcode : byte { - public enum ClientOpcode : byte - { - Login = 0x00, - AboutToPlay = 0x02, - Logout = 0x03, - ServerListExt = 0x05, - SCCheck = 0x06, - } + Login = 0x00, + AboutToPlay = 0x02, + Logout = 0x03, + ServerListExt = 0x05, + SCCheck = 0x06, } diff --git a/src/Rasa.Auth/Data/ClientState.cs b/src/Rasa.Auth/Data/ClientState.cs index 863abc10..5d733971 100644 --- a/src/Rasa.Auth/Data/ClientState.cs +++ b/src/Rasa.Auth/Data/ClientState.cs @@ -1,13 +1,12 @@ -namespace Rasa.Data +namespace Rasa.Data; + +public enum ClientState : byte { - public enum ClientState : byte - { - None = 0, - Connected = 1, - LoggedIn = 2, - ServerList = 3, - Queued = 4, - Redirecting = 5, - Disconnected = 6 - } + None = 0, + Connected = 1, + LoggedIn = 2, + ServerList = 3, + Queued = 4, + Redirecting = 5, + Disconnected = 6 } diff --git a/src/Rasa.Auth/Data/FailReason.cs b/src/Rasa.Auth/Data/FailReason.cs index 3cba4ea6..e991bdfc 100644 --- a/src/Rasa.Auth/Data/FailReason.cs +++ b/src/Rasa.Auth/Data/FailReason.cs @@ -1,17 +1,16 @@ -namespace Rasa.Data +namespace Rasa.Data; + +public enum FailReason : byte { - public enum FailReason : byte - { - UnexpectedError = 0, - UserNameOrPassword = 2, - SSNInformationUnavailable = 5, - NoAvailableServers = 6, - AlreadyLoggedIn = 7, - ServerIsDown = 8, - Kicked = 11, - AgeRestricted = 12, - ServerIsFull = 15, - MustChangePassword = 17, - OutOfTime = 18 - } + UnexpectedError = 0, + UserNameOrPassword = 2, + SSNInformationUnavailable = 5, + NoAvailableServers = 6, + AlreadyLoggedIn = 7, + ServerIsDown = 8, + Kicked = 11, + AgeRestricted = 12, + ServerIsFull = 15, + MustChangePassword = 17, + OutOfTime = 18 } diff --git a/src/Rasa.Auth/Data/ServerOpcode.cs b/src/Rasa.Auth/Data/ServerOpcode.cs index 3b615d30..4bf82140 100644 --- a/src/Rasa.Auth/Data/ServerOpcode.cs +++ b/src/Rasa.Auth/Data/ServerOpcode.cs @@ -1,20 +1,19 @@ -namespace Rasa.Data +namespace Rasa.Data; + +public enum ServerOpcode : byte { - public enum ServerOpcode : byte - { - ProtocolVersion = 0x00, - LoginFail = 0x01, - BlockedAccount = 0x02, - LoginOk = 0x03, - SendServerListExt = 0x04, - SendServerListFail = 0x05, - PlayFail = 0x06, - PlayOk = 0x07, - AccountKicked = 0x08, - BlockedAccountWithMessage = 0x09, - SCCheckReq = 0x0A, // null - Unknown1 = 0x0B, // null, or in different vTable - HandOffToQueue = 0x0C, - HandoffToGame = 0x0E - } + ProtocolVersion = 0x00, + LoginFail = 0x01, + BlockedAccount = 0x02, + LoginOk = 0x03, + SendServerListExt = 0x04, + SendServerListFail = 0x05, + PlayFail = 0x06, + PlayOk = 0x07, + AccountKicked = 0x08, + BlockedAccountWithMessage = 0x09, + SCCheckReq = 0x0A, // null + Unknown1 = 0x0B, // null, or in different vTable + HandOffToQueue = 0x0C, + HandoffToGame = 0x0E } diff --git a/src/Rasa.Auth/Packets/Auth/Client/AboutToPlayPacket.cs b/src/Rasa.Auth/Packets/Auth/Client/AboutToPlayPacket.cs index e66685a8..84720912 100644 --- a/src/Rasa.Auth/Packets/Auth/Client/AboutToPlayPacket.cs +++ b/src/Rasa.Auth/Packets/Auth/Client/AboutToPlayPacket.cs @@ -1,35 +1,34 @@ using System.IO; -namespace Rasa.Packets.Auth.Client -{ - using Data; +namespace Rasa.Packets.Auth.Client; - public class AboutToPlayPacket : IOpcodedPacket - { - public uint SessionId1 { get; set; } - public uint SessionId2 { get; set; } - public byte ServerId { get; set; } +using Rasa.Data; - public ClientOpcode Opcode { get; } = ClientOpcode.AboutToPlay; +public class AboutToPlayPacket : IOpcodedPacket +{ + public uint SessionId1 { get; set; } + public uint SessionId2 { get; set; } + public byte ServerId { get; set; } - public void Read(BinaryReader reader) - { - SessionId1 = reader.ReadUInt32(); - SessionId2 = reader.ReadUInt32(); - ServerId = reader.ReadByte(); - } + public ClientOpcode Opcode { get; } = ClientOpcode.AboutToPlay; - public void Write(BinaryWriter writer) - { - writer.Write((byte) Opcode); - writer.Write(SessionId1); - writer.Write(SessionId2); - writer.Write(ServerId); - } + public void Read(BinaryReader reader) + { + SessionId1 = reader.ReadUInt32(); + SessionId2 = reader.ReadUInt32(); + ServerId = reader.ReadByte(); + } - public override string ToString() - { - return $"AboutToPlayPacket({SessionId1}, {SessionId2}, {ServerId})"; - } + public void Write(BinaryWriter writer) + { + writer.Write((byte) Opcode); + writer.Write(SessionId1); + writer.Write(SessionId2); + writer.Write(ServerId); + } + + public override string ToString() + { + return $"AboutToPlayPacket({SessionId1}, {SessionId2}, {ServerId})"; } } diff --git a/src/Rasa.Auth/Packets/Auth/Client/LoginPacket.cs b/src/Rasa.Auth/Packets/Auth/Client/LoginPacket.cs index aaa73797..da63e046 100644 --- a/src/Rasa.Auth/Packets/Auth/Client/LoginPacket.cs +++ b/src/Rasa.Auth/Packets/Auth/Client/LoginPacket.cs @@ -5,76 +5,75 @@ using Org.BouncyCastle.Crypto.Engines; using Org.BouncyCastle.Crypto.Parameters; -namespace Rasa.Packets.Auth.Client +namespace Rasa.Packets.Auth.Client; + +using Rasa.Data; + +public class LoginPacket : IOpcodedPacket { - using Data; + private static readonly DesEngine Decrypter; + //private static readonly DesEngine Encrypter; + + public string UserName { get; set; } + public string Password { get; set; } + public uint GameId { get; set; } + public ushort CDKey { get; set; } + + public ClientOpcode Opcode { get; } = ClientOpcode.Login; + + static LoginPacket() + { + var key = new byte[] { 0x54, 0x45, 0x53, 0x54, 0x00, 0x00, 0x00, 0x00 }; + + Decrypter = new DesEngine(); + Decrypter.Init(false, new DesParameters(key)); + + //Encrypter = new DesEngine(); + //Encrypter.Init(true, new DesParameters(key)); + } + + public void Read(BinaryReader reader) + { + var buff = reader.ReadBytes(30); + + for (var i = 0; i < 24; i += 8) + Decrypter.ProcessBlock(buff, i, buff, i); + + UserName = Encoding.UTF8.GetString(buff, 0, FirstZeroIndex(buff, 0, 14)); + Password = Encoding.UTF8.GetString(buff, 14, FirstZeroIndex(buff, 14, 16)); + GameId = reader.ReadUInt32(); + CDKey = reader.ReadUInt16(); + } + + public void Write(BinaryWriter writer) + { + var data = new byte[30]; + var unBuf = Encoding.UTF8.GetBytes(UserName); + var pwBuf = Encoding.UTF8.GetBytes(Password); + + Array.Copy(unBuf, 0, data, 0, UserName.Length >= 14 ? 14 : UserName.Length); + Array.Copy(pwBuf, 0, data, 14, Password.Length >= 16 ? 16 : Password.Length); + + //for (var i = 0; i < 24; i += 8) + //Encrypter.ProcessBlock(data, i, data, i); + + writer.Write((byte) Opcode); + writer.Write(data); + writer.Write(GameId); + writer.Write(CDKey); + } + + private static int FirstZeroIndex(byte[] data, int off, int length) + { + for (var i = 0; i < length; ++i) + if (data[off + i] == 0) + return i; + + return length; + } - public class LoginPacket : IOpcodedPacket + public override string ToString() { - private static readonly DesEngine Decrypter; - //private static readonly DesEngine Encrypter; - - public string UserName { get; set; } - public string Password { get; set; } - public uint GameId { get; set; } - public ushort CDKey { get; set; } - - public ClientOpcode Opcode { get; } = ClientOpcode.Login; - - static LoginPacket() - { - var key = new byte[] { 0x54, 0x45, 0x53, 0x54, 0x00, 0x00, 0x00, 0x00 }; - - Decrypter = new DesEngine(); - Decrypter.Init(false, new DesParameters(key)); - - //Encrypter = new DesEngine(); - //Encrypter.Init(true, new DesParameters(key)); - } - - public void Read(BinaryReader reader) - { - var buff = reader.ReadBytes(30); - - for (var i = 0; i < 24; i += 8) - Decrypter.ProcessBlock(buff, i, buff, i); - - UserName = Encoding.UTF8.GetString(buff, 0, FirstZeroIndex(buff, 0, 14)); - Password = Encoding.UTF8.GetString(buff, 14, FirstZeroIndex(buff, 14, 16)); - GameId = reader.ReadUInt32(); - CDKey = reader.ReadUInt16(); - } - - public void Write(BinaryWriter writer) - { - var data = new byte[30]; - var unBuf = Encoding.UTF8.GetBytes(UserName); - var pwBuf = Encoding.UTF8.GetBytes(Password); - - Array.Copy(unBuf, 0, data, 0, UserName.Length >= 14 ? 14 : UserName.Length); - Array.Copy(pwBuf, 0, data, 14, Password.Length >= 16 ? 16 : Password.Length); - - //for (var i = 0; i < 24; i += 8) - //Encrypter.ProcessBlock(data, i, data, i); - - writer.Write((byte) Opcode); - writer.Write(data); - writer.Write(GameId); - writer.Write(CDKey); - } - - private static int FirstZeroIndex(byte[] data, int off, int length) - { - for (var i = 0; i < length; ++i) - if (data[off + i] == 0) - return i; - - return length; - } - - public override string ToString() - { - return $"LoginPacket(\"{UserName}\", \"{Password}\", {GameId}, {CDKey})"; - } + return $"LoginPacket(\"{UserName}\", \"{Password}\", {GameId}, {CDKey})"; } } diff --git a/src/Rasa.Auth/Packets/Auth/Client/LogoutPacket.cs b/src/Rasa.Auth/Packets/Auth/Client/LogoutPacket.cs index da1a2ae7..21e9a74a 100644 --- a/src/Rasa.Auth/Packets/Auth/Client/LogoutPacket.cs +++ b/src/Rasa.Auth/Packets/Auth/Client/LogoutPacket.cs @@ -1,32 +1,31 @@ using System.IO; -namespace Rasa.Packets.Auth.Client -{ - using Data; +namespace Rasa.Packets.Auth.Client; - public class LogoutPacket : IOpcodedPacket - { - public uint SessionId1 { get; set; } - public uint SessionId2 { get; set; } +using Rasa.Data; - public ClientOpcode Opcode { get; } = ClientOpcode.Logout; +public class LogoutPacket : IOpcodedPacket +{ + public uint SessionId1 { get; set; } + public uint SessionId2 { get; set; } - public void Read(BinaryReader reader) - { - SessionId1 = reader.ReadUInt32(); - SessionId2 = reader.ReadUInt32(); - } + public ClientOpcode Opcode { get; } = ClientOpcode.Logout; - public void Write(BinaryWriter writer) - { - writer.Write((byte) Opcode); - writer.Write(SessionId1); - writer.Write(SessionId2); - } + public void Read(BinaryReader reader) + { + SessionId1 = reader.ReadUInt32(); + SessionId2 = reader.ReadUInt32(); + } - public override string ToString() - { - return $"LogoutPacket({SessionId1}, {SessionId2})"; - } + public void Write(BinaryWriter writer) + { + writer.Write((byte) Opcode); + writer.Write(SessionId1); + writer.Write(SessionId2); + } + + public override string ToString() + { + return $"LogoutPacket({SessionId1}, {SessionId2})"; } } diff --git a/src/Rasa.Auth/Packets/Auth/Client/SCCheckPacket.cs b/src/Rasa.Auth/Packets/Auth/Client/SCCheckPacket.cs index 55181197..4c3b5df0 100644 --- a/src/Rasa.Auth/Packets/Auth/Client/SCCheckPacket.cs +++ b/src/Rasa.Auth/Packets/Auth/Client/SCCheckPacket.cs @@ -1,32 +1,31 @@ using System.IO; -namespace Rasa.Packets.Auth.Client -{ - using Data; +namespace Rasa.Packets.Auth.Client; - public class SCCheckPacket : IOpcodedPacket - { - public uint UserId { get; set; } - public uint CardValue { get; set; } +using Rasa.Data; - public ClientOpcode Opcode { get; } = ClientOpcode.SCCheck; +public class SCCheckPacket : IOpcodedPacket +{ + public uint UserId { get; set; } + public uint CardValue { get; set; } - public void Read(BinaryReader reader) - { - UserId = reader.ReadUInt32(); - CardValue = reader.ReadUInt32(); - } + public ClientOpcode Opcode { get; } = ClientOpcode.SCCheck; - public void Write(BinaryWriter writer) - { - writer.Write((byte) Opcode); - writer.Write(UserId); - writer.Write(CardValue); - } + public void Read(BinaryReader reader) + { + UserId = reader.ReadUInt32(); + CardValue = reader.ReadUInt32(); + } - public override string ToString() - { - return $"SCCheckPacket({UserId}, {CardValue})"; - } + public void Write(BinaryWriter writer) + { + writer.Write((byte) Opcode); + writer.Write(UserId); + writer.Write(CardValue); + } + + public override string ToString() + { + return $"SCCheckPacket({UserId}, {CardValue})"; } } diff --git a/src/Rasa.Auth/Packets/Auth/Client/ServerListExtPacket.cs b/src/Rasa.Auth/Packets/Auth/Client/ServerListExtPacket.cs index 847d09d3..738b147a 100644 --- a/src/Rasa.Auth/Packets/Auth/Client/ServerListExtPacket.cs +++ b/src/Rasa.Auth/Packets/Auth/Client/ServerListExtPacket.cs @@ -1,35 +1,34 @@ using System.IO; -namespace Rasa.Packets.Auth.Client -{ - using Data; +namespace Rasa.Packets.Auth.Client; - public class ServerListExtPacket : IOpcodedPacket - { - public uint SessionId1 { get; set; } - public uint SessionId2 { get; set; } - public byte ListKind { get; set; } +using Rasa.Data; - public ClientOpcode Opcode { get; } = ClientOpcode.ServerListExt; +public class ServerListExtPacket : IOpcodedPacket +{ + public uint SessionId1 { get; set; } + public uint SessionId2 { get; set; } + public byte ListKind { get; set; } - public void Read(BinaryReader reader) - { - SessionId1 = reader.ReadUInt32(); - SessionId2 = reader.ReadUInt32(); - ListKind = reader.ReadByte(); - } + public ClientOpcode Opcode { get; } = ClientOpcode.ServerListExt; - public void Write(BinaryWriter writer) - { - writer.Write((byte) Opcode); - writer.Write(SessionId1); - writer.Write(SessionId2); - writer.Write(ListKind); - } + public void Read(BinaryReader reader) + { + SessionId1 = reader.ReadUInt32(); + SessionId2 = reader.ReadUInt32(); + ListKind = reader.ReadByte(); + } - public override string ToString() - { - return $"ServerListExtPacket({SessionId1}, {SessionId2}, {ListKind})"; - } + public void Write(BinaryWriter writer) + { + writer.Write((byte) Opcode); + writer.Write(SessionId1); + writer.Write(SessionId2); + writer.Write(ListKind); + } + + public override string ToString() + { + return $"ServerListExtPacket({SessionId1}, {SessionId2}, {ListKind})"; } } diff --git a/src/Rasa.Auth/Packets/Auth/Server/AccountKickedPacket.cs b/src/Rasa.Auth/Packets/Auth/Server/AccountKickedPacket.cs index 58e3e872..7d3f9137 100644 --- a/src/Rasa.Auth/Packets/Auth/Server/AccountKickedPacket.cs +++ b/src/Rasa.Auth/Packets/Auth/Server/AccountKickedPacket.cs @@ -1,34 +1,33 @@ using System.IO; -namespace Rasa.Packets.Auth.Server +namespace Rasa.Packets.Auth.Server; + +using Rasa.Data; + +public class AccountKickedPacket : IOpcodedPacket { - using Data; + public byte ReasonCode { get; set; } + + public ServerOpcode Opcode { get; } = ServerOpcode.AccountKicked; + + public AccountKickedPacket(byte reasonCode) + { + ReasonCode = reasonCode; + } + + public void Read(BinaryReader reader) + { + ReasonCode = reader.ReadByte(); + } + + public void Write(BinaryWriter writer) + { + writer.Write((byte) Opcode); + writer.Write(ReasonCode); + } - public class AccountKickedPacket : IOpcodedPacket + public override string ToString() { - public byte ReasonCode { get; set; } - - public ServerOpcode Opcode { get; } = ServerOpcode.AccountKicked; - - public AccountKickedPacket(byte reasonCode) - { - ReasonCode = reasonCode; - } - - public void Read(BinaryReader reader) - { - ReasonCode = reader.ReadByte(); - } - - public void Write(BinaryWriter writer) - { - writer.Write((byte) Opcode); - writer.Write(ReasonCode); - } - - public override string ToString() - { - return $"AccountKickedPacket({ReasonCode})"; - } + return $"AccountKickedPacket({ReasonCode})"; } } diff --git a/src/Rasa.Auth/Packets/Auth/Server/BlockedAccountPacket.cs b/src/Rasa.Auth/Packets/Auth/Server/BlockedAccountPacket.cs index 6d7d8e33..1402c1ca 100644 --- a/src/Rasa.Auth/Packets/Auth/Server/BlockedAccountPacket.cs +++ b/src/Rasa.Auth/Packets/Auth/Server/BlockedAccountPacket.cs @@ -1,29 +1,28 @@ using System.IO; -namespace Rasa.Packets.Auth.Server -{ - using Data; +namespace Rasa.Packets.Auth.Server; - public class BlockedAccountPacket : IOpcodedPacket - { - public uint Reason { get; set; } +using Rasa.Data; - public ServerOpcode Opcode { get; } = ServerOpcode.BlockedAccount; +public class BlockedAccountPacket : IOpcodedPacket +{ + public uint Reason { get; set; } - public void Read(BinaryReader reader) - { - Reason = reader.ReadUInt32(); - } + public ServerOpcode Opcode { get; } = ServerOpcode.BlockedAccount; - public void Write(BinaryWriter writer) - { - writer.Write((byte) Opcode); - writer.Write(Reason); - } + public void Read(BinaryReader reader) + { + Reason = reader.ReadUInt32(); + } - public override string ToString() - { - return $"BlockedAccountPacket({Reason})"; - } + public void Write(BinaryWriter writer) + { + writer.Write((byte) Opcode); + writer.Write(Reason); + } + + public override string ToString() + { + return $"BlockedAccountPacket({Reason})"; } } diff --git a/src/Rasa.Auth/Packets/Auth/Server/BlockedAccountWithMsgPacket.cs b/src/Rasa.Auth/Packets/Auth/Server/BlockedAccountWithMsgPacket.cs index 157590cb..054a26d9 100644 --- a/src/Rasa.Auth/Packets/Auth/Server/BlockedAccountWithMsgPacket.cs +++ b/src/Rasa.Auth/Packets/Auth/Server/BlockedAccountWithMsgPacket.cs @@ -2,30 +2,29 @@ using System.Diagnostics; using System.IO; -namespace Rasa.Packets.Auth.Server -{ - using Data; +namespace Rasa.Packets.Auth.Server; + +using Rasa.Data; - public class BlockedAccountWithMsgPacket : IOpcodedPacket +public class BlockedAccountWithMsgPacket : IOpcodedPacket +{ + public ServerOpcode Opcode { get; } = ServerOpcode.BlockedAccountWithMessage; + public void Read(BinaryReader reader) { - public ServerOpcode Opcode { get; } = ServerOpcode.BlockedAccountWithMessage; - public void Read(BinaryReader reader) + var count = reader.ReadByte(); + for (var i = 0; i < count; ++i) { - var count = reader.ReadByte(); - for (var i = 0; i < count; ++i) - { - Debugger.Break(); - } - - throw new NotImplementedException(); + Debugger.Break(); } - public void Write(BinaryWriter writer) - { - writer.Write((byte) Opcode); - writer.Write((byte) 0); // TODO: when needed + throw new NotImplementedException(); + } - throw new NotImplementedException(); - } + public void Write(BinaryWriter writer) + { + writer.Write((byte) Opcode); + writer.Write((byte) 0); // TODO: when needed + + throw new NotImplementedException(); } } diff --git a/src/Rasa.Auth/Packets/Auth/Server/HandoffToQueuePacket.cs b/src/Rasa.Auth/Packets/Auth/Server/HandoffToQueuePacket.cs index 6d40de4c..0b55f3ac 100644 --- a/src/Rasa.Auth/Packets/Auth/Server/HandoffToQueuePacket.cs +++ b/src/Rasa.Auth/Packets/Auth/Server/HandoffToQueuePacket.cs @@ -1,35 +1,34 @@ using System.IO; -namespace Rasa.Packets.Auth.Server -{ - using Data; +namespace Rasa.Packets.Auth.Server; - public class HandoffToQueuePacket : IOpcodedPacket - { - public uint OneTimeKey { get; set; } - public uint AccountId { get; set; } - public byte ServerId { get; set; } +using Rasa.Data; - public ServerOpcode Opcode { get; } = ServerOpcode.HandOffToQueue; +public class HandoffToQueuePacket : IOpcodedPacket +{ + public uint OneTimeKey { get; set; } + public uint AccountId { get; set; } + public byte ServerId { get; set; } - public void Read(BinaryReader reader) - { - OneTimeKey = reader.ReadUInt32(); - AccountId = reader.ReadUInt32(); - ServerId = reader.ReadByte(); - } + public ServerOpcode Opcode { get; } = ServerOpcode.HandOffToQueue; - public void Write(BinaryWriter writer) - { - writer.Write((byte) Opcode); - writer.Write(OneTimeKey); - writer.Write(AccountId); - writer.Write(ServerId); - } + public void Read(BinaryReader reader) + { + OneTimeKey = reader.ReadUInt32(); + AccountId = reader.ReadUInt32(); + ServerId = reader.ReadByte(); + } - public override string ToString() - { - return $"HandoffToQueuePacket({OneTimeKey}, {AccountId}, {ServerId})"; - } + public void Write(BinaryWriter writer) + { + writer.Write((byte) Opcode); + writer.Write(OneTimeKey); + writer.Write(AccountId); + writer.Write(ServerId); + } + + public override string ToString() + { + return $"HandoffToQueuePacket({OneTimeKey}, {AccountId}, {ServerId})"; } } diff --git a/src/Rasa.Auth/Packets/Auth/Server/LoginFailPacket.cs b/src/Rasa.Auth/Packets/Auth/Server/LoginFailPacket.cs index 9bb03721..b719341d 100644 --- a/src/Rasa.Auth/Packets/Auth/Server/LoginFailPacket.cs +++ b/src/Rasa.Auth/Packets/Auth/Server/LoginFailPacket.cs @@ -1,34 +1,33 @@ using System.IO; -namespace Rasa.Packets.Auth.Server +namespace Rasa.Packets.Auth.Server; + +using Rasa.Data; + +public class LoginFailPacket : IOpcodedPacket { - using Data; + public FailReason ResultCode { get; set; } + + public ServerOpcode Opcode { get; } = ServerOpcode.LoginFail; + + public LoginFailPacket(FailReason resultCode) + { + ResultCode = resultCode; + } + + public void Read(BinaryReader reader) + { + ResultCode = (FailReason) reader.ReadByte(); + } + + public void Write(BinaryWriter writer) + { + writer.Write((byte) Opcode); + writer.Write((byte) ResultCode); + } - public class LoginFailPacket : IOpcodedPacket + public override string ToString() { - public FailReason ResultCode { get; set; } - - public ServerOpcode Opcode { get; } = ServerOpcode.LoginFail; - - public LoginFailPacket(FailReason resultCode) - { - ResultCode = resultCode; - } - - public void Read(BinaryReader reader) - { - ResultCode = (FailReason) reader.ReadByte(); - } - - public void Write(BinaryWriter writer) - { - writer.Write((byte) Opcode); - writer.Write((byte) ResultCode); - } - - public override string ToString() - { - return $"LoginFailPacket({ResultCode})"; - } + return $"LoginFailPacket({ResultCode})"; } } diff --git a/src/Rasa.Auth/Packets/Auth/Server/LoginOkPacket.cs b/src/Rasa.Auth/Packets/Auth/Server/LoginOkPacket.cs index 0ecc15aa..9398a1ea 100644 --- a/src/Rasa.Auth/Packets/Auth/Server/LoginOkPacket.cs +++ b/src/Rasa.Auth/Packets/Auth/Server/LoginOkPacket.cs @@ -1,56 +1,55 @@ using System.IO; -namespace Rasa.Packets.Auth.Server -{ - using Data; +namespace Rasa.Packets.Auth.Server; - public class LoginOkPacket : IOpcodedPacket - { - public uint SessionId1 { get; set; } - public uint SessionId2 { get; set; } - public uint UpdateKey1 { get; set; } - public uint UpdateKey2 { get; set; } - public uint PayStat { get; set; } - public uint RemainingTime { get; set; } - public uint QuotaTime { get; set; } - public uint WarnFlag { get; set; } - public uint LoginFlag { get; set; } - public byte UnkByte { get; set; } +using Rasa.Data; - public ServerOpcode Opcode { get; } = ServerOpcode.LoginOk; +public class LoginOkPacket : IOpcodedPacket +{ + public uint SessionId1 { get; set; } + public uint SessionId2 { get; set; } + public uint UpdateKey1 { get; set; } + public uint UpdateKey2 { get; set; } + public uint PayStat { get; set; } + public uint RemainingTime { get; set; } + public uint QuotaTime { get; set; } + public uint WarnFlag { get; set; } + public uint LoginFlag { get; set; } + public byte UnkByte { get; set; } - public void Read(BinaryReader reader) - { - SessionId1 = reader.ReadUInt32(); - SessionId2 = reader.ReadUInt32(); - UpdateKey1 = reader.ReadUInt32(); - UpdateKey2 = reader.ReadUInt32(); - PayStat = reader.ReadUInt32(); - RemainingTime = reader.ReadUInt32(); - QuotaTime = reader.ReadUInt32(); - WarnFlag = reader.ReadUInt32(); - LoginFlag = reader.ReadUInt32(); - UnkByte = reader.ReadByte(); - } + public ServerOpcode Opcode { get; } = ServerOpcode.LoginOk; - public void Write(BinaryWriter writer) - { - writer.Write((byte) Opcode); - writer.Write(SessionId1); - writer.Write(SessionId2); - writer.Write(UpdateKey1); - writer.Write(UpdateKey2); - writer.Write(PayStat); - writer.Write(RemainingTime); - writer.Write(QuotaTime); - writer.Write(WarnFlag); - writer.Write(LoginFlag); - writer.Write(UnkByte); - } + public void Read(BinaryReader reader) + { + SessionId1 = reader.ReadUInt32(); + SessionId2 = reader.ReadUInt32(); + UpdateKey1 = reader.ReadUInt32(); + UpdateKey2 = reader.ReadUInt32(); + PayStat = reader.ReadUInt32(); + RemainingTime = reader.ReadUInt32(); + QuotaTime = reader.ReadUInt32(); + WarnFlag = reader.ReadUInt32(); + LoginFlag = reader.ReadUInt32(); + UnkByte = reader.ReadByte(); + } - public override string ToString() - { - return $"LoginOkPacket({SessionId1}, {SessionId2}, {UpdateKey1}, {UpdateKey2}, {PayStat}, {RemainingTime}, {QuotaTime}, {WarnFlag}, {LoginFlag})"; - } + public void Write(BinaryWriter writer) + { + writer.Write((byte) Opcode); + writer.Write(SessionId1); + writer.Write(SessionId2); + writer.Write(UpdateKey1); + writer.Write(UpdateKey2); + writer.Write(PayStat); + writer.Write(RemainingTime); + writer.Write(QuotaTime); + writer.Write(WarnFlag); + writer.Write(LoginFlag); + writer.Write(UnkByte); + } + + public override string ToString() + { + return $"LoginOkPacket({SessionId1}, {SessionId2}, {UpdateKey1}, {UpdateKey2}, {PayStat}, {RemainingTime}, {QuotaTime}, {WarnFlag}, {LoginFlag})"; } } diff --git a/src/Rasa.Auth/Packets/Auth/Server/PlayFailPacket.cs b/src/Rasa.Auth/Packets/Auth/Server/PlayFailPacket.cs index 7bb4ca8e..0be64b93 100644 --- a/src/Rasa.Auth/Packets/Auth/Server/PlayFailPacket.cs +++ b/src/Rasa.Auth/Packets/Auth/Server/PlayFailPacket.cs @@ -1,34 +1,33 @@ using System.IO; -namespace Rasa.Packets.Auth.Server +namespace Rasa.Packets.Auth.Server; + +using Rasa.Data; + +public class PlayFailPacket : IOpcodedPacket { - using Data; + public FailReason ResultCode { get; set; } + + public ServerOpcode Opcode { get; } = ServerOpcode.PlayFail; + + public PlayFailPacket(FailReason resultCode) + { + ResultCode = resultCode; + } + + public void Read(BinaryReader reader) + { + ResultCode = (FailReason) reader.ReadByte(); + } + + public void Write(BinaryWriter writer) + { + writer.Write((byte) Opcode); + writer.Write((byte) ResultCode); + } - public class PlayFailPacket : IOpcodedPacket + public override string ToString() { - public FailReason ResultCode { get; set; } - - public ServerOpcode Opcode { get; } = ServerOpcode.PlayFail; - - public PlayFailPacket(FailReason resultCode) - { - ResultCode = resultCode; - } - - public void Read(BinaryReader reader) - { - ResultCode = (FailReason) reader.ReadByte(); - } - - public void Write(BinaryWriter writer) - { - writer.Write((byte) Opcode); - writer.Write((byte) ResultCode); - } - - public override string ToString() - { - return $"PlayFailPacket({ResultCode})"; - } + return $"PlayFailPacket({ResultCode})"; } } diff --git a/src/Rasa.Auth/Packets/Auth/Server/PlayOkPacket.cs b/src/Rasa.Auth/Packets/Auth/Server/PlayOkPacket.cs index d0f0df62..7ddddaab 100644 --- a/src/Rasa.Auth/Packets/Auth/Server/PlayOkPacket.cs +++ b/src/Rasa.Auth/Packets/Auth/Server/PlayOkPacket.cs @@ -1,35 +1,34 @@ using System.IO; -namespace Rasa.Packets.Auth.Server -{ - using Data; +namespace Rasa.Packets.Auth.Server; - public class PlayOkPacket : IOpcodedPacket - { - public uint OneTimeKey { get; set; } - public uint UserId { get; set; } - public byte ServerId { get; set; } +using Rasa.Data; - public ServerOpcode Opcode { get; } = ServerOpcode.PlayOk; +public class PlayOkPacket : IOpcodedPacket +{ + public uint OneTimeKey { get; set; } + public uint UserId { get; set; } + public byte ServerId { get; set; } - public void Read(BinaryReader reader) - { - OneTimeKey = reader.ReadUInt32(); - UserId = reader.ReadUInt32(); - ServerId = reader.ReadByte(); - } + public ServerOpcode Opcode { get; } = ServerOpcode.PlayOk; - public void Write(BinaryWriter writer) - { - writer.Write((byte) Opcode); - writer.Write(OneTimeKey); - writer.Write(UserId); - writer.Write(ServerId); - } + public void Read(BinaryReader reader) + { + OneTimeKey = reader.ReadUInt32(); + UserId = reader.ReadUInt32(); + ServerId = reader.ReadByte(); + } - public override string ToString() - { - return $"PlayOkPacket({OneTimeKey}, {UserId}, {ServerId})"; - } + public void Write(BinaryWriter writer) + { + writer.Write((byte) Opcode); + writer.Write(OneTimeKey); + writer.Write(UserId); + writer.Write(ServerId); + } + + public override string ToString() + { + return $"PlayOkPacket({OneTimeKey}, {UserId}, {ServerId})"; } } diff --git a/src/Rasa.Auth/Packets/Auth/Server/ProtocolVersionPacket.cs b/src/Rasa.Auth/Packets/Auth/Server/ProtocolVersionPacket.cs index fe3ed8fc..8b02b0c6 100644 --- a/src/Rasa.Auth/Packets/Auth/Server/ProtocolVersionPacket.cs +++ b/src/Rasa.Auth/Packets/Auth/Server/ProtocolVersionPacket.cs @@ -1,38 +1,37 @@ using System.IO; -namespace Rasa.Packets.Auth.Server +namespace Rasa.Packets.Auth.Server; + +using Rasa.Data; + +public class ProtocolVersionPacket : IOpcodedPacket { - using Data; + public uint ProtocolVersion { get; set; } + public uint OneTimeKey { get; set; } + + public ServerOpcode Opcode { get; } = ServerOpcode.ProtocolVersion; + + public ProtocolVersionPacket(uint oneTimeKey = 0U, uint protocolVersion = 0U) + { + OneTimeKey = oneTimeKey; + ProtocolVersion = protocolVersion; + } + + public void Read(BinaryReader reader) + { + OneTimeKey = reader.ReadUInt32(); + ProtocolVersion = reader.ReadUInt32(); + } + + public void Write(BinaryWriter writer) + { + writer.Write((byte) Opcode); + writer.Write(OneTimeKey); + writer.Write(ProtocolVersion); + } - public class ProtocolVersionPacket : IOpcodedPacket + public override string ToString() { - public uint ProtocolVersion { get; set; } - public uint OneTimeKey { get; set; } - - public ServerOpcode Opcode { get; } = ServerOpcode.ProtocolVersion; - - public ProtocolVersionPacket(uint oneTimeKey = 0U, uint protocolVersion = 0U) - { - OneTimeKey = oneTimeKey; - ProtocolVersion = protocolVersion; - } - - public void Read(BinaryReader reader) - { - OneTimeKey = reader.ReadUInt32(); - ProtocolVersion = reader.ReadUInt32(); - } - - public void Write(BinaryWriter writer) - { - writer.Write((byte) Opcode); - writer.Write(OneTimeKey); - writer.Write(ProtocolVersion); - } - - public override string ToString() - { - return $"ProtocolVersionPacket({ProtocolVersion}, {OneTimeKey})"; - } + return $"ProtocolVersionPacket({ProtocolVersion}, {OneTimeKey})"; } } diff --git a/src/Rasa.Auth/Packets/Auth/Server/SCCheckReqPacket.cs b/src/Rasa.Auth/Packets/Auth/Server/SCCheckReqPacket.cs index decd5171..f3cc1a2d 100644 --- a/src/Rasa.Auth/Packets/Auth/Server/SCCheckReqPacket.cs +++ b/src/Rasa.Auth/Packets/Auth/Server/SCCheckReqPacket.cs @@ -1,33 +1,32 @@  using System.IO; -namespace Rasa.Packets.Auth.Server -{ - using Data; +namespace Rasa.Packets.Auth.Server; - public class SCCheckReqPacket : IOpcodedPacket - { - public uint UserId { get; set; } - public byte CardKey { get; set; } +using Rasa.Data; - public ServerOpcode Opcode { get; } = ServerOpcode.SCCheckReq; +public class SCCheckReqPacket : IOpcodedPacket +{ + public uint UserId { get; set; } + public byte CardKey { get; set; } - public void Read(BinaryReader reader) - { - UserId = reader.ReadUInt32(); - CardKey = reader.ReadByte(); - } + public ServerOpcode Opcode { get; } = ServerOpcode.SCCheckReq; - public void Write(BinaryWriter writer) - { - writer.Write((byte) Opcode); - writer.Write(UserId); - writer.Write(CardKey); - } + public void Read(BinaryReader reader) + { + UserId = reader.ReadUInt32(); + CardKey = reader.ReadByte(); + } - public override string ToString() - { - return $"SCCheckReqPacket({UserId}, {CardKey})"; - } + public void Write(BinaryWriter writer) + { + writer.Write((byte) Opcode); + writer.Write(UserId); + writer.Write(CardKey); + } + + public override string ToString() + { + return $"SCCheckReqPacket({UserId}, {CardKey})"; } } diff --git a/src/Rasa.Auth/Packets/Auth/Server/SendServerFailPacket.cs b/src/Rasa.Auth/Packets/Auth/Server/SendServerFailPacket.cs index b03f4a5a..c9d88b5e 100644 --- a/src/Rasa.Auth/Packets/Auth/Server/SendServerFailPacket.cs +++ b/src/Rasa.Auth/Packets/Auth/Server/SendServerFailPacket.cs @@ -1,34 +1,33 @@ using System.IO; -namespace Rasa.Packets.Auth.Server +namespace Rasa.Packets.Auth.Server; + +using Rasa.Data; + +public class SendServerFailPacket : IOpcodedPacket { - using Data; + public byte ReasonCode { get; set; } + + public ServerOpcode Opcode { get; } = ServerOpcode.SendServerListFail; + + public SendServerFailPacket(byte reasonCode) + { + ReasonCode = reasonCode; + } + + public void Read(BinaryReader reader) + { + ReasonCode = reader.ReadByte(); + } + + public void Write(BinaryWriter writer) + { + writer.Write((byte) Opcode); + writer.Write(ReasonCode); + } - public class SendServerFailPacket : IOpcodedPacket + public override string ToString() { - public byte ReasonCode { get; set; } - - public ServerOpcode Opcode { get; } = ServerOpcode.SendServerListFail; - - public SendServerFailPacket(byte reasonCode) - { - ReasonCode = reasonCode; - } - - public void Read(BinaryReader reader) - { - ReasonCode = reader.ReadByte(); - } - - public void Write(BinaryWriter writer) - { - writer.Write((byte) Opcode); - writer.Write(ReasonCode); - } - - public override string ToString() - { - return $"SendServerFailPacket({ReasonCode})"; - } + return $"SendServerFailPacket({ReasonCode})"; } } diff --git a/src/Rasa.Auth/Packets/Auth/Server/SendServerListExtPacket.cs b/src/Rasa.Auth/Packets/Auth/Server/SendServerListExtPacket.cs index 010ba031..2faa10cd 100644 --- a/src/Rasa.Auth/Packets/Auth/Server/SendServerListExtPacket.cs +++ b/src/Rasa.Auth/Packets/Auth/Server/SendServerListExtPacket.cs @@ -3,81 +3,80 @@ using System.IO; using System.Net; -namespace Rasa.Packets.Auth.Server +namespace Rasa.Packets.Auth.Server; + +using Rasa.Communicator; +using Rasa.Data; + +public class SendServerListExtPacket : IOpcodedPacket { - using Data; - using Structures; + public byte LastServerId { get; set; } + public List ServerList { get; set; } + + public ServerOpcode Opcode { get; } = ServerOpcode.SendServerListExt; - public class SendServerListExtPacket : IOpcodedPacket + public SendServerListExtPacket(List servers, byte lastServerId = 0) { - public byte LastServerId { get; set; } - public List ServerList { get; set; } + ServerList = servers; + LastServerId = lastServerId; + } - public ServerOpcode Opcode { get; } = ServerOpcode.SendServerListExt; + public void Read(BinaryReader reader) + { + ServerList = new List(); - public SendServerListExtPacket(List servers, byte lastServerId = 0) - { - ServerList = servers; - LastServerId = lastServerId; - } + var count = reader.ReadByte(); + LastServerId = reader.ReadByte(); - public void Read(BinaryReader reader) + for (var i = 0; i < count; ++i) { - ServerList = new List(); - - var count = reader.ReadByte(); - LastServerId = reader.ReadByte(); - - for (var i = 0; i < count; ++i) + ServerList.Add(new ServerInfo { - ServerList.Add(new ServerInfo - { - ServerId = reader.ReadByte(), - Ip = new IPAddress(reader.ReadBytes(4)), - QueuePort = reader.ReadInt32(), - AgeLimit = reader.ReadByte(), - PKFlag = reader.ReadByte(), - CurrentPlayers = reader.ReadUInt16(), - MaxPlayers = reader.ReadUInt16(), - Status = reader.ReadByte() - }); - } + ServerId = reader.ReadByte(), + Ip = new IPAddress(reader.ReadBytes(4)), + QueuePort = reader.ReadInt32(), + AgeLimit = reader.ReadByte(), + PKFlag = reader.ReadByte(), + CurrentPlayers = reader.ReadUInt16(), + MaxPlayers = reader.ReadUInt16(), + Status = reader.ReadByte() + }); } + } - public void Write(BinaryWriter writer) - { - if (ServerList == null) - throw new InvalidOperationException("You must specify a list of ServerInfo before you can serialize it!"); + public void Write(BinaryWriter writer) + { + if (ServerList == null) + throw new InvalidOperationException("You must specify a list of ServerInfo before you can serialize it!"); - var count = ServerList.Count; - if (count >= 16) - count = 16; + var count = ServerList.Count; + if (count >= 16) + count = 16; - writer.Write((byte) Opcode); - writer.Write((byte) count); - writer.Write(LastServerId); + writer.Write((byte) Opcode); + writer.Write((byte) count); + writer.Write(LastServerId); - var c = 0U; + var c = 0U; - foreach (var s in ServerList) - { - writer.Write(s.ServerId); - writer.Write(s.Ip.GetAddressBytes()); - writer.Write(s.QueuePort); - writer.Write(s.AgeLimit); - writer.Write(s.PKFlag); - writer.Write(s.CurrentPlayers); - writer.Write(s.MaxPlayers); - writer.Write(s.Status); + foreach (var s in ServerList) + { + writer.Write(s.ServerId); + writer.Write(s.Ip.GetAddressBytes()); + writer.Write(s.QueuePort); + writer.Write(s.AgeLimit); + writer.Write(s.PKFlag); + writer.Write(s.CurrentPlayers); + writer.Write(s.MaxPlayers); + writer.Write(s.Status); - if (++c == count) - break; - } + if (++c == count) + break; } + } - public override string ToString() - { - return $"SendServerListExtPacket(Count: {ServerList?.Count ?? -1})"; - } + public override string ToString() + { + return $"SendServerListExtPacket(Count: {ServerList?.Count ?? -1})"; } } diff --git a/src/Rasa.Auth/Properties/AssemblyInfo.cs b/src/Rasa.Auth/Properties/AssemblyInfo.cs deleted file mode 100644 index 749f335b..00000000 --- a/src/Rasa.Auth/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System.Reflection; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("Rasa.Auth")] -[assembly: AssemblyTrademark("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("a0c37e2b-2da0-4d9b-9c8f-a3cffd06f51d")] diff --git a/src/Rasa.Auth/Rasa.Auth.csproj b/src/Rasa.Auth/Rasa.Auth.csproj index 04ff21b5..e6033b5d 100644 --- a/src/Rasa.Auth/Rasa.Auth.csproj +++ b/src/Rasa.Auth/Rasa.Auth.csproj @@ -2,18 +2,16 @@ Rasa.NET Auth - net5.0 + net7.0 Rasa.Auth Exe Rasa.Auth - win10-x64;osx.10.10-x64;ubuntu.14.04-x64 - 5.0.0 false false false Rasa Rasa.AuthProgram - 9.0 + 10.0 @@ -27,8 +25,8 @@ + - diff --git a/src/Rasa.Auth/Structures/ServerInfo.cs b/src/Rasa.Auth/Structures/ServerInfo.cs deleted file mode 100644 index c6aa5c53..00000000 --- a/src/Rasa.Auth/Structures/ServerInfo.cs +++ /dev/null @@ -1,41 +0,0 @@ -using System.Net; - -namespace Rasa.Structures -{ - public class ServerInfo - { - public byte ServerId { get; set; } - public IPAddress Ip { get; set; } - public int QueuePort { get; set; } - public int GamePort { get; set; } - public byte AgeLimit { get; set; } - public byte PKFlag { get; set; } - public ushort CurrentPlayers { get; set; } - public ushort MaxPlayers { get; set; } - public byte Status { get; set; } - - public void Setup(IPAddress address, int queuePort, int gamePort, byte ageLimit, byte pkFlag, ushort currPlayers, ushort maxPlayers) - { - Ip = address; - QueuePort = queuePort; - GamePort = gamePort; - AgeLimit = ageLimit; - PKFlag = pkFlag; - CurrentPlayers = currPlayers; - MaxPlayers = maxPlayers; - Status = 1; - } - - public void Clear() - { - Ip = IPAddress.None; - QueuePort = 0; - GamePort = 0; - AgeLimit = 0; - PKFlag = 0; - CurrentPlayers = 0; - MaxPlayers = 0; - Status = 0; - } - } -} diff --git a/src/Rasa.Communicator/Communicator.cs b/src/Rasa.Communicator/Communicator.cs index 25021f69..46ed821c 100644 --- a/src/Rasa.Communicator/Communicator.cs +++ b/src/Rasa.Communicator/Communicator.cs @@ -1,379 +1,469 @@ using System; using System.Collections.Generic; +using System.IO; using System.Net; -using System.Net.Sockets; +using System.Text; +namespace Rasa.Communicator; + +using Rasa.Communicator.Packets; +using Rasa.Memory; +using Rasa.Networking; using Rasa.Packets; +using System.Buffers; + +public enum CommunicatorType +{ + Server, + ServerClient, + Client +} -namespace Rasa.Communicator +public enum CommunicatorOpcode : byte { - using Memory; - using Networking; - using Packets; + LoginRequest = 0, + LoginResponse = 1, + RedirectRequest = 2, + RedirectResponse = 3, + ServerInfoRequest = 4, + ServerInfoResponse = 5 +} - public enum CommunicatorType +public enum CommunicatorActionResult : byte +{ + Success = 0, + Failure = 1 +} + +public class Communicator +{ + public const int SendBufferSize = 512; + public const double ServerInfoUpdateIntervalMs = 30000.0d; + + public CommunicatorType Type { get; } + public AsyncLengthedSocket Socket { get; } + public List AuthenticatingChildren { get; } + public Dictionary Clients { get; } + public List ToRemoveClients { get; } + public DateTime LastRequestTime { get; private set; } + public ServerData ServerData { get; private set; } + public ServerInfo ServerInfo { get; private set; } + public bool Connected => Socket?.Connected ?? false; + + private Communicator Server { get; } + + public Action OnError { get; set; } + public Action OnConnect { get; set; } + public Func OnLoginRequest { get; set; } + public Action OnLoginResponse { get; set; } + public Func OnRedirectRequest { get; set; } + public Action OnRedirectResponse { get; set; } + public Action OnServerInfoRequest { get; set; } + public Action OnServerInfoResponse { get; set; } + + public Communicator(CommunicatorType type) { - Server, - ServerClient, - Client + if (type == CommunicatorType.ServerClient) + throw new ArgumentOutOfRangeException(nameof(type)); + + Type = type; + + Socket = new AsyncLengthedSocket(AsyncLengthedSocket.HeaderSizeType.Word); + Socket.OnError += OnSocketError; + + switch (Type) + { + case CommunicatorType.Server: + AuthenticatingChildren = new(); + Clients = new(); + ToRemoveClients = new(); + + Socket.OnAccept += OnSocketAccept; + break; + + case CommunicatorType.Client: + Socket.OnReceive += OnSocketReceive; + Socket.OnConnect += OnSocketConnect; + break; + } } - public enum CommunicatorOpcode : byte + public Communicator(AsyncLengthedSocket socket, Communicator server) { - LoginRequest = 0, - LoginResponse = 1, - RedirectRequest = 2, - RedirectResponse = 3, - ServerInfoRequest = 4, - ServerInfoResponse = 5 + Type = CommunicatorType.ServerClient; + + Server = server; + + Socket = socket; + Socket.OnReceive += OnSocketReceive; + Socket.Start(); } - public enum CommunicatorActionResult : byte + public void Start(IPAddress address, int port, int backlog = int.MaxValue) { - Success = 0, - Failure = 1 + switch (Type) + { + case CommunicatorType.Server: + Socket.StartListening(new IPEndPoint(address, port), backlog); + break; + + case CommunicatorType.Client: + Socket.ConnectAsync(new IPEndPoint(address, port)); + break; + } } - public class Communicator + public void Update() { - public const SizeType CommunicatorHeaderLen = SizeType.Word; - public const double ServerInfoUpdateIntervalMs = 30000.0d; - - public CommunicatorType Type { get; } - public LengthedSocket Socket { get; private set; } - public List Children { get; } - public DateTime LastRequestTime { get; private set; } - public ServerData ServerData { get; set; } - - public Action OnError { get; set; } - public Action OnConnect { get; set; } - public Func OnLoginRequest { get; set; } - public Action OnLoginResponse { get; set; } - public Func OnRedirectRequest { get; set; } - public Action OnRedirectResponse { get; set; } - public Action OnServerInfoRequest { get; set; } - public Action OnServerInfoResponse { get; set; } - - public Communicator(CommunicatorType type, IPAddress address, int port, int backlog = 0) + if (Type != CommunicatorType.Server) + throw new Exception("Update can only be called on a server Communicator!"); + + lock (ToRemoveClients) { - if (type == CommunicatorType.ServerClient) - throw new ArgumentOutOfRangeException(nameof(type)); + foreach (var id in ToRemoveClients) + { + if (Clients.TryGetValue(id, out var comm)) + { + comm.Close(); - Type = type; + Clients.Remove(id); + } + } + + ToRemoveClients.Clear(); + } + } - Socket = new LengthedSocket(CommunicatorHeaderLen); - Socket.OnError += OnSocketError; + private void ClientAucthenticated(Communicator client) + { + if (Type != CommunicatorType.Server) + { + Logger.WriteLog(LogType.Error, $"Communicator(Type = {Type}) can't have clients!"); + return; + } - switch (Type) - { - case CommunicatorType.Server: - Children = new(); + Clients!.Add(client.ServerData.Id, client); + AuthenticatingChildren.Remove(client); + } - Socket.OnAccept += OnSocketAccept; + private void OnSocketError() + { + Socket.Close(); - Socket.Bind(new IPEndPoint(address, port)); - Socket.Listen(backlog); - Socket.AcceptAsync(); - break; + OnError?.Invoke(); - case CommunicatorType.Client: - Socket.OnReceive += OnSocketReceive; - Socket.OnConnect += OnSocketConnect; + Logger.WriteLog(LogType.Communicator, $"Communicator(Type = {Type}) has encountered an error!"); + } - Socket.ConnectAsync(new IPEndPoint(address, port)); - break; - } - } + private void OnSocketAccept(AsyncLengthedSocket socket) + { + AuthenticatingChildren!.Add(new Communicator(socket, this)); - public Communicator(LengthedSocket socket) - { - Type = CommunicatorType.ServerClient; + Logger.WriteLog(LogType.Communicator, $"New Communicator(Type = {Type}) client has connected! Remote: {socket.RemoteAddress}"); + } - Socket = socket; - Socket.OnReceive += OnSocketReceive; + private void OnSocketReceive(NonContiguousMemoryStream incomingStream, int length) + { + var startPosition = incomingStream.Position; - Socket.ReceiveAsync(); - } + using var br = new BinaryReader(incomingStream, Encoding.UTF8, true); - #region Socketing - private void OnSocketError(SocketAsyncEventArgs args) + var opcode = (CommunicatorOpcode)br.ReadByte(); + + IOpcodedPacket packet = opcode switch { - Socket.Close(); + CommunicatorOpcode.LoginRequest => new LoginRequestPacket(), + CommunicatorOpcode.LoginResponse => new LoginResponsePacket(), + CommunicatorOpcode.RedirectRequest => new RedirectRequestPacket(), + CommunicatorOpcode.RedirectResponse => new RedirectResponsePacket(), + CommunicatorOpcode.ServerInfoRequest => new ServerInfoRequestPacket(), + CommunicatorOpcode.ServerInfoResponse => new ServerInfoResponsePacket(), + _ => throw new Exception("Invalid opcode found in the Communicator's OnSocketReceive!") + }; - OnError?.Invoke(); + packet.Read(br); - Logger.WriteLog(LogType.Communicator, $"Communicator(Type = {Type}) has encountered an error!"); - } + if (startPosition + length != incomingStream.Position) + throw new Exception($"Over or under read of the incoming packet! Start position: {startPosition} | Length: {length} | Ending position: {incomingStream.Position}"); - private void OnSocketAccept(LengthedSocket socket) + switch (opcode) { - Children.Add(new Communicator(socket)); + case CommunicatorOpcode.LoginRequest: + MsgLoginRequest(packet as LoginRequestPacket); + break; - Logger.WriteLog(LogType.Communicator, $"New Communicator(Type = {Type}) client has connected! Remote: {socket.RemoteAddress}"); + case CommunicatorOpcode.LoginResponse: + MsgLoginResponse(packet as LoginResponsePacket); + break; - Socket.AcceptAsync(); - } + case CommunicatorOpcode.RedirectRequest: + MsgRedirectRequest(packet as RedirectRequestPacket); + break; - private void OnSocketReceive(BufferData data) - { - using var br = data.GetReader(); + case CommunicatorOpcode.RedirectResponse: + MsgRedirectResponse(packet as RedirectResponsePacket); + break; - var opcode = (CommunicatorOpcode)br.ReadByte(); + case CommunicatorOpcode.ServerInfoRequest: + MsgServerInfoRequest(packet as ServerInfoRequestPacket); + break; - IOpcodedPacket packet = opcode switch - { - CommunicatorOpcode.LoginRequest => new LoginRequestPacket(), - CommunicatorOpcode.LoginResponse => new LoginResponsePacket(), - CommunicatorOpcode.RedirectRequest => new RedirectRequestPacket(), - CommunicatorOpcode.RedirectResponse => new RedirectResponsePacket(), - CommunicatorOpcode.ServerInfoRequest => new ServerInfoRequestPacket(), - CommunicatorOpcode.ServerInfoResponse => new ServerInfoResponsePacket(), + case CommunicatorOpcode.ServerInfoResponse: + MsgServerInfoResponse(packet as ServerInfoResponsePacket); + break; + } + } - _ => throw new Exception("Invalid opcode found in the Communicator's OnSocketReceive!") - }; + private void OnSocketConnect() + { + Logger.WriteLog(LogType.Communicator, $"Communicator(Type = {Type}) has connected to the Communicator Server!"); - packet.Read(br); + if (OnConnect == null) + return; - switch (opcode) - { - case CommunicatorOpcode.LoginRequest: - MsgLoginRequest(packet as LoginRequestPacket); - break; + var info = new ServerData(); - case CommunicatorOpcode.LoginResponse: - MsgLoginResponse(packet as LoginResponsePacket); - break; + OnConnect(info); - case CommunicatorOpcode.RedirectRequest: - MsgRedirectRequest(packet as RedirectRequestPacket); - break; + Socket.Start(); - case CommunicatorOpcode.RedirectResponse: - MsgRedirectResponse(packet as RedirectResponsePacket); - break; + SendPacket(new LoginRequestPacket(info)); + } - case CommunicatorOpcode.ServerInfoRequest: - MsgServerInfoRequest(packet as ServerInfoRequestPacket); - break; + private void SendPacket(IOpcodedPacket packet) + { + var buffer = ArrayPool.Shared.Rent(SendBufferSize); + var writer = new BinaryWriter(new MemoryStream(buffer, true)); - case CommunicatorOpcode.ServerInfoResponse: - MsgServerInfoResponse(packet as ServerInfoResponsePacket); - break; - } - } + packet.Write(writer); + + Socket.Send(buffer, 0, (int)writer.BaseStream.Position); + + ArrayPool.Shared.Return(buffer); + } - private void OnSocketConnect(SocketAsyncEventArgs args) + public void Close() + { + if (Type == CommunicatorType.Server) { - if (args.SocketError != SocketError.Success) - { - OnSocketError(args); - return; - } + foreach (var child in AuthenticatingChildren!) + child.Close(); - Logger.WriteLog(LogType.Communicator, $"Communicator(Type = {Type}) has connected to the Communicator Server!"); + foreach (var client in Clients!) + client.Value.Close(); - if (OnConnect == null) + AuthenticatingChildren.Clear(); + Clients.Clear(); + } + + Socket.Close(); + } + + public void RequestServerInfo() + { + if (Type == CommunicatorType.Server) + { + foreach (var client in Clients) { - return; + if ((DateTime.Now - client.Value.LastRequestTime).TotalMilliseconds > ServerInfoUpdateIntervalMs) + client.Value.RequestServerInfo(); } + } + else if (Type == CommunicatorType.ServerClient) + { + LastRequestTime = DateTime.Now; - var info = new ServerData(); + SendPacket(new ServerInfoRequestPacket()); + } + } - OnConnect(info); + public void RequestRedirection(byte serverId, RedirectRequest request) + { + if (Type == CommunicatorType.ServerClient) + { + SendPacket(new RedirectRequestPacket(request)); - Socket.Send(new LoginRequestPacket(info)); - Socket.ReceiveAsync(); + return; } - #endregion - #region Requests - public void RequestServerInfo() + if (Type == CommunicatorType.Server) { - if (Type == CommunicatorType.Server) + if (Clients!.TryGetValue(serverId, out var client)) { - foreach (var client in Children) - { - if ((DateTime.Now - client.LastRequestTime).TotalMilliseconds > ServerInfoUpdateIntervalMs) - client.RequestServerInfo(); - } + client.RequestRedirection(serverId, request); + return; } - else if (Type == CommunicatorType.ServerClient) - { - LastRequestTime = DateTime.Now; - Socket.Send(new ServerInfoRequestPacket()); - } + Logger.WriteLog(LogType.Error, $"Communicator(Type = {Type}) was requested for redirection for an unknown server!"); } + else + Logger.WriteLog(LogType.Error, $"Communicator(Type = {Type}) can not request redirection!"); + } - public void RequestRedirection(RedirectRequest request) + #region Packet Handlers + private void MsgLoginRequest(LoginRequestPacket packet) + { + if (Type != CommunicatorType.ServerClient) { - if (Type != CommunicatorType.ServerClient) - { - Logger.WriteLog(LogType.Error, $"Communicator(Type = {Type}) can not request redirection!"); - return; - } + Logger.WriteLog(LogType.Error, $"Communicator(Type = {Type}) can not handle login requests!"); + return; + } - Socket.Send(new RedirectRequestPacket(request)); + if (Server.OnLoginRequest == null) + { + Logger.WriteLog(LogType.Error, $"Communicator(Type = {Type}) has no OnLoginRequest callback!"); + return; } - #endregion - #region Packet Handlers - private void MsgLoginRequest(LoginRequestPacket packet) + var result = Server.OnLoginRequest(this, packet); + + SendPacket(new LoginResponsePacket { - if (Type != CommunicatorType.ServerClient) - { - Logger.WriteLog(LogType.Error, $"Communicator(Type = {Type}) can not handle login requests!"); - return; - } + Result = result ? CommunicatorActionResult.Success : CommunicatorActionResult.Failure + }); - if (OnLoginRequest == null) - { - Logger.WriteLog(LogType.Error, $"Communicator(Type = {Type}) has no OnLoginRequest callback!"); - return; - } + if (!result) + { + lock (ToRemoveClients!) + ToRemoveClients.Add(ServerData!.Id); - var result = OnLoginRequest(packet.Data); + return; + } - Socket.Send(new LoginResponsePacket - { - Result = result ? CommunicatorActionResult.Success : CommunicatorActionResult.Failure - }); + ServerData = packet.Data; - if (!result) - return; + Server.ClientAucthenticated(this); - ServerData = packet.Data; + RequestServerInfo(); + } - RequestServerInfo(); + private void MsgLoginResponse(LoginResponsePacket packet) + { + if (Type != CommunicatorType.Client) + { + Logger.WriteLog(LogType.Error, $"Communicator(Type = {Type}) can not handle login responses!"); + return; } - private void MsgLoginResponse(LoginResponsePacket packet) + if (packet.Result == CommunicatorActionResult.Failure) { - if (Type != CommunicatorType.Client) - { - Logger.WriteLog(LogType.Error, $"Communicator(Type = {Type}) can not handle login responses!"); - return; - } + Close(); - if (packet.Result == CommunicatorActionResult.Success) - { - Logger.WriteLog(LogType.Communicator, $"Communicator(Type = {Type}) successfully authenticated with the Communicator server!"); - } - else - { - Socket?.Close(); + Logger.WriteLog(LogType.Error, $"Communicator(Type = {Type}) could not authenticate with the Communicator server!"); + return; + } - Logger.WriteLog(LogType.Error, $"Communicator(Type = {Type}) could not authenticate with the Communicator server!"); - } + OnLoginResponse?.Invoke(packet.Result); + } - OnLoginResponse?.Invoke(packet.Result); + private void MsgRedirectRequest(RedirectRequestPacket packet) + { + if (Type != CommunicatorType.Client) + { + Logger.WriteLog(LogType.Error, $"Communicator(Type = {Type}) can not handle redirect requests!"); + return; } - private void MsgRedirectRequest(RedirectRequestPacket packet) + if (OnRedirectRequest == null) { - if (Type != CommunicatorType.Client) - { - Logger.WriteLog(LogType.Error, $"Communicator(Type = {Type}) can not handle redirect requests!"); - return; - } + Logger.WriteLog(LogType.Error, $"Communicator(Type = {Type}) has no OnRedirectRequest callback!"); + return; + } - if (OnRedirectRequest == null) - { - Logger.WriteLog(LogType.Error, $"Communicator(Type = {Type}) has no OnRedirectRequest callback!"); - return; - } + var result = OnRedirectRequest(packet.Request); - var result = OnRedirectRequest(packet.Request); + SendPacket(new RedirectResponsePacket + { + AccountId = packet.Request.AccountId, + Result = result ? CommunicatorActionResult.Success : CommunicatorActionResult.Failure + }); + } - Socket.Send(new RedirectResponsePacket - { - AccountId = packet.Request.AccountId, - Result = result ? CommunicatorActionResult.Success : CommunicatorActionResult.Failure - }); + private void MsgRedirectResponse(RedirectResponsePacket packet) + { + if (Type != CommunicatorType.ServerClient) + { + Logger.WriteLog(LogType.Error, $"Communicator(Type = {Type}) can not handle redirect responses!"); + return; } - private void MsgRedirectResponse(RedirectResponsePacket packet) + if (Server!.OnRedirectResponse == null) { - if (Type != CommunicatorType.ServerClient) - { - Logger.WriteLog(LogType.Error, $"Communicator(Type = {Type}) can not handle redirect responses!"); - return; - } + Logger.WriteLog(LogType.Error, $"Communicator(Type = {Type}) has no OnRedirectResponse callback!"); + return; + } - if (OnRedirectResponse == null) - { - Logger.WriteLog(LogType.Error, $"Communicator(Type = {Type}) has no OnRedirectResponse callback!"); - return; - } + Server.OnRedirectResponse(this, packet); + } - OnRedirectResponse(packet.Result, packet.AccountId); +#pragma warning disable IDE0060 // Remove unused parameter + private void MsgServerInfoRequest(ServerInfoRequestPacket packet) +#pragma warning restore IDE0060 // Remove unused parameter + { + if (Type != CommunicatorType.Client) + { + Logger.WriteLog(LogType.Error, $"Communicator(Type = {Type}) can not handle server info requests!"); + return; } - private void MsgServerInfoRequest(ServerInfoRequestPacket packet) + if (OnServerInfoRequest == null) { - if (Type != CommunicatorType.Client) - { - Logger.WriteLog(LogType.Error, $"Communicator(Type = {Type}) can not handle server info requests!"); - return; - } + Logger.WriteLog(LogType.Error, $"Communicator(Type = {Type}) has no OnServerInfoRequest callback!"); + return; + } - if (OnServerInfoRequest == null) - { - Logger.WriteLog(LogType.Error, $"Communicator(Type = {Type}) has no OnServerInfoRequest callback!"); - return; - } + var info = new ServerInfo(); - var info = new ServerInfo(); + OnServerInfoRequest(info); - OnServerInfoRequest(info); + SendPacket(new ServerInfoResponsePacket(info)); + } - Socket.Send(new ServerInfoResponsePacket(info)); + private void MsgServerInfoResponse(ServerInfoResponsePacket packet) + { + if (Type != CommunicatorType.ServerClient) + { + Logger.WriteLog(LogType.Error, $"Communicator(Type = {Type}) can not handle server info responses!"); + return; } - private void MsgServerInfoResponse(ServerInfoResponsePacket packet) + if (Server.OnServerInfoResponse == null) { - if (Type != CommunicatorType.ServerClient) - { - Logger.WriteLog(LogType.Error, $"Communicator(Type = {Type}) can not handle server info responses!"); - return; - } + Logger.WriteLog(LogType.Error, $"Communicator(Type = {Type}) has no OnServerInfoResponse callback!"); + return; + } - if (OnServerInfoResponse == null) - { - Logger.WriteLog(LogType.Error, $"Communicator(Type = {Type}) has no OnServerInfoResponse callback!"); - return; - } + ServerInfo = packet.Info; - OnServerInfoResponse(packet.Info); - } - #endregion + Server.OnServerInfoResponse(); } + #endregion +} - public class ServerData - { - public byte Id { get; set; } - public string Password { get; set; } - public IPAddress Address { get; set; } - } +public class ServerData +{ + public byte Id { get; set; } + public string Password { get; set; } + public IPAddress Address { get; set; } +} - public class ServerInfo - { - public byte ServerId { get; set; } - public IPAddress Ip { get; set; } - public int QueuePort { get; set; } - public int GamePort { get; set; } - public byte AgeLimit { get; set; } - public byte PKFlag { get; set; } - public ushort CurrentPlayers { get; set; } - public ushort MaxPlayers { get; set; } - public byte Status { get; set; } - } +public class ServerInfo +{ + public byte ServerId { get; set; } + public IPAddress Ip { get; set; } + public int QueuePort { get; set; } + public int GamePort { get; set; } + public byte AgeLimit { get; set; } + public byte PKFlag { get; set; } + public ushort CurrentPlayers { get; set; } + public ushort MaxPlayers { get; set; } + public byte Status { get; set; } +} - public class RedirectRequest - { - public uint AccountId { get; set; } - public string Username { get; set; } - public string Email { get; set; } - public uint OneTimeKey { get; set; } - } +public class RedirectRequest +{ + public uint AccountId { get; set; } + public string Username { get; set; } + public string Email { get; set; } + public uint OneTimeKey { get; set; } } diff --git a/src/Rasa.Communicator/Packets/LoginRequestPacket.cs b/src/Rasa.Communicator/Packets/LoginRequestPacket.cs index 482c1631..065d9eb4 100644 --- a/src/Rasa.Communicator/Packets/LoginRequestPacket.cs +++ b/src/Rasa.Communicator/Packets/LoginRequestPacket.cs @@ -4,39 +4,38 @@ using Rasa.Packets; -namespace Rasa.Communicator.Packets +namespace Rasa.Communicator.Packets; + +using Rasa.Extensions; + +public class LoginRequestPacket : IOpcodedPacket { - using Extensions; + public CommunicatorOpcode Opcode { get; } = CommunicatorOpcode.LoginRequest; + public ServerData Data { get; set; } + + public LoginRequestPacket() + { + Data = new(); + } + + public LoginRequestPacket(ServerData info) + { + Data = info; + } + + public void Read(BinaryReader br) + { + Data.Id = br.ReadByte(); + Data.Password = br.ReadLengthedString(); + Data.Address = new IPAddress(br.ReadBytes(br.ReadByte())); + } - public class LoginRequestPacket : IOpcodedPacket + public void Write(BinaryWriter bw) { - public CommunicatorOpcode Opcode { get; } = CommunicatorOpcode.LoginRequest; - public ServerData Data { get; set; } - - public LoginRequestPacket() - { - Data = new(); - } - - public LoginRequestPacket(ServerData info) - { - Data = info; - } - - public void Read(BinaryReader br) - { - Data.Id = br.ReadByte(); - Data.Password = br.ReadLengthedString(); - Data.Address = new IPAddress(br.ReadBytes(br.ReadByte())); - } - - public void Write(BinaryWriter bw) - { - bw.Write((byte)Opcode); - bw.Write(Data.Id); - bw.WriteLengthedString(Data.Password); - bw.Write((byte)(Data.Address.AddressFamily == AddressFamily.InterNetwork ? 4 : 16)); - bw.Write(Data.Address.GetAddressBytes()); - } + bw.Write((byte)Opcode); + bw.Write(Data.Id); + bw.WriteLengthedString(Data.Password); + bw.Write((byte)(Data.Address.AddressFamily == AddressFamily.InterNetwork ? 4 : 16)); + bw.Write(Data.Address.GetAddressBytes()); } } diff --git a/src/Rasa.Communicator/Rasa.Communicator.csproj b/src/Rasa.Communicator/Rasa.Communicator.csproj index 04c8c933..6af2eb3c 100644 --- a/src/Rasa.Communicator/Rasa.Communicator.csproj +++ b/src/Rasa.Communicator/Rasa.Communicator.csproj @@ -1,8 +1,9 @@ - + - net5.0 + net7.0 Rasa.Communicator + 10.0 diff --git a/src/Rasa.DBL/Context/RasaDbContextBase.cs b/src/Rasa.DBL/Context/RasaDbContextBase.cs index 6e29e5df..8d33a88c 100644 --- a/src/Rasa.DBL/Context/RasaDbContextBase.cs +++ b/src/Rasa.DBL/Context/RasaDbContextBase.cs @@ -11,6 +11,7 @@ namespace Rasa.Context using Initialization; using Repositories; using Structures.Interfaces; + using System; public abstract class RasaDbContextBase : DbContext, IInitializable { @@ -98,7 +99,9 @@ public void Initialize() { if (_databaseConfiguration.Value.GetDatabaseProvider() == DatabaseProvider.Sqlite) { + Console.WriteLine($"Please wait, loading Sqlite database..."); this.Database.Migrate(); + Console.WriteLine("Database ready."); } } } diff --git a/src/Rasa.DBL/Migrations/MySqlAuth/MySqlAuthContextModelSnapshot.cs b/src/Rasa.DBL/Migrations/MySqlAuth/MySqlAuthContextModelSnapshot.cs index 2c021fea..e3e724b6 100644 --- a/src/Rasa.DBL/Migrations/MySqlAuth/MySqlAuthContextModelSnapshot.cs +++ b/src/Rasa.DBL/Migrations/MySqlAuth/MySqlAuthContextModelSnapshot.cs @@ -17,7 +17,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) .HasAnnotation("Relational:MaxIdentifierLength", 64) .HasAnnotation("ProductVersion", "5.0.1"); - modelBuilder.Entity("Rasa.Structures.AuthAccountEntry", b => + modelBuilder.Entity("Rasa.Structures.Auth.AuthAccountEntry", b => { b.Property("Id") .ValueGeneratedOnAdd() diff --git a/src/Rasa.DBL/Migrations/SqliteAuth/SqliteAuthContextModelSnapshot.cs b/src/Rasa.DBL/Migrations/SqliteAuth/SqliteAuthContextModelSnapshot.cs index 99d0a0a6..fd92ba0a 100644 --- a/src/Rasa.DBL/Migrations/SqliteAuth/SqliteAuthContextModelSnapshot.cs +++ b/src/Rasa.DBL/Migrations/SqliteAuth/SqliteAuthContextModelSnapshot.cs @@ -16,7 +16,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) modelBuilder .HasAnnotation("ProductVersion", "5.0.1"); - modelBuilder.Entity("Rasa.Structures.AuthAccountEntry", b => + modelBuilder.Entity("Rasa.Structures.Auth.AuthAccountEntry", b => { b.Property("Id") .ValueGeneratedOnAdd() diff --git a/src/Rasa.DBL/Properties/AssemblyInfo.cs b/src/Rasa.DBL/Properties/AssemblyInfo.cs deleted file mode 100644 index 0322bb9a..00000000 --- a/src/Rasa.DBL/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System.Reflection; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("Rasa.DBL")] -[assembly: AssemblyTrademark("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("94ba5d4f-67e5-4027-8440-65be576952c6")] diff --git a/src/Rasa.DBL/Rasa.DBL.csproj b/src/Rasa.DBL/Rasa.DBL.csproj index 5273d199..72e5756c 100644 --- a/src/Rasa.DBL/Rasa.DBL.csproj +++ b/src/Rasa.DBL/Rasa.DBL.csproj @@ -2,15 +2,14 @@ Rasa.NET DBL - net5.0 + net7.0 Rasa.DBL Rasa.DBL - 2.1.0 false false false Rasa - 9.0 + 10.0 diff --git a/src/Rasa.DBL/Repositories/Auth/Account/AuthAccountRepository.cs b/src/Rasa.DBL/Repositories/Auth/Account/AuthAccountRepository.cs index 318705a6..447830b6 100644 --- a/src/Rasa.DBL/Repositories/Auth/Account/AuthAccountRepository.cs +++ b/src/Rasa.DBL/Repositories/Auth/Account/AuthAccountRepository.cs @@ -25,14 +25,8 @@ public AuthAccountRepository(AuthContext dbContext, IRandomNumberService randomN public void Create(string email, string userName, string password) { - if (string.IsNullOrEmpty(email)) - { - throw new ArgumentNullException(nameof(email)); - } - if (string.IsNullOrEmpty(userName)) - { - throw new ArgumentNullException(nameof(userName)); - } + ArgumentException.ThrowIfNullOrEmpty(email); + ArgumentException.ThrowIfNullOrEmpty(userName); var salt = CreateSalt(); var hashedPassword = Hash(password ?? string.Empty, salt); diff --git a/src/Rasa.DBL/databasesettings.json b/src/Rasa.DBL/databasesettings.json index dc05f291..d63e6793 100644 --- a/src/Rasa.DBL/databasesettings.json +++ b/src/Rasa.DBL/databasesettings.json @@ -1,6 +1,6 @@ { "Databases": { - "Provider": "MySql", + "Provider": "Sqlite", "Auth": { "Host": "localhost", "Port": 3306, diff --git a/src/Rasa.Game/Game/Client.cs b/src/Rasa.Game/Game/Client.cs index 34044f2d..7cfda511 100644 --- a/src/Rasa.Game/Game/Client.cs +++ b/src/Rasa.Game/Game/Client.cs @@ -1,440 +1,436 @@ using System; +using System.Buffers; using System.Collections.Generic; using System.Diagnostics; using System.IO; -using System.Net.Sockets; +using System.Net; using System.Text; -namespace Rasa.Game +namespace Rasa.Game; + +using Rasa.Cryptography; +using Rasa.Data; +using Rasa.Game.Handlers; +using Rasa.Managers; +using Rasa.Memory; +using Rasa.Networking; +using Rasa.Packets; +using Rasa.Packets.Protocol; +using Rasa.Repositories.Char; +using Rasa.Repositories.UnitOfWork; +using Rasa.Structures; +using Rasa.Structures.Char; + +public class Client { - using Cryptography; - using Data; - using Handlers; - using Managers; - using Memory; - using Networking; - using Packets; - using Packets.Protocol; - using Repositories.Char; - using Repositories.UnitOfWork; - using Structures; - using Structures.Char; - - public class Client - { - private readonly IGameUnitOfWorkFactory _gameUnitOfWorkFactory; - - private readonly ICharacterManager _characterManager; + private readonly IGameUnitOfWorkFactory _gameUnitOfWorkFactory; - public const int LengthSize = 2; + private readonly ICharacterManager _characterManager; - public Server Server { get; private set; } - public LengthedSocket Socket { get; private set; } - public ClientCryptData Data { get; private set; } - public GameAccountEntry AccountEntry { get; private set; } - public ClientState State { get; set; } - public Manifestation Player { get; set; } - public uint[] SendSequence { get; } = new uint[256]; - public uint[] ReceiveSequence { get; } = new uint[256]; + public const int LengthSize = 2; - private readonly object _clientLock = new(); - private readonly ClientPacketHandler _handler; - private readonly PacketQueue _packetQueue = new(); - private readonly NonContiguousMemoryStream _incomingDataQueue = new(); + public Server Server { get; private set; } + public AsyncLengthedSocket Socket { get; private set; } + public ClientCryptData Data { get; private set; } + public GameAccountEntry AccountEntry { get; private set; } + public ClientState State { get; set; } + public Manifestation Player { get; set; } + public uint[] SendSequence { get; } = new uint[256]; + public uint[] ReceiveSequence { get; } = new uint[256]; + private readonly object _clientLock = new(); + private readonly ClientPacketHandler _handler; + private readonly PacketQueue _packetQueue = new(); + private readonly NonContiguousMemoryStream _incomingDataQueue = new(); - private static PacketRouter PacketRouter { get; } = new PacketRouter(); - public static Type GetPacketType(GameOpcode opcode) - { - return PacketRouter.GetPacketType(opcode); - } + private static PacketRouter PacketRouter { get; } = new PacketRouter(); - public Client( - IGameUnitOfWorkFactory gameUnitOfWorkFactory, - ICharacterManager characterManager, - ClientPacketHandler handler) - { - _gameUnitOfWorkFactory = gameUnitOfWorkFactory; - _characterManager = characterManager; + public static Type GetPacketType(GameOpcode opcode) + { + return PacketRouter.GetPacketType(opcode); + } - _handler = handler; - _handler.RegisterClient(this); - } + public Client( + IGameUnitOfWorkFactory gameUnitOfWorkFactory, + ICharacterManager characterManager, + ClientPacketHandler handler) + { + _gameUnitOfWorkFactory = gameUnitOfWorkFactory; + _characterManager = characterManager; - public void RegisterAtServer(Server server, LengthedSocket socket, ClientCryptData cryptData) - { - Socket = socket; - Data = cryptData; - Server = server; + _handler = handler; + _handler.RegisterClient(this); + } - State = ClientState.Connected; + public void RegisterAtServer(Server server, AsyncLengthedSocket socket, ClientCryptData cryptData) + { + Socket = socket; + Data = cryptData; + Server = server; - Socket.OnError += OnError; - Socket.OnReceive += OnReceive; - Socket.OnEncrypt += OnEncrypt; - Socket.OnDecrypt += OnDecrypt; + State = ClientState.Connected; - Socket.ReceiveAsync(); + Socket.OnError += OnError; + Socket.OnReceive += OnReceive; + Socket.Start(); - for (var i = 0; i < 256; ++i) - SendSequence[i] = 1; + for (var i = 0; i < 256; ++i) + SendSequence[i] = 1; - Logger.WriteLog(LogType.Network, "*** Client connected from {0}", Socket.RemoteAddress); - } + Logger.WriteLog(LogType.Network, "*** Client connected from {0}", Socket.RemoteAddress); + } - public void Update(long delta) + public void Update(long delta) + { + foreach (var protocolPacket in DecodeIncomingPackets()) { - foreach (var protocolPacket in DecodeIncomingPackets()) + try { - try - { - HandleProtocolPacket(protocolPacket); - } - catch (InvalidClientMessageException) - { - Close(); - } + HandleProtocolPacket(protocolPacket); } + catch (InvalidClientMessageException) + { + Close(); + } + } - IBasePacket packet; + IBasePacket packet; - while ((packet = _packetQueue.PopOutgoing()) != null) - SendPacket(packet); - } + while ((packet = _packetQueue.PopOutgoing()) != null) + SendPacket(packet); + } + + public void Close() + { + if (State == ClientState.Disconnected) + return; - public void Close(bool sendPacket = true) + lock (_clientLock) { if (State == ClientState.Disconnected) return; - lock (_clientLock) - { - if (State == ClientState.Disconnected) - return; + Logger.WriteLog(LogType.Network, "*** Client disconnected! Ip: {0}", Socket.RemoteAddress); - Logger.WriteLog(LogType.Network, "*** Client disconnected! Ip: {0}", Socket.RemoteAddress); + State = ClientState.Disconnected; - State = ClientState.Disconnected; + Socket.Close(); - Socket.Close(); + Server.Disconnect(this); - Server.Disconnect(this); - - SaveCharacter(); - } + SaveCharacter(); } + } - public void CallMethod(ulong entityId, PythonPacket packet) - { - SendMessage(new CallMethodMessage(entityId, packet)); - } + public void CallMethod(ulong entityId, PythonPacket packet) + { + SendMessage(new CallMethodMessage(entityId, packet)); + } - public void CallMethod(SysEntity entityId, PythonPacket packet) - { - SendMessage(new CallMethodMessage((ulong)entityId, packet)); - } + public void CallMethod(SysEntity entityId, PythonPacket packet) + { + SendMessage(new CallMethodMessage((ulong)entityId, packet)); + } - public void SendMessage(IClientMessage message, bool compress = false, byte channel = 0, bool delay = true) - { - var protocolPacket = new ProtocolPacket(message, message.Type, compress, channel); + public void SendMessage(IClientMessage message, bool compress = false, byte channel = 0, bool delay = true) + { + var protocolPacket = new ProtocolPacket(message, message.Type, compress, channel); - if (!delay) - SendPacket(protocolPacket); - else - _packetQueue.EnqueueOutgoing(protocolPacket); - } + if (!delay) + SendPacket(protocolPacket); + else + _packetQueue.EnqueueOutgoing(protocolPacket); + } - public void SendPacket(IBasePacket packet) + public void SendPacket(IBasePacket packet) + { + if (packet is not ProtocolPacket pPacket) { - var pPacket = packet as ProtocolPacket; - if (pPacket == null) - { - Debugger.Break(); - return; - } - - if (pPacket.Channel != 0) - pPacket.SequenceNumber = SendSequence[pPacket.Channel]++; - - Socket.Send(pPacket); + Debugger.Break(); + return; } - private void HandleProtocolPacket(ProtocolPacket protocolPacket) - { - switch (protocolPacket.Type) - { - case ClientMessageOpcode.Login: - var loginMsg = GetMessageAs(protocolPacket); - - if (loginMsg.Version.Length != 8 || loginMsg.Version != "1.16.5.0") - { - Logger.WriteLog(LogType.Error, $"Client version mismatch: Server: 1.16.5.0 | Client: {loginMsg.Version}"); + if (pPacket.Channel != 0) + pPacket.SequenceNumber = SendSequence[pPacket.Channel]++; - SendMessage(new LoginResponseMessage - { - ErrorCode = LoginErrorCodes.VersionMismatch, - Subtype = LoginResponseMessageSubtype.Failed - }, delay: false); + // Write packet to buffer + var buffer = ArrayPool.Shared.Rent(AsyncLengthedSocket.MaxDataSize); + var writer = new BinaryWriter(new MemoryStream(buffer, true)); - return; - } + packet.Write(writer); - var loginEntry = Server.AuthenticateClient(this, loginMsg.AccountId, loginMsg.OneTimeKey); - if (loginEntry == null) - { - Logger.WriteLog(LogType.Error, "Client with ip: {0} tried to log in with invalid session data! User Id: {1} | OneTimeKey: {2}", Socket.RemoteAddress, loginMsg.AccountId, loginMsg.OneTimeKey); + // Determine the required padding + var length = (int)writer.BaseStream.Position; + var paddingCount = (byte)(8 - length % 8); - SendMessage(new LoginResponseMessage - { - ErrorCode = LoginErrorCodes.AuthenticationFailed, - Subtype = LoginResponseMessageSubtype.Failed - }, delay: false); + // Create the padded buffer + var paddedBuffer = ArrayPool.Shared.Rent(length + paddingCount); + paddedBuffer[0] = paddingCount; - return; - } + // Copy the data after the padding + Array.Copy(buffer, 0, paddedBuffer, paddingCount, length); - using (var unitOfWork = _gameUnitOfWorkFactory.CreateChar()) - { - unitOfWork.GameAccounts.CreateOrUpdate(loginEntry.Id, loginEntry.Name, loginEntry.Email); + length += paddingCount; - if (Server.IsBanned(loginMsg.AccountId)) - { - Logger.WriteLog(LogType.Error, "Client with ip: {0} tried to log in while the account is banned! User Id: {1}", Socket.RemoteAddress, loginMsg.AccountId); + // Encrypt the data + GameCryptManager.Encrypt(paddedBuffer, 0, ref length, length, Data); - SendMessage(new LoginResponseMessage - { - ErrorCode = LoginErrorCodes.AccountLocked, - Subtype = LoginResponseMessageSubtype.Failed - }, delay: false); + // Send on the socket + Socket.Send(paddedBuffer, 0, length); - return; - } + // Free up the arrays + ArrayPool.Shared.Return(buffer); + ArrayPool.Shared.Return(paddedBuffer); + } - if (Server.IsAlreadyLoggedIn(loginMsg.AccountId)) - { - Logger.WriteLog(LogType.Error, "Client with ip: {0} tried to log in while the account is being played on! User Id: {1}", Socket.RemoteAddress, loginMsg.AccountId); + private void HandleProtocolPacket(ProtocolPacket protocolPacket) + { + switch (protocolPacket.Type) + { + case ClientMessageOpcode.Login: + var loginMsg = GetMessageAs(protocolPacket); - SendMessage(new LoginResponseMessage - { - ErrorCode = LoginErrorCodes.AlreadyLoggedIn, - Subtype = LoginResponseMessageSubtype.Failed - }, delay: false); + if (loginMsg.Version.Length != 8 || loginMsg.Version != "1.16.5.0") + { + Logger.WriteLog(LogType.Error, $"Client version mismatch: Server: 1.16.5.0 | Client: {loginMsg.Version}"); - return; - } + SendMessage(new LoginResponseMessage + { + ErrorCode = LoginErrorCodes.VersionMismatch, + Subtype = LoginResponseMessageSubtype.Failed + }, delay: false); - LoadGameAccountEntry(unitOfWork, loginEntry.Id); + return; + } - unitOfWork.GameAccounts.UpdateLoginData(loginEntry.Id, Socket.RemoteAddress); - unitOfWork.Complete(); - } + var loginEntry = Server.AuthenticateClient(this, loginMsg.AccountId, loginMsg.OneTimeKey); + if (loginEntry == null) + { + Logger.WriteLog(LogType.Error, "Client with ip: {0} tried to log in with invalid session data! User Id: {1} | OneTimeKey: {2}", Socket.RemoteAddress, loginMsg.AccountId, loginMsg.OneTimeKey); SendMessage(new LoginResponseMessage { - AccountId = loginMsg.AccountId, - Subtype = LoginResponseMessageSubtype.Success - }); + ErrorCode = LoginErrorCodes.AuthenticationFailed, + Subtype = LoginResponseMessageSubtype.Failed + }, delay: false); - State = ClientState.LoggedIn; + return; + } - _characterManager.StartCharacterSelection(this); - break; + using (var unitOfWork = _gameUnitOfWorkFactory.CreateChar()) + { + unitOfWork.GameAccounts.CreateOrUpdate(loginEntry.Id, loginEntry.Name, loginEntry.Email); - case ClientMessageOpcode.Move: - if (Player == null) + if (Server.IsBanned(loginMsg.AccountId)) { - return; - } + Logger.WriteLog(LogType.Error, "Client with ip: {0} tried to log in while the account is banned! User Id: {1}", Socket.RemoteAddress, loginMsg.AccountId); + + SendMessage(new LoginResponseMessage + { + ErrorCode = LoginErrorCodes.AccountLocked, + Subtype = LoginResponseMessageSubtype.Failed + }, delay: false); - var moveMessage = GetMessageAs(protocolPacket); - if (moveMessage.Movement == null) - { return; } - Player.Position = moveMessage.Movement.Position; - Player.Rotation = moveMessage.Movement.ViewDirection.X; - break; + if (Server.IsAlreadyLoggedIn(loginMsg.AccountId)) + { + Logger.WriteLog(LogType.Error, "Client with ip: {0} tried to log in while the account is being played on! User Id: {1}", Socket.RemoteAddress, loginMsg.AccountId); - case ClientMessageOpcode.CallServerMethod: - var csmPacket = GetMessageAs(protocolPacket); + SendMessage(new LoginResponseMessage + { + ErrorCode = LoginErrorCodes.AlreadyLoggedIn, + Subtype = LoginResponseMessageSubtype.Failed + }, delay: false); - if (!csmPacket.ReadPacket()) - { - Close(true); return; } - PacketRouter.RoutePacket(_handler, csmPacket.Packet); - break; + LoadGameAccountEntry(unitOfWork, loginEntry.Id); - case ClientMessageOpcode.Ping: - var pingMessage = GetMessageAs(protocolPacket); + unitOfWork.GameAccounts.UpdateLoginData(loginEntry.Id, (Socket.RemoteAddress as IPEndPoint).Address); + unitOfWork.Complete(); + } - SendMessage(pingMessage, delay: false); - break; - } - } + SendMessage(new LoginResponseMessage + { + AccountId = loginMsg.AccountId, + Subtype = LoginResponseMessageSubtype.Success + }); - private T GetMessageAs(ProtocolPacket protocolPacket) - where T : class, IClientMessage - { - if (protocolPacket.Message is T message) - { - return message; - } - throw new InvalidClientMessageException(); - } + State = ClientState.LoggedIn; - public bool IsAuthenticated() - { - return State != ClientState.Connected && State != ClientState.Disconnected; - } + _characterManager.StartCharacterSelection(this); + break; - #region Socketing - private void OnEncrypt(BufferData data, ref int length) - { - var paddingCount = (byte) (8 - length % 8); + case ClientMessageOpcode.Move: + if (Player == null) + { + return; + } - var tempArray = BufferManager.RequestBuffer(); + var moveMessage = GetMessageAs(protocolPacket); + if (moveMessage.Movement == null) + { + return; + } - tempArray[0] = paddingCount; + Player.Position = moveMessage.Movement.Position; + Player.Rotation = moveMessage.Movement.ViewDirection.X; + break; - BufferData.Copy(data, data.Offset, tempArray, paddingCount, length); + case ClientMessageOpcode.CallServerMethod: + var csmPacket = GetMessageAs(protocolPacket); - length += paddingCount; + if (!csmPacket.ReadPacket()) + { + Close(); + return; + } - GameCryptManager.Encrypt(tempArray.Buffer, tempArray.BaseOffset, ref length, length, Data); + PacketRouter.RoutePacket(_handler, csmPacket.Packet); + break; - BufferData.Copy(tempArray, 0, data, data.Offset, length); + case ClientMessageOpcode.Ping: + var pingMessage = GetMessageAs(protocolPacket); - BufferManager.FreeBuffer(tempArray); + SendMessage(pingMessage, delay: false); + break; } + } - private bool OnDecrypt(BufferData data) - { - var result = GameCryptManager.Decrypt(data.Buffer, data.BaseOffset + data.Offset, data.RemainingLength, Data); - if (!result) - return false; + private static T GetMessageAs(ProtocolPacket protocolPacket) + where T : class, IClientMessage + { + if (protocolPacket.Message is T message) + return message; - var blowfishPadding = data[data.Offset] & 0xF; - if (blowfishPadding > 8) - throw new Exception("More than 8 bytes of blowfish padding was added to the packet?"); + throw new InvalidClientMessageException(); + } - data.Offset += blowfishPadding; + public bool IsAuthenticated() + { + return State != ClientState.Connected && State != ClientState.Disconnected; + } - return true; - } + private void OnError() => Close(); - private void OnError(SocketAsyncEventArgs args) - { - Close(false); - } - - private void OnReceive(BufferData data) - { - _incomingDataQueue.CopyFromArray(data.Buffer, data.BaseOffset + data.Offset, data.RemainingLength); - } + private void OnReceive(NonContiguousMemoryStream incomingStream, int length) + { + var buffer = ArrayPool.Shared.Rent(length); + _incomingDataQueue.Read(buffer, 0, length); - private IEnumerable DecodeIncomingPackets() - { - ProtocolPacket packet; + var result = GameCryptManager.Decrypt(buffer, 0, length, Data); + if (!result) + throw new Exception("Unable to decrypt packet!"); - while ((packet = DecodeNextPacket()) != null) - yield return packet; + var blowfishPadding = buffer[0] & 0xF; + if (blowfishPadding > 8) + throw new Exception("More than 8 bytes of blowfish padding was added to the packet?"); - yield break; - } + incomingStream.Write(buffer, blowfishPadding, length - blowfishPadding); - private ProtocolPacket DecodeNextPacket() - { - // If there is not enough data to read the packet size at all, then stop processing - if (_incomingDataQueue.Length < 2) - return null; + ArrayPool.Shared.Return(buffer); + } - using var br = new BinaryReader(_incomingDataQueue, Encoding.UTF8, true); + private IEnumerable DecodeIncomingPackets() + { + ProtocolPacket packet; - // Peek the packet size to determine if the whole packet has arrived - var startPosition = _incomingDataQueue.Position; + while ((packet = DecodeNextPacket()) != null) + yield return packet; - // Read the size of the next packet - var packetSize = br.ReadUInt16(); + yield break; + } - // Rewind the stream to the starting position - _incomingDataQueue.Position = startPosition; + private ProtocolPacket DecodeNextPacket() + { + // If there is not enough data to read the packet size at all, then stop processing + if (_incomingDataQueue.Length < 2) + return null; - // If the packet is fragmented and not all the fragments has arrived yet, then stop processing - if (packetSize > _incomingDataQueue.Length) - return null; + using var br = new BinaryReader(_incomingDataQueue, Encoding.UTF8, true); - // Construct and the packet - var rawPacket = new ProtocolPacket(); + // Peek the packet size to determine if the whole packet has arrived + var startPosition = _incomingDataQueue.Position; - rawPacket.Read(br); + // Read the size of the next packet + var packetSize = br.ReadUInt16(); - // Check for overreading or underreading the packet - if (_incomingDataQueue.Position != startPosition + packetSize) - throw new Exception($"ProtocolPacket over or under read! Start position: {startPosition} | Packet size: {packetSize} | End position: {_incomingDataQueue.Position}!"); + // Rewind the stream to the starting position + _incomingDataQueue.Position = startPosition; - // Advance the stream by removing the already processed data - _incomingDataQueue.RemoveBytes(packetSize); + // If the packet is fragmented and not all the fragments has arrived yet, then stop processing + if (packetSize > _incomingDataQueue.Length) + return null; - // Throw away any packet that came out of order, if it came on a channel - if (rawPacket.Channel != 0) - { - // If an out of sequence packet arrived, then throw it away - if (rawPacket.SequenceNumber < ReceiveSequence[rawPacket.Channel]) - { - Debugger.Break(); // todo: test and remove later + // Construct and the packet + var rawPacket = new ProtocolPacket(); - return null; - } + rawPacket.Read(br); - // Update the receive sequence for the channel - ReceiveSequence[rawPacket.Channel] = rawPacket.SequenceNumber; - } + // Check for overreading or underreading the packet + if (_incomingDataQueue.Position != startPosition + packetSize) + throw new Exception($"ProtocolPacket over or under read! Start position: {startPosition} | Packet size: {packetSize} | End position: {_incomingDataQueue.Position}!"); + + // Advance the stream by removing the already processed data + _incomingDataQueue.RemoveBytes(packetSize); - // Some internal send timeout check, skip the packet - if (rawPacket.Type == ClientMessageOpcode.None) + // Throw away any packet that came out of order, if it came on a channel + if (rawPacket.Channel != 0) + { + // If an out of sequence packet arrived, then throw it away + if (rawPacket.SequenceNumber < ReceiveSequence[rawPacket.Channel]) { - if (rawPacket.Size != 4) - Debugger.Break(); // If it's not send timeout check, let's investigate... + Debugger.Break(); // todo: test and remove later return null; } - - return rawPacket; + + // Update the receive sequence for the channel + ReceiveSequence[rawPacket.Channel] = rawPacket.SequenceNumber; } - #endregion - public void SaveCharacter() + // Some internal send timeout check, skip the packet + if (rawPacket.Type == ClientMessageOpcode.None) { - var player = Player; - if (player == null) - { - return; - } + if (rawPacket.Size != 4) + Debugger.Break(); // If it's not send timeout check, let's investigate... - using var unitOfWork = _gameUnitOfWorkFactory.CreateChar(); - unitOfWork.Characters.SaveCharacter(player); - unitOfWork.Complete(); + return null; } + + return rawPacket; + } - public void ReloadGameAccountEntry() + public void SaveCharacter() + { + var player = Player; + if (player == null) { - if (AccountEntry == null) - { - throw new InvalidOperationException("Client must be initialized by handling a login packet first."); - } - - using var unitOfWork = _gameUnitOfWorkFactory.CreateChar(); - LoadGameAccountEntry(unitOfWork, AccountEntry.Id); + return; } - private void LoadGameAccountEntry(ICharUnitOfWork unitOfWork, uint id) + using var unitOfWork = _gameUnitOfWorkFactory.CreateChar(); + unitOfWork.Characters.SaveCharacter(player); + unitOfWork.Complete(); + } + + public void ReloadGameAccountEntry() + { + if (AccountEntry == null) { - AccountEntry = unitOfWork.GameAccounts.Get(id); + throw new InvalidOperationException("Client must be initialized by handling a login packet first."); } + + using var unitOfWork = _gameUnitOfWorkFactory.CreateChar(); + LoadGameAccountEntry(unitOfWork, AccountEntry.Id); + } + + private void LoadGameAccountEntry(ICharUnitOfWork unitOfWork, uint id) + { + AccountEntry = unitOfWork.GameAccounts.Get(id); } } diff --git a/src/Rasa.Game/Game/ClientFactory.cs b/src/Rasa.Game/Game/ClientFactory.cs index 4ba9e91a..80b46bae 100644 --- a/src/Rasa.Game/Game/ClientFactory.cs +++ b/src/Rasa.Game/Game/ClientFactory.cs @@ -1,25 +1,24 @@ using System; using Microsoft.Extensions.DependencyInjection; -namespace Rasa.Game +namespace Rasa.Game; + +using Rasa.Cryptography; +using Rasa.Networking; + +public class ClientFactory : IClientFactory { - using Cryptography; - using Networking; + private readonly IServiceProvider _serviceProvider; - public class ClientFactory : IClientFactory + public ClientFactory(IServiceProvider serviceProvider) { - private readonly IServiceProvider _serviceProvider; - - public ClientFactory(IServiceProvider serviceProvider) - { - _serviceProvider = serviceProvider; - } + _serviceProvider = serviceProvider; + } - public Client Create(LengthedSocket socket, ClientCryptData data, Server server) - { - var client = _serviceProvider.GetService(); - client.RegisterAtServer(server, socket, data); - return client; - } + public Client Create(AsyncLengthedSocket socket, ClientCryptData data, Server server) + { + var client = _serviceProvider.GetService(); + client.RegisterAtServer(server, socket, data); + return client; } } \ No newline at end of file diff --git a/src/Rasa.Game/Game/IClientFactory.cs b/src/Rasa.Game/Game/IClientFactory.cs index 90e3c1ae..121f93e0 100644 --- a/src/Rasa.Game/Game/IClientFactory.cs +++ b/src/Rasa.Game/Game/IClientFactory.cs @@ -1,10 +1,9 @@ -namespace Rasa.Game -{ - using Cryptography; - using Networking; +namespace Rasa.Game; + +using Rasa.Cryptography; +using Rasa.Networking; - public interface IClientFactory - { - Client Create(LengthedSocket socket, ClientCryptData data, Server server); - } +public interface IClientFactory +{ + Client Create(AsyncLengthedSocket socket, ClientCryptData data, Server server); } \ No newline at end of file diff --git a/src/Rasa.Game/Game/Server.cs b/src/Rasa.Game/Game/Server.cs index 7aa12177..2a141e28 100644 --- a/src/Rasa.Game/Game/Server.cs +++ b/src/Rasa.Game/Game/Server.cs @@ -3,427 +3,358 @@ using System.Linq; using System.Net; using System.Net.Sockets; + using Microsoft.Extensions.Hosting; -namespace Rasa.Game +namespace Rasa.Game; + +using Rasa.Commands; +using Rasa.Communicator; +using Rasa.Config; +using Rasa.Hosting; +using Rasa.Login; +using Rasa.Memory; +using Rasa.Networking; +using Rasa.Packets; +using Rasa.Queue; +using Rasa.Structures; +using Rasa.Threading; +using Rasa.Timer; + +public class Server : ILoopable, IRasaServer { - using Commands; - using Config; - using Data; - using Hosting; - using Login; - using Memory; - using Networking; - using Packets; - using Packets.Communicator; - using Queue; - using Structures; - using Threading; - using Timer; - - public class Server : ILoopable, IRasaServer + private readonly IHostApplicationLifetime _hostApplicationLifetime; + private readonly IClientFactory _clientFactory; + + public string ServerType { get; } = "Game"; + + public const int MainLoopTime = 100; // Milliseconds + public const int SendBufferSize = 512; + + public Config Config { get; private set; } + public IPAddress PublicAddress { get; } + public Communicator AuthCommunicator { get; } = new(CommunicatorType.Client); + public AsyncLengthedSocket ListenerSocket { get; } = new(AsyncLengthedSocket.HeaderSizeType.Dword, false); + public QueueManager QueueManager { get; private set; } + public LoginManager LoginManager { get; } = new(); + public List Clients { get; } = new(); + public Dictionary IncomingClients { get; } = new(); + public MainLoop Loop { get; } + public Timer Timer { get; } = new(); + public bool Running => Loop != null && Loop.Running; + public bool IsFull => CurrentPlayers >= Config.ServerInfoConfig.MaxPlayers; + public ushort CurrentPlayers { get; set; } + + private readonly List _clientsToRemove = new List(); + + public Server(IHostApplicationLifetime hostApplicationLifetime, IClientFactory clientFactory) { - private readonly IHostApplicationLifetime _hostApplicationLifetime; - private readonly IClientFactory _clientFactory; - - public string ServerType { get; } = "Game"; - - public const int MainLoopTime = 100; // Milliseconds - - public Config Config { get; private set; } - public IPAddress PublicAddress { get; } - public LengthedSocket AuthCommunicator { get; private set; } - public LengthedSocket ListenerSocket { get; private set; } - public QueueManager QueueManager { get; private set; } - public LoginManager LoginManager { get; set; } = new LoginManager(); - public List Clients { get; } = new List(); - public Dictionary IncomingClients { get; } = new Dictionary(); - public MainLoop Loop { get; } - public Timer Timer { get; } = new Timer(); - public bool Running => Loop != null && Loop.Running; - public bool IsFull => CurrentPlayers >= Config.ServerInfoConfig.MaxPlayers; - public ushort CurrentPlayers { get; set; } - - private readonly List _clientsToRemove = new List(); - private readonly PacketRouter _router = new PacketRouter(); - - public Server(IHostApplicationLifetime hostApplicationLifetime, IClientFactory clientFactory) - { - _hostApplicationLifetime = hostApplicationLifetime; - _clientFactory = clientFactory; + _hostApplicationLifetime = hostApplicationLifetime; + _clientFactory = clientFactory; - Configuration.OnLoad += ConfigLoaded; - Configuration.OnReLoad += ConfigReLoaded; - Configuration.Load(); + Configuration.OnLoad += ConfigLoaded; + Configuration.OnReLoad += ConfigReLoaded; + Configuration.Load(); - Loop = new MainLoop(this, MainLoopTime); + Loop = new MainLoop(this, MainLoopTime); - PublicAddress = IPAddress.Parse(Config.GameConfig.PublicAddress); + PublicAddress = IPAddress.Parse(Config.GameConfig.PublicAddress); - LengthedSocket.InitializeEventArgsPool(Config.SocketAsyncConfig.MaxClients * Config.SocketAsyncConfig.ConcurrentOperationsByClient); + CommandProcessor.RegisterCommand("exit", ProcessExitCommand); + CommandProcessor.RegisterCommand("reload", ProcessReloadCommand); + } - BufferManager.Initialize(Config.SocketAsyncConfig.BufferSize, Config.SocketAsyncConfig.MaxClients, Config.SocketAsyncConfig.ConcurrentOperationsByClient); + ~Server() + { + Shutdown(); + } - CommandProcessor.RegisterCommand("exit", ProcessExitCommand); - CommandProcessor.RegisterCommand("reload", ProcessReloadCommand); - } + #region Configuration + private static void ConfigReLoaded() + { + Logger.WriteLog(LogType.Initialize, "Config file reloaded by external change!"); - ~Server() - { - Shutdown(); - } + // Totally reload the configuration, because it's automatic reload case can only handle one reload. Our code's bug? + Configuration.Load(); + } - #region Configuration - private static void ConfigReLoaded() - { - Logger.WriteLog(LogType.Initialize, "Config file reloaded by external change!"); + private void ConfigLoaded() + { + Config = new Config(); + Configuration.Bind(Config); - // Totally reload the configuration, because it's automatic reload case can only handle one reload. Our code's bug? - Configuration.Load(); - } + Logger.UpdateConfig(Config.LoggerConfig); + } + #endregion - private void ConfigLoaded() - { - Config = new Config(); - Configuration.Bind(Config); + public void Disconnect(Client client) + { + lock (_clientsToRemove) + _clientsToRemove.Add(client); + } - Logger.UpdateConfig(Config.LoggerConfig); - } - #endregion + public void MainLoop(long delta) + { + Timer.Update(delta); - public void Disconnect(Client client) - { - lock (_clientsToRemove) - _clientsToRemove.Add(client); - } + if (Clients.Count == 0) + return; - public void MainLoop(long delta) + lock (Clients) { - Timer.Update(delta); - - if (Clients.Count == 0) - return; + foreach (var client in Clients) + client.Update(delta); - lock (Clients) + if (_clientsToRemove.Count > 0) { - foreach (var client in Clients) - client.Update(delta); - - if (_clientsToRemove.Count > 0) + lock (_clientsToRemove) { - lock (_clientsToRemove) - { - foreach (var client in _clientsToRemove) - Clients.Remove(client); + foreach (var client in _clientsToRemove) + Clients.Remove(client); - _clientsToRemove.Clear(); - } + _clientsToRemove.Clear(); } } } + } - #region Socketing - - public bool Start() + public bool Start() + { + // If no config file has been found, these values are 0 by default + if (Config.GameConfig.Port == 0 || Config.GameConfig.Backlog == 0) { - // If no config file has been found, these values are 0 by default - if (Config.GameConfig.Port == 0 || Config.GameConfig.Backlog == 0) - { - Logger.WriteLog(LogType.Error, "Invalid config values!"); - return false; - } - - Loop.Start(); - - SetupCommunicator(); - - try - { - ListenerSocket = new LengthedSocket(SizeType.Dword, false); - ListenerSocket.OnError += OnError; - ListenerSocket.OnAccept += OnAccept; - ListenerSocket.Bind(new IPEndPoint(IPAddress.Any, Config.GameConfig.Port)); - ListenerSocket.Listen(Config.GameConfig.Backlog); - } - catch (Exception e) - { - Logger.WriteLog(LogType.Error, "Unable to create or start listening on the client socket! Exception:"); - Logger.WriteLog(LogType.Error, e); - - return false; - } - - LoginManager.OnLogin += OnLogin; - - QueueManager = new QueueManager(this); - - ListenerSocket.AcceptAsync(); - - Logger.WriteLog(LogType.Network, "*** Listening for clients on port {0}", Config.GameConfig.Port); - - Timer.Add("SessionExpire", 10000, true, () => - { - var toRemove = new List(); - - lock (IncomingClients) - { - toRemove.AddRange(IncomingClients.Where(ic => ic.Value.ExpireTime < DateTime.Now).Select(ic => ic.Key)); + Logger.WriteLog(LogType.Error, "Invalid config values!"); + return false; + } - foreach (var rem in toRemove) - IncomingClients.Remove(rem); - } - }); + Loop.Start(); - Timer.Add("QueueManagerUpdate", Config.QueueConfig.UpdateInterval, true, () => - { - QueueManager.Update(Config.ServerInfoConfig.MaxPlayers - CurrentPlayers); - }); + SetupCommunicator(); - return true; - } + QueueManager = new QueueManager(this); + LoginManager.OnLogin += OnLogin; - private void OnLogin(LoginClient client) + try { - lock (Clients) - { - var newClient = _clientFactory.Create(client.Socket, client.Data, this); - Clients.Add(newClient); - } + + ListenerSocket.OnAccept += OnAccept; + ListenerSocket.StartListening(new IPEndPoint(IPAddress.Any, Config.GameConfig.Port), Config.GameConfig.Backlog); } - - private static void OnError(SocketAsyncEventArgs args) + catch (Exception e) { - if (args.LastOperation == SocketAsyncOperation.Accept && args.AcceptSocket != null && args.AcceptSocket.Connected) - args.AcceptSocket.Shutdown(SocketShutdown.Both); - } + Logger.WriteLog(LogType.Error, "Unable to create or start listening on the client socket! Exception:"); + Logger.WriteLog(LogType.Error, e); - private void OnAccept(LengthedSocket newSocket) - { - ListenerSocket.AcceptAsync(); - - if (newSocket == null) - return; - - LoginManager.LoginSocket(newSocket); + return false; } - public LoginAccountEntry AuthenticateClient(Client client, uint accountId, uint oneTimeKey) + Logger.WriteLog(LogType.Network, "*** Listening for clients on port {0}", Config.GameConfig.Port); + + Timer.Add("SessionExpire", 10000, true, () => { + var toRemove = new List(); + lock (IncomingClients) { - if (!IncomingClients.ContainsKey(accountId)) - return null; + toRemove.AddRange(IncomingClients.Where(ic => ic.Value.ExpireTime < DateTime.Now).Select(ic => ic.Key)); - var entry = IncomingClients[accountId]; - if (entry == null || entry.OneTimeKey != oneTimeKey) - return null; + foreach (var rem in toRemove) + IncomingClients.Remove(rem); + } + }); - IncomingClients.Remove(accountId); + Timer.Add("QueueManagerUpdate", Config.QueueConfig.UpdateInterval, true, () => + { + QueueManager.Update(Config.ServerInfoConfig.MaxPlayers - CurrentPlayers); + }); - return entry; - } - } + return true; + } - public bool IsBanned(uint accountId) + private void OnLogin(LoginClient client) + { + lock (Clients) { - return false; // TODO + var newClient = _clientFactory.Create(client.Socket, client.Data, this); + Clients.Add(newClient); } + } - public bool IsAlreadyLoggedIn(uint accountId) - { - lock (Clients) - foreach (var client in Clients) - if (client.IsAuthenticated() && client.AccountEntry.Id == accountId) - return true; + private void OnAccept(AsyncLengthedSocket newSocket) + { + if (newSocket == null) + return; - return false; - } + LoginManager.LoginSocket(newSocket); + } - public void Shutdown() + public LoginAccountEntry AuthenticateClient(Client client, uint accountId, uint oneTimeKey) + { + lock (IncomingClients) { - AuthCommunicator?.Close(); - AuthCommunicator = null; + if (!IncomingClients.ContainsKey(accountId)) + return null; - ListenerSocket?.Close(); - ListenerSocket = null; + var entry = IncomingClients[accountId]; + if (entry == null || entry.OneTimeKey != oneTimeKey) + return null; - Loop.Stop(); + IncomingClients.Remove(accountId); + + return entry; } - #endregion + } - #region Communicator - private void SetupCommunicator() - { - if (Config.CommunicatorConfig.Port == 0 || Config.CommunicatorConfig.Address == null) - { - Logger.WriteLog(LogType.Error, "Invalid Communicator config data! Can't connect!"); - return; - } + public bool IsBanned(uint accountId) + { + return false; // TODO + } - ConnectCommunicator(); - } + public bool IsAlreadyLoggedIn(uint accountId) + { + lock (Clients) + foreach (var client in Clients) + if (client.IsAuthenticated() && client.AccountEntry.Id == accountId) + return true; - public void ConnectCommunicator() - { - if (AuthCommunicator?.Connected ?? false) - AuthCommunicator?.Close(); + return false; + } - try - { - AuthCommunicator = new LengthedSocket(SizeType.Word); - AuthCommunicator.OnConnect += OnCommunicatorConnect; - AuthCommunicator.OnError += OnCommunicatorError; - AuthCommunicator.ConnectAsync(new IPEndPoint(IPAddress.Parse(Config.CommunicatorConfig.Address), Config.CommunicatorConfig.Port)); - } - catch (Exception e) - { - Logger.WriteLog(LogType.Error, "Unable to create or start listening on the Auth server socket! Retrying soon... Exception:"); - Logger.WriteLog(LogType.Error, e); - } + public void Shutdown() + { + AuthCommunicator.Close(); - Logger.WriteLog(LogType.Network, $"*** Connecting to auth server! Address: {Config.CommunicatorConfig.Address}:{Config.CommunicatorConfig.Port}"); - } + ListenerSocket.Close(); - private void OnCommunicatorError(SocketAsyncEventArgs args) - { - Timer.Add("CommReconnect", 10000, false, () => - { - if (!AuthCommunicator?.Connected ?? true) - ConnectCommunicator(); - }); + Loop.Stop(); - Logger.WriteLog(LogType.Error, "Could not connect to the Auth server! Trying again in a few seconds..."); - } + _hostApplicationLifetime.StopApplication(); + } - private void OnCommunicatorConnect(SocketAsyncEventArgs args) + #region Communicator + private void SetupCommunicator() + { + if (Config.CommunicatorConfig.Port == 0 || Config.CommunicatorConfig.Address == null) { - if (args.SocketError != SocketError.Success) - { - OnCommunicatorError(args); - return; - } + Logger.WriteLog(LogType.Error, "Invalid Communicator config data! Can't connect!"); + return; + } - Logger.WriteLog(LogType.Network, "*** Connected to the Auth Server!"); + ConnectCommunicator(); + } - AuthCommunicator.OnReceive += OnCommunicatorReceive; - AuthCommunicator.Send(new LoginRequestPacket - { - ServerId = Config.ServerInfoConfig.Id, - Password = Config.ServerInfoConfig.Password, - PublicAddress = PublicAddress - }); + public void ConnectCommunicator() + { + if (AuthCommunicator.Connected) + AuthCommunicator.Close(); - AuthCommunicator.ReceiveAsync(); + try + { + AuthCommunicator.OnConnect += OnCommunicatorConnect; + AuthCommunicator.OnError += OnCommunicatorError; + AuthCommunicator.OnLoginResponse += OnCommunicatorLoginResponse; + AuthCommunicator.OnRedirectRequest += OnCommunicatorRedirectRequest; + AuthCommunicator.OnServerInfoRequest += OnCommunicatorServerInfoRequest; + AuthCommunicator.Start(IPAddress.Parse(Config.CommunicatorConfig.Address), Config.CommunicatorConfig.Port); } - - private void OnCommunicatorReceive(BufferData data) + catch (Exception e) { - var opcode = (CommOpcode) data.Buffer[data.BaseOffset + data.Offset++]; - - var packetType = _router.GetPacketType(opcode); - if (packetType == null) - return; - - var packet = Activator.CreateInstance(packetType) as IOpcodedPacket; - if (packet == null) - return; - - packet.Read(data.GetReader()); - - _router.RoutePacket(this, packet); + Logger.WriteLog(LogType.Error, "Unable to create or start listening on the Auth server socket! Retrying soon... Exception:"); + Logger.WriteLog(LogType.Error, e); } - // ReSharper disable once UnusedMember.Local - [PacketHandler(CommOpcode.LoginResponse)] - private void MsgLoginResponse(LoginResponsePacket packet) + Logger.WriteLog(LogType.Network, $"*** Connecting to auth server! Address: {Config.CommunicatorConfig.Address}:{Config.CommunicatorConfig.Port}"); + } + + private void OnCommunicatorError() + { + Timer.Add("CommReconnect", 10000, false, () => { - if (packet.Response == CommLoginReason.Success) - { - Logger.WriteLog(LogType.Network, "Successfully authenticated with the Auth server!"); - return; - } + if (!AuthCommunicator?.Connected ?? true) + ConnectCommunicator(); + }); - AuthCommunicator?.Close(); - AuthCommunicator = null; + Logger.WriteLog(LogType.Error, "Could not connect to the Auth server! Trying again in a few seconds..."); + } - Logger.WriteLog(LogType.Error, "Could not authenticate with the Auth server! Shutting down internal communication!"); - } + private void OnCommunicatorConnect(ServerData data) + { + Logger.WriteLog(LogType.Network, "*** Connected to the Auth Server!"); - // ReSharper disable once UnusedMember.Local - // ReSharper disable once UnusedParameter.Local - [PacketHandler(CommOpcode.ServerInfoRequest)] - private void MsgGameInfoRequest(ServerInfoRequestPacket packet) + data.Id = Config.ServerInfoConfig.Id; + data.Address = PublicAddress; + data.Password = Config.ServerInfoConfig.Password; + } + + private void OnCommunicatorLoginResponse(CommunicatorActionResult result) + { + if (result == CommunicatorActionResult.Success) { - AuthCommunicator.Send(new ServerInfoResponsePacket - { - AgeLimit = Config.ServerInfoConfig.AgeLimit, - PKFlag = Config.ServerInfoConfig.PKFlag, - CurrentPlayers = CurrentPlayers, - GamePort = Config.GameConfig.Port, - QueuePort = Config.QueueConfig.Port, - MaxPlayers = (ushort) Config.SocketAsyncConfig.MaxClients - }); + Logger.WriteLog(LogType.Network, "Successfully authenticated with the Auth server!"); + return; } - // ReSharper disable once UnusedMember.Local - [PacketHandler(CommOpcode.RedirectRequest)] - private void MsgRedirectRequest(RedirectRequestPacket packet) - { - lock (IncomingClients) - { - if (IncomingClients.ContainsKey(packet.AccountId)) - IncomingClients.Remove(packet.AccountId); + AuthCommunicator.Close(); - IncomingClients.Add(packet.AccountId, new LoginAccountEntry(packet)); - } + Logger.WriteLog(LogType.Error, "Could not authenticate with the Auth server! Shutting down internal communication!"); + } - AuthCommunicator.Send(new RedirectResponsePacket - { - AccountId = packet.AccountId, - Response = RedirectResult.Success - }); - } - #endregion + private void OnCommunicatorServerInfoRequest(ServerInfo info) + { + info.AgeLimit = Config.ServerInfoConfig.AgeLimit; + info.PKFlag = Config.ServerInfoConfig.PKFlag; + info.CurrentPlayers = CurrentPlayers; + info.GamePort = Config.GameConfig.Port; + info.QueuePort = Config.QueueConfig.Port; + info.MaxPlayers = (ushort)Config.SocketAsyncConfig.MaxClients; + } - #region Commands - private void ProcessExitCommand(string[] parts) + private bool OnCommunicatorRedirectRequest(RedirectRequest request) + { + lock (IncomingClients) { - var minutes = 0; + IncomingClients.Remove(request.AccountId); + IncomingClients.Add(request.AccountId, new LoginAccountEntry(request)); + } - if (parts.Length > 1) - minutes = int.Parse(parts[1]); + return true; + } + #endregion - Timer.Add("exit", minutes * 60000, false, () => - { - Shutdown(); - _hostApplicationLifetime.StopApplication(); - }); + #region Commands + private void ProcessExitCommand(string[] parts) + { + var minutes = 0; - Logger.WriteLog(LogType.Command, $"Exiting the server in {minutes} minute(s)."); - } + if (parts.Length > 1) + minutes = int.Parse(parts[1]); - private static void ProcessReloadCommand(string[] parts) - { - if (parts.Length > 1 && parts[1] == "config") - { - Configuration.Load(); - return; - } + Timer.Add("exit", minutes * 60000, false, Shutdown); - Logger.WriteLog(LogType.Command, "Invalid reload command!"); - } + Logger.WriteLog(LogType.Command, $"Exiting the server in {minutes} minute(s)."); + } - /*private void ProcessRestartCommand(string[] parts) + private static void ProcessReloadCommand(string[] parts) + { + if (parts.Length > 1 && parts[1] == "config") { - // TODO: delayed restart, with contacting globals, so they can warn players not to leave the server, or they won't be able to reconnect + Configuration.Load(); + return; } - private void ProcessShutdownCommand(string[] parts) - { - // TODO: delayed shutdown, with contacting globals, so they can warn players not to leave the server, or they won't be able to reconnect - // TODO: add timer to report the remaining time until shutdown? - // TODO: add timer to contact global servers to tell them periodically that we're getting shut down? - }*/ - #endregion + Logger.WriteLog(LogType.Command, "Invalid reload command!"); } + + /*private void ProcessRestartCommand(string[] parts) + { + // TODO: delayed restart, with contacting globals, so they can warn players not to leave the server, or they won't be able to reconnect + } + + private void ProcessShutdownCommand(string[] parts) + { + // TODO: delayed shutdown, with contacting globals, so they can warn players not to leave the server, or they won't be able to reconnect + // TODO: add timer to report the remaining time until shutdown? + // TODO: add timer to contact global servers to tell them periodically that we're getting shut down? + }*/ + #endregion } diff --git a/src/Rasa.Game/Login/LoginClient.cs b/src/Rasa.Game/Login/LoginClient.cs index d2b05b15..9456c082 100644 --- a/src/Rasa.Game/Login/LoginClient.cs +++ b/src/Rasa.Game/Login/LoginClient.cs @@ -1,88 +1,109 @@ using System.Net.Sockets; -namespace Rasa.Login +namespace Rasa.Login; + +using Rasa.Cryptography; +using Rasa.Memory; +using Rasa.Networking; +using Rasa.Packets; +using Rasa.Packets.Login.Client; +using Rasa.Packets.Login.Server; +using System; +using System.Buffers; +using System.IO; +using System.Text; + +public class LoginClient { - using Cryptography; - using Memory; - using Networking; - using Packets.Login.Client; - using Packets.Login.Server; + public const int SendBufferSize = 512; + public const int SendBufferCryptoPadding = 8; + public const int SendBufferChecksumPadding = 8; - public class LoginClient + public AsyncLengthedSocket Socket { get; } + public LoginManager Manager { get; } + public ClientCryptData Data { get; } = new ClientCryptData(); + + public BigNum PrivateKey { get; } = new BigNum(); + public BigNum PublicKey { get; } = new BigNum(); + public BigNum K { get; } = new BigNum(); + + public LoginClient(LoginManager manager, AsyncLengthedSocket socket) { - public LengthedSocket Socket { get; } - public LoginManager Manager { get; } - public ClientCryptData Data { get; } = new ClientCryptData(); + Manager = manager; - // ReSharper disable once InconsistentNaming - public BigNum PrivateKey { get; } = new BigNum(); - public BigNum PublicKey { get; } = new BigNum(); - public BigNum K { get; } = new BigNum(); + Socket = socket; + Socket.OnReceive += OnReceive; + Socket.OnError += OnError; - public LoginClient(LoginManager manager, LengthedSocket socket) + DHKeyExchange.GeneratePrivateAndPublicA(PrivateKey, PublicKey); + + SendPacket(new ServerKeyPacket { - Manager = manager; + PublicKey = PublicKey, + Prime = DHKeyExchange.ConstantPrime, + Generator = DHKeyExchange.ConstantGenerator + }); - Socket = socket; - Socket.AutoReceive = false; - Socket.OnReceive += OnReceive; - Socket.OnError += OnError; + Socket.Start(); + } - DHKeyExchange.GeneratePrivateAndPublicA(PrivateKey, PublicKey); + public void SendPacket(IBasePacket packet) + { + var buffer = ArrayPool.Shared.Rent(SendBufferSize + SendBufferCryptoPadding + SendBufferChecksumPadding); + var writer = new BinaryWriter(new MemoryStream(buffer, true)); - Socket.Send(new ServerKeyPacket - { - PublicKey = PublicKey, - Prime = DHKeyExchange.ConstantPrime, - Generator = DHKeyExchange.ConstantGenerator - }); + packet.Write(writer); - Socket.OnEncrypt += OnEncrypt; - Socket.ReceiveAsync(); - } + var length = (int)writer.BaseStream.Position; - private void OnEncrypt(BufferData data, ref int length) + if (packet is not ServerKeyPacket) { - GameCryptManager.Encrypt(data.Buffer, data.BaseOffset + data.Offset, ref length, data.RemainingLength, Data); + GameCryptManager.Encrypt(buffer, 0, ref length, buffer.Length, Data); } - private void OnReceive(BufferData data) - { - var packet = new ClientKeyPacket(); - packet.Read(data.GetReader()); + Socket.Send(buffer, 0, length); - DHKeyExchange.GenerateServerK(PrivateKey, packet.B, K); + ArrayPool.Shared.Return(buffer); + } - var key = new byte[64]; - K.WriteToBigEndian(key, 0, key.Length); + private void OnReceive(NonContiguousMemoryStream incomingStream, int length) + { + var startPosition = incomingStream.Position; - GameCryptManager.Initialize(Data, key); + using var br = new BinaryReader(incomingStream, Encoding.UTF8, true); - Socket.Send(new ClientKeyOkPacket()); + var packet = new ClientKeyPacket(); + packet.Read(br); - Cleanup(); + if (startPosition + length != incomingStream.Position) + throw new Exception($"Over or under read of the incoming packet! Start position: {startPosition} | Length: {length} | Ending position: {incomingStream.Position}"); - Manager.ExchangeDone(this); - } + DHKeyExchange.GenerateServerK(PrivateKey, packet.B, K); - private void OnError(SocketAsyncEventArgs args) - { - Manager.Disconnect(this); + var key = new byte[64]; + K.WriteToBigEndian(key, 0, key.Length); - Close(); - } + GameCryptManager.Initialize(Data, key); - private void Cleanup() - { - Socket.AutoReceive = true; - Socket.OnReceive = null; - Socket.OnError = null; - Socket.OnEncrypt = null; - } + SendPacket(new ClientKeyOkPacket()); - public void Close() - { - Socket.Close(); - } + Cleanup(); + + Manager.ExchangeDone(this); + } + + private void OnError() + { + Manager.Disconnect(this); + + Close(); + } + + private void Cleanup() + { + Socket.OnReceive = null; + Socket.OnError = null; } + + public void Close() => Socket.Close(); } diff --git a/src/Rasa.Game/Login/LoginManager.cs b/src/Rasa.Game/Login/LoginManager.cs index 36729110..df43ddaa 100644 --- a/src/Rasa.Game/Login/LoginManager.cs +++ b/src/Rasa.Game/Login/LoginManager.cs @@ -1,37 +1,36 @@ using System.Collections.Generic; -namespace Rasa.Login +namespace Rasa.Login; + +using Rasa.Networking; + +public delegate void LoginDelegate(LoginClient client); + +public class LoginManager { - using Networking; + public LoginDelegate OnLogin { get; set; } + public LoginDelegate OnFail { get; set; } + public List Clients { get; } = new List(); + + public void LoginSocket(AsyncLengthedSocket socket) + { + lock (Clients) + Clients.Add(new LoginClient(this, socket)); + } - public delegate void LoginDelegate(LoginClient client); + public void ExchangeDone(LoginClient client) + { + lock (Clients) + Clients.Remove(client); - public class LoginManager + OnLogin?.Invoke(client); + } + + public void Disconnect(LoginClient client) { - public LoginDelegate OnLogin { get; set; } - public LoginDelegate OnFail { get; set; } - public List Clients { get; } = new List(); - - public void LoginSocket(LengthedSocket socket) - { - lock (Clients) - Clients.Add(new LoginClient(this, socket)); - } - - public void ExchangeDone(LoginClient client) - { - lock (Clients) - Clients.Remove(client); - - OnLogin?.Invoke(client); - } - - public void Disconnect(LoginClient client) - { - lock (Clients) - Clients.Remove(client); - - OnFail?.Invoke(client); - } + lock (Clients) + Clients.Remove(client); + + OnFail?.Invoke(client); } } diff --git a/src/Rasa.Game/Memory/PythonReader.cs b/src/Rasa.Game/Memory/PythonReader.cs index 3f54402c..b1f0d7cd 100644 --- a/src/Rasa.Game/Memory/PythonReader.cs +++ b/src/Rasa.Game/Memory/PythonReader.cs @@ -2,383 +2,382 @@ using System.IO; using System.Text; -namespace Rasa.Memory +namespace Rasa.Memory; + +using Rasa.Extensions; + +public enum PythonType { - using Extensions; + Structs = 0x00, + Int = 0x10, + Long = 0x20, + Double = 0x30, + String = 0x40, + UnicodeString = 0x50, + Dictionary = 0x60, + List = 0x70, + Tuple = 0x80 +} - public enum PythonType +public enum PythonStruct +{ + None = 0x00, + True = 0x01, + Zero = 0x02 +} + +public sealed class PythonReader : IDisposable +{ + public BinaryReader Reader { get; } + public long BeginPosition { get; } + + public PythonReader(BinaryReader reader) { - Structs = 0x00, - Int = 0x10, - Long = 0x20, - Double = 0x30, - String = 0x40, - UnicodeString = 0x50, - Dictionary = 0x60, - List = 0x70, - Tuple = 0x80 + Reader = reader; + BeginPosition = Reader.BaseStream.Position; } - public enum PythonStruct + public PythonType PeekType() { - None = 0x00, - True = 0x01, - Zero = 0x02 + var type = Reader.ReadByte(); + + --Reader.BaseStream.Position; + + return (PythonType)(type & 0xF0); + } + + public void ReadNoneStruct() + { + var val = Reader.ReadByte(); + if (val != 0x00) + throw new Exception($"Expected NoneStruct, found data: {val:X2}"); } - public sealed class PythonReader : IDisposable + public void ReadTrueStruct() { - public BinaryReader Reader { get; } - public long BeginPosition { get; } + var val = Reader.ReadByte(); + if (val != 0x01) + throw new Exception($"Expected TrueStruct, found data: {val:X2}"); + } + + public void ReadZeroStruct() + { + var val = Reader.ReadByte(); + if (val != 0x02) + throw new Exception($"Expected ZeroStruct, found data: {val:X2}"); + } - public PythonReader(BinaryReader reader) + public PythonStruct ReadUnkStruct() + { + var val = Reader.ReadByte(); + + return val switch { - Reader = reader; - BeginPosition = Reader.BaseStream.Position; - } + 0x00 => PythonStruct.None, + 0x01 => PythonStruct.True, + 0x02 => PythonStruct.Zero, + _ => throw new Exception($"Expected NoneStruct, TrueStruct or ZeroStruct, found data: {val:X2}"), + }; + } - public PythonType PeekType() + public bool ReadBool() + { + var val = Reader.ReadByte(); + return val switch { - var type = Reader.ReadByte(); + 0x00 or 0x10 => false, // NoneStruct or int 0 + 0x01 or 0x11 => true, // TrueStruct or int 1 + _ => throw new Exception($"Expected 0x00, 0x10 or 0x01, 0x11. Got: {val:X2}"), + }; + } - --Reader.BaseStream.Position; + public int ReadInt() + { + var type = Reader.ReadByte(); + if ((type & 0x10) != 0x10) + throw new Exception($"Expected 0x1_. Got: {type:X2}"); - return (PythonType)(type & 0xF0); - } + if (type <= 0x1C) + return type & 0xF; - public void ReadNoneStruct() + return type switch { - var val = Reader.ReadByte(); - if (val != 0x00) - throw new Exception($"Expected NoneStruct, found data: {val:X2}"); - } + 0x1D => Reader.ReadByte(), + 0x1E => Reader.ReadInt16(), + 0x1F => Reader.ReadInt32(), + _ => throw new Exception($"WTF? Int type: {type:X2}"), + }; + } - public void ReadTrueStruct() - { - var val = Reader.ReadByte(); - if (val != 0x01) - throw new Exception($"Expected TrueStruct, found data: {val:X2}"); - } + public uint ReadUInt() + { + var type = Reader.ReadByte(); + if ((type & 0x10) != 0x10) + throw new Exception($"Expected 0x1_. Got: {type:X2}"); - public void ReadZeroStruct() - { - var val = Reader.ReadByte(); - if (val != 0x02) - throw new Exception($"Expected ZeroStruct, found data: {val:X2}"); - } + if (type <= 0x1C) + return (uint)(type & 0xF); - public PythonStruct ReadUnkStruct() + return type switch { - var val = Reader.ReadByte(); + 0x1D => Reader.ReadByte(), + 0x1E => Reader.ReadUInt16(), + 0x1F => Reader.ReadUInt32(), + _ => throw new Exception($"WTF? Int type: {type:X2}"), + }; + } - return val switch - { - 0x00 => PythonStruct.None, - 0x01 => PythonStruct.True, - 0x02 => PythonStruct.Zero, - _ => throw new Exception($"Expected NoneStruct, TrueStruct or ZeroStruct, found data: {val:X2}"), - }; - } + public long ReadLong() + { + var type = Reader.ReadByte(); + if ((type & 0x20) != 0x20) + throw new Exception($"Expected 0x2_. Got: {type:X2}"); - public bool ReadBool() - { - var val = Reader.ReadByte(); - return val switch - { - 0x00 or 0x10 => false, // NoneStruct or int 0 - 0x01 or 0x11 => true, // TrueStruct or int 1 - _ => throw new Exception($"Expected 0x00, 0x10 or 0x01, 0x11. Got: {val:X2}"), - }; - } + if (type == 0x20) + return 0L; - public int ReadInt() - { - var type = Reader.ReadByte(); - if ((type & 0x10) != 0x10) - throw new Exception($"Expected 0x1_. Got: {type:X2}"); + if (type != 0x2F) + throw new Exception($"WTF? Long type: {type:X2}"); - if (type <= 0x1C) - return type & 0xF; + return Reader.ReadInt64(); + } - return type switch - { - 0x1D => Reader.ReadByte(), - 0x1E => Reader.ReadInt16(), - 0x1F => Reader.ReadInt32(), - _ => throw new Exception($"WTF? Int type: {type:X2}"), - }; - } + public ulong ReadULong() + { + var type = Reader.ReadByte(); + if ((type & 0x20) != 0x20) + throw new Exception($"Expected 0x2_. Got: {type:X2}"); - public uint ReadUInt() - { - var type = Reader.ReadByte(); - if ((type & 0x10) != 0x10) - throw new Exception($"Expected 0x1_. Got: {type:X2}"); + if (type == 0x20) + return 0UL; - if (type <= 0x1C) - return (uint)(type & 0xF); + if (type != 0x2F) + throw new Exception($"WTF? Long type: {type:X2}"); - return type switch - { - 0x1D => Reader.ReadByte(), - 0x1E => Reader.ReadUInt16(), - 0x1F => Reader.ReadUInt32(), - _ => throw new Exception($"WTF? Int type: {type:X2}"), - }; - } + return Reader.ReadUInt64(); + } - public long ReadLong() - { - var type = Reader.ReadByte(); - if ((type & 0x20) != 0x20) - throw new Exception($"Expected 0x2_. Got: {type:X2}"); + public double ReadDouble() + { + var type = Reader.ReadByte(); + if ((type & 0x30) != 0x30) + throw new Exception($"Expected 0x3_. Got: {type:X2}"); - if (type == 0x20) - return 0L; + return type switch + { + 0x30 => 0.0D, + 0x31 => 1.0D, + 0x3E => Reader.ReadDouble(), + 0x3F => Reader.ReadSingle(), + _ => throw new Exception($"WTF? Double type: {type:X2}"), + }; + } - if (type != 0x2F) - throw new Exception($"WTF? Long type: {type:X2}"); + public string ReadString() + { + var type = Reader.ReadByte(); + if ((type & 0x40) != 0x40) + throw new Exception($"Expected 0x4_. Got: {type:X2}"); - return Reader.ReadInt64(); - } + int length; - public ulong ReadULong() + switch (type) { - var type = Reader.ReadByte(); - if ((type & 0x20) != 0x20) - throw new Exception($"Expected 0x2_. Got: {type:X2}"); + case 0x40: + return null; - if (type == 0x20) - return 0UL; + case 0x41: + case 0x42: + throw new NotImplementedException(); - if (type != 0x2F) - throw new Exception($"WTF? Long type: {type:X2}"); + case 0x4D: + length = Reader.ReadByte(); + break; - return Reader.ReadUInt64(); - } + case 0x4E: + length = Reader.ReadInt16(); + break; - public double ReadDouble() - { - var type = Reader.ReadByte(); - if ((type & 0x30) != 0x30) - throw new Exception($"Expected 0x3_. Got: {type:X2}"); + case 0x4F: + length = Reader.ReadInt32(); + break; - return type switch - { - 0x30 => 0.0D, - 0x31 => 1.0D, - 0x3E => Reader.ReadDouble(), - 0x3F => Reader.ReadSingle(), - _ => throw new Exception($"WTF? Double type: {type:X2}"), - }; + default: + throw new Exception($"WTF? String type: {type:X2}"); } - public string ReadString() - { - var type = Reader.ReadByte(); - if ((type & 0x40) != 0x40) - throw new Exception($"Expected 0x4_. Got: {type:X2}"); + return Reader.ReadUtf8StringOn(length); + } - int length; + public string ReadUnicodeString() + { + var type = Reader.ReadByte(); + if ((type & 0x50) != 0x50) + throw new Exception($"Expected 0x5_. Got: {type:X2}"); - switch (type) - { - case 0x40: - return null; + int length; - case 0x41: - case 0x42: - throw new NotImplementedException(); + switch (type) + { + case 0x50: + return null; - case 0x4D: - length = Reader.ReadByte(); - break; + case 0x52: + throw new NotImplementedException(); - case 0x4E: - length = Reader.ReadInt16(); - break; + case 0x5D: + length = Reader.ReadByte(); + break; - case 0x4F: - length = Reader.ReadInt32(); - break; + case 0x5E: + length = Reader.ReadInt16(); + break; - default: - throw new Exception($"WTF? String type: {type:X2}"); - } + case 0x5F: + length = Reader.ReadInt32(); + break; - return Reader.ReadUtf8StringOn(length); + default: + throw new Exception($"WTF? String type: {type:X2}"); } - public string ReadUnicodeString() - { - var type = Reader.ReadByte(); - if ((type & 0x50) != 0x50) - throw new Exception($"Expected 0x5_. Got: {type:X2}"); + return Reader.ReadUtf8StringOn(length); + } - int length; + public int ReadDictionary() + { + var type = Reader.ReadByte(); + if ((type & 0x60) != 0x60) + throw new Exception($"Expected 0x6_. Got: {type:X2}"); - switch (type) - { - case 0x50: - return null; + if (type <= 0x6C) + return type & 0x0F; - case 0x52: - throw new NotImplementedException(); + return type switch + { + 0x6D => Reader.ReadByte(), + 0x6E => Reader.ReadInt16(), + 0x6F => Reader.ReadInt32(), + _ => throw new Exception($"WTF? Dictionary type: {type:X2}"), + }; + } - case 0x5D: - length = Reader.ReadByte(); - break; + public int ReadList() + { + var type = Reader.ReadByte(); + if ((type & 0x70) != 0x70) + throw new Exception($"Expected 0x7_. Got: {type:X2}"); - case 0x5E: - length = Reader.ReadInt16(); - break; + if (type <= 0x7C) + return type & 0x0F; - case 0x5F: - length = Reader.ReadInt32(); - break; + return type switch + { + 0x7D => Reader.ReadByte(), + 0x7E => Reader.ReadInt16(), + 0x7F => Reader.ReadInt32(), + _ => throw new Exception($"WTF? List type: {type:X2}"), + }; + } - default: - throw new Exception($"WTF? String type: {type:X2}"); - } + public int ReadTuple() + { + var type = Reader.ReadByte(); + if ((type & 0x80) != 0x80) + throw new Exception($"Expected 0x8_. Got: {type:X2}"); - return Reader.ReadUtf8StringOn(length); - } + if (type <= 0x8C) + return type & 0x0F; - public int ReadDictionary() + return type switch { - var type = Reader.ReadByte(); - if ((type & 0x60) != 0x60) - throw new Exception($"Expected 0x6_. Got: {type:X2}"); + 0x8D => Reader.ReadByte(), + 0x8E => Reader.ReadInt16(), + 0x8F => Reader.ReadInt32(), + _ => throw new Exception($"WTF? Tuple type: {type:X2}"), + }; + } - if (type <= 0x6C) - return type & 0x0F; + public T ReadStruct() + where T : IPythonDataStruct, new() + { + var ret = new T(); - return type switch - { - 0x6D => Reader.ReadByte(), - 0x6E => Reader.ReadInt16(), - 0x6F => Reader.ReadInt32(), - _ => throw new Exception($"WTF? Dictionary type: {type:X2}"), - }; - } + ret.Read(this); - public int ReadList() - { - var type = Reader.ReadByte(); - if ((type & 0x70) != 0x70) - throw new Exception($"Expected 0x7_. Got: {type:X2}"); + return ret; + } - if (type <= 0x7C) - return type & 0x0F; + public override string ToString() + { + var originalPosition = Reader.BaseStream.Position; - return type switch - { - 0x7D => Reader.ReadByte(), - 0x7E => Reader.ReadInt16(), - 0x7F => Reader.ReadInt32(), - _ => throw new Exception($"WTF? List type: {type:X2}"), - }; - } + Reader.BaseStream.Position = BeginPosition; + + var sb = new StringBuilder(); - public int ReadTuple() + while (Reader.BaseStream.Position < Reader.BaseStream.Length) { var type = Reader.ReadByte(); - if ((type & 0x80) != 0x80) - throw new Exception($"Expected 0x8_. Got: {type:X2}"); + if (type == 0x66) + { + //if (Reader.ReadByte() == 0x2A) + break; - if (type <= 0x8C) - return type & 0x0F; + //--Reader.BaseStream.Position; + } - return type switch + --Reader.BaseStream.Position; + + switch ((PythonType)(type & 0xF0)) { - 0x8D => Reader.ReadByte(), - 0x8E => Reader.ReadInt16(), - 0x8F => Reader.ReadInt32(), - _ => throw new Exception($"WTF? Tuple type: {type:X2}"), - }; - } + case PythonType.Structs: + sb.Append("Struct: ").AppendLine($"{ReadUnkStruct()}"); + break; - public T ReadStruct() - where T : IPythonDataStruct, new() - { - var ret = new T(); + case PythonType.Int: + sb.Append("Integer: ").AppendLine($"{ReadInt()}"); + break; - ret.Read(this); + case PythonType.Long: + sb.Append("Long: ").AppendLine($"{ReadLong()}"); + break; - return ret; - } + case PythonType.Double: + sb.Append("Double: ").AppendLine($"{ReadDouble()}"); + break; - public override string ToString() - { - var originalPosition = Reader.BaseStream.Position; + case PythonType.String: + sb.Append("String: ").AppendLine($"{ReadString()}"); + break; - Reader.BaseStream.Position = BeginPosition; + case PythonType.UnicodeString: + sb.Append("Unicode string: ").AppendLine($"{ReadUnicodeString()}"); + break; - var sb = new StringBuilder(); + case PythonType.Dictionary: + sb.Append("Dictionary: Element count: ").AppendLine($"{ReadDictionary()}"); + break; - while (Reader.BaseStream.Position < Reader.BaseStream.Length) - { - var type = Reader.ReadByte(); - if (type == 0x66) - { - //if (Reader.ReadByte() == 0x2A) - break; - - //--Reader.BaseStream.Position; - } - - --Reader.BaseStream.Position; - - switch ((PythonType)(type & 0xF0)) - { - case PythonType.Structs: - sb.Append("Struct: ").AppendLine($"{ReadUnkStruct()}"); - break; - - case PythonType.Int: - sb.Append("Integer: ").AppendLine($"{ReadInt()}"); - break; - - case PythonType.Long: - sb.Append("Long: ").AppendLine($"{ReadLong()}"); - break; - - case PythonType.Double: - sb.Append("Double: ").AppendLine($"{ReadDouble()}"); - break; - - case PythonType.String: - sb.Append("String: ").AppendLine($"{ReadString()}"); - break; - - case PythonType.UnicodeString: - sb.Append("Unicode string: ").AppendLine($"{ReadUnicodeString()}"); - break; - - case PythonType.Dictionary: - sb.Append("Dictionary: Element count: ").AppendLine($"{ReadDictionary()}"); - break; - - case PythonType.List: - sb.Append("List: Element count: ").AppendLine($"{ReadList()}"); - break; - - case PythonType.Tuple: - sb.Append("Tuple: Element count: ").AppendLine($"{ReadTuple()}"); - break; - - default: - throw new Exception($"Invalid type read! Type: {type:X}"); - } - } + case PythonType.List: + sb.Append("List: Element count: ").AppendLine($"{ReadList()}"); + break; - Reader.BaseStream.Position = originalPosition; + case PythonType.Tuple: + sb.Append("Tuple: Element count: ").AppendLine($"{ReadTuple()}"); + break; - return sb.ToString(); + default: + throw new Exception($"Invalid type read! Type: {type:X}"); + } } - public void Dispose() - { - } + Reader.BaseStream.Position = originalPosition; + + return sb.ToString(); + } + + public void Dispose() + { } } diff --git a/src/Rasa.Game/Packets/Protocol/ProtocolPacket.cs b/src/Rasa.Game/Packets/Protocol/ProtocolPacket.cs index 0953d91d..648f189d 100644 --- a/src/Rasa.Game/Packets/Protocol/ProtocolPacket.cs +++ b/src/Rasa.Game/Packets/Protocol/ProtocolPacket.cs @@ -64,8 +64,6 @@ public void Read(BinaryReader br) using (var reader = new ProtocolBufferReader(br, ProtocolBufferFlags.DontFragment)) { reader.ReadProtocolFlags(); - - reader.ReadPacketType(out ushort type, out bool compress); Type = (ClientMessageOpcode) type; diff --git a/src/Rasa.Game/Properties/AssemblyInfo.cs b/src/Rasa.Game/Properties/AssemblyInfo.cs deleted file mode 100644 index 714e4653..00000000 --- a/src/Rasa.Game/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System.Reflection; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("Rasa.Game")] -[assembly: AssemblyTrademark("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("0880a5f1-a46b-4bbf-be52-37feec006d30")] diff --git a/src/Rasa.Game/Properties/launchSettings.json b/src/Rasa.Game/Properties/launchSettings.json deleted file mode 100644 index f5428cf7..00000000 --- a/src/Rasa.Game/Properties/launchSettings.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "profiles": { - "Rasa.Game": { - "commandName": "Project" - } - } -} \ No newline at end of file diff --git a/src/Rasa.Game/Queue/QueueClient.cs b/src/Rasa.Game/Queue/QueueClient.cs index dc1979c1..5aa3b6ea 100644 --- a/src/Rasa.Game/Queue/QueueClient.cs +++ b/src/Rasa.Game/Queue/QueueClient.cs @@ -1,120 +1,137 @@ using System; using System.Net; -using System.Net.Sockets; -namespace Rasa.Queue +namespace Rasa.Queue; + +using Rasa.Data; +using Rasa.Memory; +using Rasa.Networking; +using Rasa.Packets; +using Rasa.Packets.Queue.Client; +using Rasa.Packets.Queue.Server; +using System.Buffers; +using System.IO; +using System.Text; + +public class QueueClient { - using Data; - using Memory; - using Networking; - using Packets.Queue.Client; - using Packets.Queue.Server; + public const int SendBufferSize = 512; - public class QueueClient + public QueueManager Manager { get; } + public AsyncLengthedSocket Socket { get; } + public QueueState State { get; private set; } + public uint UserId { get; set; } + public uint OneTimeKey { get; set; } + public DateTime EnqueueTime { get; private set; } + public DateTime DequeueTime { get; set; } + + public QueueClient(QueueManager manager, AsyncLengthedSocket socket) { - public QueueManager Manager { get; } - public LengthedSocket Socket { get; } - public QueueState State { get; private set; } - public uint UserId { get; set; } - public uint OneTimeKey { get; set; } - public DateTime EnqueueTime { get; private set; } - public DateTime DequeueTime { get; set; } - - public QueueClient(QueueManager manager, LengthedSocket socket) + Manager = manager; + Socket = socket; + Socket.OnReceive += OnReceive; + Socket.OnError += OnError; + + Socket.Start(); + + SendPacket(new ServerKeyPacket { - Manager = manager; - Socket = socket; - Socket.OnReceive += OnReceive; - Socket.OnError += OnError; + PublicKey = Manager.Config.PublicKey, + Prime = Manager.Config.Prime, + Generator = Manager.Config.Generator + }); + + State = QueueState.Authenticating; + } - Socket.ReceiveAsync(); + private void SendPacket(IOpcodedPacket packet) + { + var buffer = ArrayPool.Shared.Rent(SendBufferSize); + var writer = new BinaryWriter(new MemoryStream(buffer, true)); - Socket.Send(new ServerKeyPacket - { - PublicKey = Manager.Config.PublicKey, - Prime = Manager.Config.Prime, - Generator = Manager.Config.Generator - }); + packet.Write(writer); - State = QueueState.Authenticating; - } + Socket.Send(buffer, 0, (int)writer.BaseStream.Position); + + ArrayPool.Shared.Return(buffer); + } + + private void OnReceive(NonContiguousMemoryStream incomingStream, int length) + { + var startPosition = incomingStream.Position; + + using var br = new BinaryReader(incomingStream, Encoding.UTF8, true); - private void OnReceive(BufferData data) + switch (State) { - switch (State) - { - case QueueState.Authenticating: - var keyPacket = new ClientKeyPacket(); + case QueueState.Authenticating: + var keyPacket = new ClientKeyPacket(); - keyPacket.Read(data.GetReader()); + keyPacket.Read(br); - if (keyPacket.PublicKey != Manager.Config.PublicKey) - { - Close(); - return; - } + if (keyPacket.PublicKey != Manager.Config.PublicKey) + { + Close(); + return; + } - Socket.Send(new ClientKeyOkPacket()); + SendPacket(new ClientKeyOkPacket()); - State = QueueState.Authenticated; + State = QueueState.Authenticated; - break; + break; - case QueueState.Authenticated: - if (data[data.Offset++] != 7) - throw new Exception("Invalid opcode???"); + case QueueState.Authenticated: + if (br.ReadByte() != 7) + throw new Exception("Invalid opcode???"); - var loginPacket = new QueueLoginPacket(); + var loginPacket = new QueueLoginPacket(); - loginPacket.Read(data.GetReader()); + loginPacket.Read(br); - UserId = loginPacket.UserId; - OneTimeKey = loginPacket.OneTimeKey; - State = QueueState.InQueue; + UserId = loginPacket.UserId; + OneTimeKey = loginPacket.OneTimeKey; + State = QueueState.InQueue; - Manager.Enqueue(this); - EnqueueTime = DateTime.Now; - break; + Manager.Enqueue(this); + EnqueueTime = DateTime.Now; + break; - default: - throw new Exception("Received packet in a invalid queue state!"); - } + default: + throw new Exception("Received packet in a invalid queue state!"); } + } - private void OnError(SocketAsyncEventArgs args) - { - Close(); - } + private void OnError() => Close(); - public void Close() - { - Socket.Close(); + public void Close() + { + Socket.Close(); - State = QueueState.Disconnected; + State = QueueState.Disconnected; - Manager.Disconnect(this); - } + Manager.Disconnect(this); + } - public void Redirect(IPAddress ip, int port) + public void Redirect(IPAddress ip, int port) + { + State = QueueState.Redirecting; + + SendPacket(new HandoffToGamePacket { - State = QueueState.Redirecting; - - Socket.Send(new HandoffToGamePacket - { - OneTimeKey = OneTimeKey, - ServerIp = ip, - ServerPort = port, - UserId = UserId - }); - } + OneTimeKey = OneTimeKey, + ServerIp = ip, + ServerPort = port, + UserId = UserId + }); + } - public void SendPositionUpdate(int position, int estimatedTime) + public void SendPositionUpdate(int position, int estimatedTime) + { + SendPacket(new QueuePositionPacket { - Socket.Send(new QueuePositionPacket - { - Position = position, - EstimatedTime = estimatedTime - }); - } + Position = position, + EstimatedTime = estimatedTime + }); } } diff --git a/src/Rasa.Game/Queue/QueueManager.cs b/src/Rasa.Game/Queue/QueueManager.cs index a0a6f631..ed22d5b3 100644 --- a/src/Rasa.Game/Queue/QueueManager.cs +++ b/src/Rasa.Game/Queue/QueueManager.cs @@ -1,145 +1,129 @@ using System.Collections.Generic; using System.Net; -using System.Net.Sockets; -using System.Runtime.InteropServices.ComTypes; -namespace Rasa.Queue -{ - using Config; - using Data; - using Game; - using Networking; +namespace Rasa.Queue; - public delegate void RedirectDelegate(QueueClient client); +using Rasa.Config; +using Rasa.Data; +using Rasa.Game; +using Rasa.Networking; - public class QueueManager - { - private readonly Queue _queuedClients = new Queue(); +public delegate void RedirectDelegate(QueueClient client); - public List Clients { get; } = new List(); +public class QueueManager +{ + private readonly Queue _queuedClients = new Queue(); - public Server Server { get; } - public LengthedSocket Socket { get; } - public int QueuedClients => _queuedClients.Count; - public RedirectDelegate OnRedirect { get; set; } - public QueueConfig Config => Server.Config.QueueConfig; + public List Clients { get; } = new List(); - public QueueManager(Server server) - { - Server = server; + public Server Server { get; } + public AsyncLengthedSocket Socket { get; } = new(AsyncLengthedSocket.HeaderSizeType.Dword, false); + public int QueuedClients => _queuedClients.Count; + public RedirectDelegate OnRedirect { get; set; } + public QueueConfig Config => Server.Config.QueueConfig; - Socket = new LengthedSocket(SizeType.Dword, false); - Socket.OnError += OnError; - Socket.OnAccept += OnAccept; - Socket.Bind(new IPEndPoint(IPAddress.Any, Config.Port)); - Socket.Listen(Config.Backlog); + public QueueManager(Server server) + { + Server = server; - Socket.AcceptAsync(); - } + Socket.OnAccept += OnAccept; + Socket.StartListening(new IPEndPoint(IPAddress.Any, Config.Port), Config.Backlog); + } - private static void OnError(SocketAsyncEventArgs args) - { - if (args.LastOperation == SocketAsyncOperation.Accept && args.AcceptSocket != null && args.AcceptSocket.Connected) - args.AcceptSocket.Shutdown(SocketShutdown.Both); - } + private void OnAccept(AsyncLengthedSocket socket) + { + lock (Clients) + Clients.Add(new QueueClient(this, socket)); + } - private void OnAccept(LengthedSocket socket) + public void Disconnect(QueueClient client) + { + lock (Clients) + Clients.Remove(client); + } + + public void Enqueue(QueueClient client) + { + lock (_queuedClients) { - Socket.AcceptAsync(); + if (!Server.IsFull) + { + // TODO: need a position update before redirect? + client.Redirect(Server.PublicAddress, Server.Config.GameConfig.Port); + return; + } - lock (Clients) - Clients.Add(new QueueClient(this, socket)); - } + _queuedClients.Enqueue(client); - public void Disconnect(QueueClient client) - { - lock (Clients) - Clients.Remove(client); - } + var pos = 0; - public void Enqueue(QueueClient client) - { - lock (_queuedClients) + foreach (var c in _queuedClients) { - if (!Server.IsFull) - { - // TODO: need a position update before redirect? - client.Redirect(Server.PublicAddress, Server.Config.GameConfig.Port); - return; - } - - _queuedClients.Enqueue(client); - - var pos = 0; - - foreach (var c in _queuedClients) - { - if (c.State == QueueState.Disconnected) - continue; - - if (c == client) - c.SendPositionUpdate(pos, 10000 * pos); // TODO: proper estimated time calculation - else - ++pos; - } + if (c.State == QueueState.Disconnected) + continue; + + if (c == client) + c.SendPositionUpdate(pos, 10000 * pos); // TODO: proper estimated time calculation + else + ++pos; } } + } - private void AdvanceQueue(int freeSlots) - { - if (QueuedClients == 0) - return; + private void AdvanceQueue(int freeSlots) + { + if (QueuedClients == 0) + return; - lock (_queuedClients) + lock (_queuedClients) + { + for (var i = 0; i < freeSlots && QueuedClients > 0;) { - for (var i = 0; i < freeSlots && QueuedClients > 0;) - { - var client = _queuedClients.Dequeue(); - if (client.State == QueueState.Disconnected) - continue; - - client.Redirect(Server.PublicAddress, Server.Config.GameConfig.Port); - ++i; - } + var client = _queuedClients.Dequeue(); + if (client.State == QueueState.Disconnected) + continue; + + client.Redirect(Server.PublicAddress, Server.Config.GameConfig.Port); + ++i; } } + } - private void ClearDisconnected() - { - if (QueuedClients == 0) - return; + private void ClearDisconnected() + { + if (QueuedClients == 0) + return; - lock (_queuedClients) + lock (_queuedClients) + { + do { - do - { - var c = _queuedClients.Peek(); - if (c.State != QueueState.Disconnected) - break; - - _queuedClients.Dequeue(); - } - while (QueuedClients > 0); + var c = _queuedClients.Peek(); + if (c.State != QueueState.Disconnected) + break; + + _queuedClients.Dequeue(); } + while (QueuedClients > 0); } + } - public void Update(int freeSlots) - { - if (QueuedClients == 0) - return; + public void Update(int freeSlots) + { + if (QueuedClients == 0) + return; - lock (_queuedClients) - { - ClearDisconnected(); + lock (_queuedClients) + { + ClearDisconnected(); - AdvanceQueue(freeSlots); + AdvanceQueue(freeSlots); - var position = 0; + var position = 0; - foreach (var client in _queuedClients) - if (client.State != QueueState.Disconnected) - client.SendPositionUpdate(position, 10000 * position++); // TODO: proper estimated time calculation - } + foreach (var client in _queuedClients) + if (client.State != QueueState.Disconnected) + client.SendPositionUpdate(position, 10000 * position++); // TODO: proper estimated time calculation } } } diff --git a/src/Rasa.Game/Rasa.Game.csproj b/src/Rasa.Game/Rasa.Game.csproj index 5503e2f3..5af24285 100644 --- a/src/Rasa.Game/Rasa.Game.csproj +++ b/src/Rasa.Game/Rasa.Game.csproj @@ -2,18 +2,16 @@ Rasa.NET Game - net5.0 + net7.0 Rasa.Game Exe Rasa.Game - win10-x64;osx.10.10-x64;ubuntu.14.04-x64 - 5.0.0 false false false Rasa Rasa.GameProgram - 9.0 + 10.0 @@ -21,8 +19,8 @@ + - diff --git a/src/Rasa.Game/Structures/LoginAccountEntry.cs b/src/Rasa.Game/Structures/LoginAccountEntry.cs index 3573eb56..28f70534 100644 --- a/src/Rasa.Game/Structures/LoginAccountEntry.cs +++ b/src/Rasa.Game/Structures/LoginAccountEntry.cs @@ -1,24 +1,23 @@ using System; -namespace Rasa.Structures +namespace Rasa.Structures; + +using Rasa.Communicator; + +public class LoginAccountEntry { - using Packets.Communicator; + public uint Id { get; set; } + public string Email { get; set; } + public string Name { get; set; } + public DateTime ExpireTime { get; set; } + public uint OneTimeKey { get; set; } - public class LoginAccountEntry + public LoginAccountEntry(RedirectRequest request) { - public uint Id { get; set; } - public string Email { get; set; } - public string Name { get; set; } - public DateTime ExpireTime { get; set; } - public uint OneTimeKey { get; set; } - - public LoginAccountEntry(RedirectRequestPacket packet) - { - Id = packet.AccountId; - Email = packet.Email; - Name = packet.Username; - OneTimeKey = packet.OneTimeKey; - ExpireTime = DateTime.Now.AddMinutes(1); - } + Id = request.AccountId; + Email = request.Email; + Name = request.Username; + OneTimeKey = request.OneTimeKey; + ExpireTime = DateTime.Now.AddMinutes(1); } } diff --git a/src/Rasa.Shared/Data/CommLoginReason.cs b/src/Rasa.Shared/Data/CommLoginReason.cs deleted file mode 100644 index 63ca812d..00000000 --- a/src/Rasa.Shared/Data/CommLoginReason.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Rasa.Data -{ - public enum CommLoginReason : byte - { - Success = 0, - Failure = 1 - } -} diff --git a/src/Rasa.Shared/Data/CommOpcode.cs b/src/Rasa.Shared/Data/CommOpcode.cs deleted file mode 100644 index b296c6bf..00000000 --- a/src/Rasa.Shared/Data/CommOpcode.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace Rasa.Data -{ - public enum CommOpcode : byte - { - LoginRequest = 0, - LoginResponse = 1, - RedirectRequest = 2, - RedirectResponse = 3, - ServerInfoRequest = 4, - ServerInfoResponse = 5 - } -} diff --git a/src/Rasa.Shared/Data/RedirectResult.cs b/src/Rasa.Shared/Data/RedirectResult.cs deleted file mode 100644 index c921b50e..00000000 --- a/src/Rasa.Shared/Data/RedirectResult.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Rasa.Data -{ - public enum RedirectResult : byte - { - Fail = 0, - Success = 1 - } -} diff --git a/src/Rasa.Shared/Packets/Communicator/LoginRequestPacket.cs b/src/Rasa.Shared/Packets/Communicator/LoginRequestPacket.cs index fbc4b2bd..1853413c 100644 --- a/src/Rasa.Shared/Packets/Communicator/LoginRequestPacket.cs +++ b/src/Rasa.Shared/Packets/Communicator/LoginRequestPacket.cs @@ -2,32 +2,31 @@ using System.Net; using System.Net.Sockets; -namespace Rasa.Packets.Communicator +namespace Rasa.Packets.Communicator; + +using Rasa.Data; +using Rasa.Extensions; + +public class LoginRequestPacket : IOpcodedPacket { - using Data; - using Extensions; + public CommOpcode Opcode { get; } = CommOpcode.LoginRequest; + public byte ServerId { get; set; } + public string Password { get; set; } + public IPAddress PublicAddress { get; set; } - public class LoginRequestPacket : IOpcodedPacket + public void Read(BinaryReader br) { - public CommOpcode Opcode { get; } = CommOpcode.LoginRequest; - public byte ServerId { get; set; } - public string Password { get; set; } - public IPAddress PublicAddress { get; set; } - - public void Read(BinaryReader br) - { - ServerId = br.ReadByte(); - Password = br.ReadLengthedString(); - PublicAddress = new IPAddress(br.ReadBytes(br.ReadByte())); - } + ServerId = br.ReadByte(); + Password = br.ReadLengthedString(); + PublicAddress = new IPAddress(br.ReadBytes(br.ReadByte())); + } - public void Write(BinaryWriter bw) - { - bw.Write((byte) Opcode); - bw.Write(ServerId); - bw.WriteLengthedString(Password); - bw.Write((byte) (PublicAddress.AddressFamily == AddressFamily.InterNetwork ? 4 : 16)); - bw.Write(PublicAddress.GetAddressBytes()); - } + public void Write(BinaryWriter bw) + { + bw.Write((byte) Opcode); + bw.Write(ServerId); + bw.WriteLengthedString(Password); + bw.Write((byte) (PublicAddress.AddressFamily == AddressFamily.InterNetwork ? 4 : 16)); + bw.Write(PublicAddress.GetAddressBytes()); } } diff --git a/src/Rasa.Shared/Packets/Communicator/LoginResponsePacket.cs b/src/Rasa.Shared/Packets/Communicator/LoginResponsePacket.cs index e7836a22..d6c6940f 100644 --- a/src/Rasa.Shared/Packets/Communicator/LoginResponsePacket.cs +++ b/src/Rasa.Shared/Packets/Communicator/LoginResponsePacket.cs @@ -1,23 +1,22 @@ using System.IO; -namespace Rasa.Packets.Communicator +namespace Rasa.Packets.Communicator; + +using Rasa.Data; + +public class LoginResponsePacket : IOpcodedPacket { - using Data; + public CommOpcode Opcode { get; } = CommOpcode.LoginResponse; + public CommLoginReason Response { get; set; } - public class LoginResponsePacket : IOpcodedPacket + public void Read(BinaryReader br) { - public CommOpcode Opcode { get; } = CommOpcode.LoginResponse; - public CommLoginReason Response { get; set; } - - public void Read(BinaryReader br) - { - Response = (CommLoginReason) br.ReadByte(); - } + Response = (CommLoginReason) br.ReadByte(); + } - public void Write(BinaryWriter bw) - { - bw.Write((byte) Opcode); - bw.Write((byte) Response); - } + public void Write(BinaryWriter bw) + { + bw.Write((byte) Opcode); + bw.Write((byte) Response); } } diff --git a/src/Rasa.Shared/Packets/Communicator/RedirectRequestPacket.cs b/src/Rasa.Shared/Packets/Communicator/RedirectRequestPacket.cs index 89e2b631..3db54772 100644 --- a/src/Rasa.Shared/Packets/Communicator/RedirectRequestPacket.cs +++ b/src/Rasa.Shared/Packets/Communicator/RedirectRequestPacket.cs @@ -1,34 +1,33 @@ using System.IO; -namespace Rasa.Packets.Communicator -{ - using Data; - using Extensions; +namespace Rasa.Packets.Communicator; - public class RedirectRequestPacket : IOpcodedPacket - { - public CommOpcode Opcode { get; } = CommOpcode.RedirectRequest; +using Rasa.Data; +using Rasa.Extensions; - public uint AccountId { get; set; } - public string Username { get; set; } - public string Email { get; set; } - public uint OneTimeKey { get; set; } +public class RedirectRequestPacket : IOpcodedPacket +{ + public CommOpcode Opcode { get; } = CommOpcode.RedirectRequest; - public void Read(BinaryReader br) - { - AccountId = br.ReadUInt32(); - Username = br.ReadLengthedString(); - Email = br.ReadLengthedString(); - OneTimeKey = br.ReadUInt32(); - } + public uint AccountId { get; set; } + public string Username { get; set; } + public string Email { get; set; } + public uint OneTimeKey { get; set; } - public void Write(BinaryWriter bw) - { - bw.Write((byte) Opcode); - bw.Write(AccountId); - bw.WriteLengthedString(Username); - bw.WriteLengthedString(Email); - bw.Write(OneTimeKey); - } + public void Read(BinaryReader br) + { + AccountId = br.ReadUInt32(); + Username = br.ReadLengthedString(); + Email = br.ReadLengthedString(); + OneTimeKey = br.ReadUInt32(); + } + + public void Write(BinaryWriter bw) + { + bw.Write((byte) Opcode); + bw.Write(AccountId); + bw.WriteLengthedString(Username); + bw.WriteLengthedString(Email); + bw.Write(OneTimeKey); } } diff --git a/src/Rasa.Shared/Packets/Communicator/RedirectResponsePacket.cs b/src/Rasa.Shared/Packets/Communicator/RedirectResponsePacket.cs index fa15c171..5d9fff4d 100644 --- a/src/Rasa.Shared/Packets/Communicator/RedirectResponsePacket.cs +++ b/src/Rasa.Shared/Packets/Communicator/RedirectResponsePacket.cs @@ -1,26 +1,25 @@ using System.IO; -namespace Rasa.Packets.Communicator +namespace Rasa.Packets.Communicator; + +using Rasa.Data; + +public class RedirectResponsePacket : IOpcodedPacket { - using Data; + public CommOpcode Opcode { get; } = CommOpcode.RedirectResponse; + public RedirectResult Response { get; set; } + public uint AccountId { get; set; } - public class RedirectResponsePacket : IOpcodedPacket + public void Read(BinaryReader br) { - public CommOpcode Opcode { get; } = CommOpcode.RedirectResponse; - public RedirectResult Response { get; set; } - public uint AccountId { get; set; } - - public void Read(BinaryReader br) - { - Response = (RedirectResult) br.ReadByte(); - AccountId = br.ReadUInt32(); - } + Response = (RedirectResult) br.ReadByte(); + AccountId = br.ReadUInt32(); + } - public void Write(BinaryWriter bw) - { - bw.Write((byte) Opcode); - bw.Write((byte) Response); - bw.Write(AccountId); - } + public void Write(BinaryWriter bw) + { + bw.Write((byte) Opcode); + bw.Write((byte) Response); + bw.Write(AccountId); } } diff --git a/src/Rasa.Shared/Packets/Communicator/ServerInfoRequestPacket.cs b/src/Rasa.Shared/Packets/Communicator/ServerInfoRequestPacket.cs index 04acc58d..80e52452 100644 --- a/src/Rasa.Shared/Packets/Communicator/ServerInfoRequestPacket.cs +++ b/src/Rasa.Shared/Packets/Communicator/ServerInfoRequestPacket.cs @@ -1,21 +1,19 @@ -using System; -using System.IO; +using System.IO; -namespace Rasa.Packets.Communicator +namespace Rasa.Packets.Communicator; + +using Rasa.Data; + +public class ServerInfoRequestPacket : IOpcodedPacket { - using Data; + public CommOpcode Opcode { get; } = CommOpcode.ServerInfoRequest; - public class ServerInfoRequestPacket : IOpcodedPacket + public void Read(BinaryReader br) { - public CommOpcode Opcode { get; } = CommOpcode.ServerInfoRequest; - - public void Read(BinaryReader br) - { - } + } - public void Write(BinaryWriter bw) - { - bw.Write((byte) Opcode); - } + public void Write(BinaryWriter bw) + { + bw.Write((byte) Opcode); } } diff --git a/src/Rasa.Shared/Packets/Communicator/ServerInfoResponsePacket.cs b/src/Rasa.Shared/Packets/Communicator/ServerInfoResponsePacket.cs index da75d9c1..e140c01a 100644 --- a/src/Rasa.Shared/Packets/Communicator/ServerInfoResponsePacket.cs +++ b/src/Rasa.Shared/Packets/Communicator/ServerInfoResponsePacket.cs @@ -1,39 +1,37 @@ -using System; -using System.IO; +using System.IO; -namespace Rasa.Packets.Communicator +namespace Rasa.Packets.Communicator; + +using Rasa.Data; + +public class ServerInfoResponsePacket : IOpcodedPacket { - using Data; + public CommOpcode Opcode { get; } = CommOpcode.ServerInfoResponse; + public int QueuePort { get; set; } + public int GamePort { get; set; } + public byte AgeLimit { get; set; } + public byte PKFlag { get; set; } + public ushort CurrentPlayers { get; set; } + public ushort MaxPlayers { get; set; } - public class ServerInfoResponsePacket : IOpcodedPacket + public void Read(BinaryReader br) { - public CommOpcode Opcode { get; } = CommOpcode.ServerInfoResponse; - public int QueuePort { get; set; } - public int GamePort { get; set; } - public byte AgeLimit { get; set; } - public byte PKFlag { get; set; } - public ushort CurrentPlayers { get; set; } - public ushort MaxPlayers { get; set; } - - public void Read(BinaryReader br) - { - QueuePort = br.ReadInt32(); - GamePort = br.ReadInt32(); - AgeLimit = br.ReadByte(); - PKFlag = br.ReadByte(); - CurrentPlayers = br.ReadUInt16(); - MaxPlayers = br.ReadUInt16(); - } + QueuePort = br.ReadInt32(); + GamePort = br.ReadInt32(); + AgeLimit = br.ReadByte(); + PKFlag = br.ReadByte(); + CurrentPlayers = br.ReadUInt16(); + MaxPlayers = br.ReadUInt16(); + } - public void Write(BinaryWriter bw) - { - bw.Write((byte) Opcode); - bw.Write(QueuePort); - bw.Write(GamePort); - bw.Write(AgeLimit); - bw.Write(PKFlag); - bw.Write(CurrentPlayers); - bw.Write(MaxPlayers); - } + public void Write(BinaryWriter bw) + { + bw.Write((byte) Opcode); + bw.Write(QueuePort); + bw.Write(GamePort); + bw.Write(AgeLimit); + bw.Write(PKFlag); + bw.Write(CurrentPlayers); + bw.Write(MaxPlayers); } } diff --git a/src/Rasa.Shared/Properties/AssemblyInfo.cs b/src/Rasa.Shared/Properties/AssemblyInfo.cs deleted file mode 100644 index 70d89a82..00000000 --- a/src/Rasa.Shared/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System.Reflection; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("Rasa.Shared")] -[assembly: AssemblyTrademark("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("97f299b7-4cb1-4437-b910-f6f84958a6cf")] diff --git a/src/Rasa.Shared/Rasa.Shared.csproj b/src/Rasa.Shared/Rasa.Shared.csproj index 6cf0067b..0885718b 100644 --- a/src/Rasa.Shared/Rasa.Shared.csproj +++ b/src/Rasa.Shared/Rasa.Shared.csproj @@ -2,7 +2,7 @@ Rasa.NET Shared - net5.0 + net7.0 Rasa.Shared Rasa.Shared 2.1.0 @@ -10,11 +10,15 @@ false false Rasa - 9.0 + 10.0 + + + + diff --git a/src/Rasa.Test/Memory/NonContiguousMemoryStreamTests.cs b/src/Rasa.Test/Memory/NonContiguousMemoryStreamTests.cs index 1541b1a9..f91f0042 100644 --- a/src/Rasa.Test/Memory/NonContiguousMemoryStreamTests.cs +++ b/src/Rasa.Test/Memory/NonContiguousMemoryStreamTests.cs @@ -1,226 +1,184 @@ using System; -using System.Buffers; using Microsoft.VisualStudio.TestTools.UnitTesting; -namespace Rasa.Test.Memory +namespace Rasa.Test.Memory; + +using Rasa.Memory; + +[TestClass] +public class NonContiguousMemoryStreamTests { - using Rasa.Memory; + [TestMethod] + public void TestLength() + { + var buffer1 = new byte[10]; + var buffer2 = new byte[20]; + var buffer3 = new byte[30]; + + using var stream = new NonContiguousMemoryStream(); + + stream.Write(buffer1); + stream.Write(buffer2); + stream.Write(buffer3, 0, buffer3.Length - 10); - [TestClass] - public class NonContiguousMemoryStreamTests + Assert.AreEqual(stream.WritePosition, buffer1.Length + buffer2.Length + buffer3.Length - 10); + } + + [TestMethod] + public void TestRead() { - [TestMethod] - public void TestLength() - { - var buffer1 = new byte[10]; - var buffer2 = new byte[20]; - var buffer3 = new byte[30]; + var buffer1 = new byte[20]; + for (var i = 0; i < buffer1.Length; ++i) + buffer1[i] = (byte)i; - using var stream = new NonContiguousMemoryStream(); + var buffer2 = new byte[40]; + for (var i = 0; i < buffer2.Length; ++i) + buffer2[i] = (byte)(buffer1.Length + i); - stream.CopyFromArray(buffer1); - stream.CopyFromArray(buffer2); - stream.CopyFromArray(buffer3, 0, buffer3.Length - 10); + var buffer3 = new byte[60]; + for (var i = 0; i < buffer3.Length; ++i) + buffer3[i] = (byte)(buffer1.Length + buffer2.Length + i); - Assert.AreEqual(stream.Length, buffer1.Length + buffer2.Length + buffer3.Length - 10); - } + using var stream = new NonContiguousMemoryStream(); - [TestMethod] - public void TestLengthManualPoolArray() - { - var buffer1 = new byte[10]; - var buffer2 = new byte[20]; - var buffer3 = ArrayPool.Shared.Rent(20); + stream.Write(buffer1); + stream.Write(buffer2); + stream.Write(buffer3); - using var stream = new NonContiguousMemoryStream(); + var read1 = new byte[30]; + var readCount1 = stream.Read(read1, 0, read1.Length); - stream.CopyFromArray(buffer1); - stream.CopyFromArray(buffer2); - stream.AddSharedPoolArray(buffer3, 20); + var read2 = new byte[20]; + var readCount2 = stream.Read(read2, 0, read2.Length); - Assert.AreEqual(stream.Length, buffer1.Length + buffer2.Length + 20); - } + var read3 = new byte[70]; + var readCount3 = stream.Read(read3, 0, read3.Length); - [TestMethod] - public void TestRead() - { - var buffer1 = new byte[20]; - for (var i = 0; i < buffer1.Length; ++i) - { - buffer1[i] = (byte)i; - } - - var buffer2 = new byte[40]; - for (var i = 0; i < buffer2.Length; ++i) - { - buffer2[i] = (byte)(buffer1.Length + i); - } - - var buffer3 = new byte[60]; - for (var i = 0; i < buffer3.Length; ++i) - { - buffer3[i] = (byte)(buffer1.Length + buffer2.Length + i); - } - - using var stream = new NonContiguousMemoryStream(); - - stream.CopyFromArray(buffer1); - stream.CopyFromArray(buffer2); - stream.CopyFromArray(buffer3); - - var read1 = new byte[30]; - var readCount1 = stream.Read(read1, 0, read1.Length); - - var read2 = new byte[20]; - var readCount2 = stream.Read(read2, 0, read2.Length); - - var read3 = new byte[70]; - var readCount3 = stream.Read(read3, 0, read3.Length); - - Assert.AreEqual(readCount1, 30); - Assert.AreEqual(readCount2, 20); - Assert.AreEqual(readCount3, 70); - Assert.AreEqual(stream.Position, stream.Length); - - // Validate read1 - for (var i = 0; i < 20; ++i) - { - Assert.AreEqual(read1[i], buffer1[i]); - } - - for (var i = 0; i < 10; ++i) - { - Assert.AreEqual(read1[20 + i], buffer2[i]); - } - - // Validate read2 - for (var i = 0; i < 20; ++i) - { - Assert.AreEqual(read2[i], buffer2[10 + i]); - } - - // Validate read3 - for (var i = 0; i < 10; ++i) - { - Assert.AreEqual(read3[i], buffer2[30 + i]); - } - - for (var i = 0; i < 60; ++i) - { - Assert.AreEqual(read3[10 + i], buffer3[i]); - } - } + Assert.AreEqual(readCount1, 30); + Assert.AreEqual(readCount2, 20); + Assert.AreEqual(readCount3, 70); + Assert.AreEqual(stream.Position, stream.WritePosition); + + // Validate read1 + for (var i = 0; i < 20; ++i) + Assert.AreEqual(read1[i], buffer1[i]); + + for (var i = 0; i < 10; ++i) + Assert.AreEqual(read1[20 + i], buffer2[i]); + + // Validate read2 + for (var i = 0; i < 20; ++i) + Assert.AreEqual(read2[i], buffer2[10 + i]); + + // Validate read3 + for (var i = 0; i < 10; ++i) + Assert.AreEqual(read3[i], buffer2[30 + i]); + + for (var i = 0; i < 60; ++i) + Assert.AreEqual(read3[10 + i], buffer3[i]); + } - [TestMethod] - public void TestRemoveBytes() + [TestMethod] + public void TestRemoveBytes() + { + var buffer1 = new byte[5]; + var buffer2 = new byte[5]; + + for (var i = 0; i < 5; ++i) { - var buffer1 = new byte[5]; - var buffer2 = new byte[5]; + buffer1[i] = (byte)i; + buffer2[i] = (byte)(i * 2); + } - for (var i = 0; i < 5; ++i) - { - buffer1[i] = (byte)i; - buffer2[i] = (byte)(i * 2); - } + using var stream = new NonContiguousMemoryStream(); - using var stream = new NonContiguousMemoryStream(); + stream.Write(buffer1); + stream.Write(buffer2); - stream.CopyFromArray(buffer1); - stream.CopyFromArray(buffer2); + var throwAwayData = new byte[2]; + stream.Read(throwAwayData, 0, 2); - var throwAwayData = new byte[2]; - stream.Read(throwAwayData, 0, 2); + stream.RemoveBytes(3); - stream.RemoveBytes(3); + var data = new byte[7]; + stream.Read(data, 0, data.Length); - var data = new byte[7]; - stream.Read(data, 0, data.Length); + Assert.AreEqual(data[0], 3); + Assert.AreEqual(data[1], 4); + Assert.AreEqual(data[2], 0); + Assert.AreEqual(data[3], 2); + Assert.AreEqual(data[4], 4); + Assert.AreEqual(data[5], 6); + Assert.AreEqual(data[6], 8); + Assert.AreEqual(stream.Position, stream.WritePosition); + } - Assert.AreEqual(data[0], 3); - Assert.AreEqual(data[1], 4); - Assert.AreEqual(data[2], 0); - Assert.AreEqual(data[3], 2); - Assert.AreEqual(data[4], 4); - Assert.AreEqual(data[5], 6); - Assert.AreEqual(data[6], 8); - Assert.AreEqual(stream.Length, buffer1.Length + buffer2.Length - 3); - Assert.AreEqual(stream.Position, stream.Length); - } + [TestMethod] + public void TestRemoveMoreBytes() + { + var buffer = new byte[5]; - [TestMethod] - public void TestRemoveMoreBytes() - { - var buffer1 = new byte[5]; - var buffer2 = new byte[5]; + using var stream = new NonContiguousMemoryStream(); - for (var i = 0; i < 5; ++i) - { - buffer1[i] = (byte)i; - buffer2[i] = (byte)(i * 2); - } + stream.Write(buffer); + stream.Write(buffer); - using var stream = new NonContiguousMemoryStream(); + var throwAwayData = new byte[6]; + stream.Read(throwAwayData, 0, 6); - stream.CopyFromArray(buffer1); - stream.CopyFromArray(buffer2); + stream.RemoveBytes(9); - var throwAwayData = new byte[6]; - stream.Read(throwAwayData, 0, 6); + Assert.AreEqual(stream.Position, 0); + Assert.AreEqual(stream.WritePosition, 1); + } - stream.RemoveBytes(9); + [TestMethod] + public void TestRemoveAllBytes() + { + var buffer = new byte[5]; - Assert.AreEqual(stream.Length, 1); - Assert.AreEqual(stream.Position, 0); - } + using var stream = new NonContiguousMemoryStream(); - [TestMethod] - public void TestRemoveAllBytes() - { - var buffer1 = new byte[5]; - var buffer2 = new byte[5]; + stream.Write(buffer); + stream.Write(buffer); - for (var i = 0; i < 5; ++i) - { - buffer1[i] = (byte)i; - buffer2[i] = (byte)(i * 2); - } + var throwAwayData = new byte[6]; + stream.Read(throwAwayData, 0, 6); - using var stream = new NonContiguousMemoryStream(); + stream.RemoveBytes(10); - stream.CopyFromArray(buffer1); - stream.CopyFromArray(buffer2); + Assert.AreEqual(stream.Position, 0); + Assert.AreEqual(stream.WritePosition, 0); + } - var throwAwayData = new byte[6]; - stream.Read(throwAwayData, 0, 6); + [TestMethod] + public void TestRemoveTooManyBytes() + { + var buffer = new byte[5]; - stream.RemoveBytes(10); + using var stream = new NonContiguousMemoryStream(); - Assert.AreEqual(stream.Length, 0); - Assert.AreEqual(stream.Position, 0); - } + stream.Write(buffer); + stream.Write(buffer); - [TestMethod] - public void TestRemoveTooManyBytes() - { - var buffer1 = new byte[5]; - var buffer2 = new byte[5]; + Assert.ThrowsException(() => stream.RemoveBytes((int)stream.Length + 1)); + } - for (var i = 0; i < 5; ++i) - { - buffer1[i] = (byte)i; - buffer2[i] = (byte)(i * 2); - } + [TestMethod] + public void TestCopyToWithCount() + { + var buffer = new byte[5]; - using var stream = new NonContiguousMemoryStream(); + using var stream1 = new NonContiguousMemoryStream(); + using var stream2 = new NonContiguousMemoryStream(); - stream.CopyFromArray(buffer1); - stream.CopyFromArray(buffer2); + stream1.Write(buffer); + stream1.CopyToWithCount(stream2, 10); - Assert.ThrowsException(() => - { - stream.RemoveBytes(11); - }); - } + Assert.AreEqual(5, stream1.Position); + Assert.AreEqual(5, stream1.WritePosition); + Assert.AreEqual(0, stream2.Position); + Assert.AreEqual(5, stream2.WritePosition); } } diff --git a/src/Rasa.Test/Rasa.Test.csproj b/src/Rasa.Test/Rasa.Test.csproj index a7b1e180..64123ed3 100644 --- a/src/Rasa.Test/Rasa.Test.csproj +++ b/src/Rasa.Test/Rasa.Test.csproj @@ -1,11 +1,12 @@ - net5.0 + net7.0 false Rasa.Test + 10.0 diff --git a/src/Rasa.Test/UnitTest1.cs b/src/Rasa.Test/UnitTest1.cs deleted file mode 100644 index b32f0145..00000000 --- a/src/Rasa.Test/UnitTest1.cs +++ /dev/null @@ -1,14 +0,0 @@ -using Microsoft.VisualStudio.TestTools.UnitTesting; - -namespace Rasa.Test -{ - // WIP PH: to be removed when tests are added - [TestClass] - public class UnitTest1 - { - [TestMethod] - public void TestMethod1() - { - } - } -} diff --git a/src/Rasa.Utils/Commands/CommandProcessor.cs b/src/Rasa.Utils/Commands/CommandProcessor.cs index 7bf2cab0..00f69e5e 100644 --- a/src/Rasa.Utils/Commands/CommandProcessor.cs +++ b/src/Rasa.Utils/Commands/CommandProcessor.cs @@ -1,65 +1,63 @@ -using System; -using System.Collections.Generic; -using System.Threading; +using System.Threading; -namespace Rasa.Commands +namespace Rasa.Commands; + +public static class CommandProcessor { - public static class CommandProcessor - { - private static readonly Dictionary> Commands = new Dictionary>(); + private static readonly Dictionary> Commands = new(); - public static void ProcessCommand(CancellationToken stopToken) + public static void ProcessCommand(CancellationToken stopToken) + { + var command = ReadCommand(stopToken); + if (string.IsNullOrWhiteSpace(command)) + return; + + // Nice to have TODO: Handle parameters escaped by quotes, which could contain spaces! + // Example: test "this is a test" 10 + // Expected parameters: + // - "test" + // - "this is a test" + // - "10" + var parts = command.Split(' '); + if (parts.Length < 1) + return; + + if (Commands.TryGetValue(parts[0], out var value)) { - var command = ReadCommand(stopToken); - if (string.IsNullOrWhiteSpace(command)) - return; - - var parts = command.Split(' '); - if (parts.Length < 1) - return; + value(parts); + return; + } - if (Commands.ContainsKey(parts[0])) - { - Commands[parts[0]](parts); - return; - } + Logger.WriteLog(LogType.Command, $"Invalid command: {command}"); + } - Logger.WriteLog(LogType.Command, $"Invalid command: {command}"); - } + private static string ReadCommand(CancellationToken stopToken) + { + var command = string.Empty; - private static string ReadCommand(CancellationToken stopToken) + while (!stopToken.IsCancellationRequested) { - var command = string.Empty; - while (!stopToken.IsCancellationRequested) + if (Console.KeyAvailable) { - if (Console.KeyAvailable) + var key = Console.ReadKey(); + switch (key.Key) { - var key = Console.ReadKey(); - switch (key.Key) - { - case ConsoleKey.Enter: - return command; - case ConsoleKey.Backspace: - command = command.Substring(0, command.Length - 1); - break; - default: - command += key.KeyChar; - break; - } - } - } - return null; - } + case ConsoleKey.Enter: + return command; - public static void RegisterCommand(string name, Action handler) - { - Commands.Add(name, handler); - } + case ConsoleKey.Backspace: + command = command[..^1]; + break; - public static void RemoveCommand(string name) - { - if (Commands.ContainsKey(name)) - Commands.Remove(name); + default: + command += key.KeyChar; + break; + } + } } + return string.Empty; } + + public static void RegisterCommand(string name, Action handler) => Commands.Add(name, handler); + public static void RemoveCommand(string name) => Commands.Remove(name); } diff --git a/src/Rasa.Utils/Config/Configuration.cs b/src/Rasa.Utils/Config/Configuration.cs index 0037c232..6d41c016 100644 --- a/src/Rasa.Utils/Config/Configuration.cs +++ b/src/Rasa.Utils/Config/Configuration.cs @@ -1,38 +1,38 @@ using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Primitives; -namespace Rasa.Config +namespace Rasa.Config; + +public static class Configuration { - public static class Configuration + public delegate void OnLoadDelegate(); + + private static IChangeToken? Token { get; set; } + private static IConfiguration? Config { get; set; } + + public static OnLoadDelegate? OnLoad { get; set; } + public static OnLoadDelegate? OnReLoad { get; set; } + + public static void Load() + { + var builder = new ConfigurationBuilder() + .AddJsonFile("appsettings.json", false, true) + .AddJsonFile("appsettings.env.json", true, true); + + Config = builder.Build(); + Token = Config.GetReloadToken(); + Token.RegisterChangeCallback(OnChange, null); + + OnLoad?.Invoke(); + } + + public static void OnChange(object state) + { + OnReLoad?.Invoke(); + } + + public static void Bind(object obj) { - public delegate void OnLoadDelegate(); - - public static IConfiguration Config { get; private set; } - public static IChangeToken Token { get; private set; } - public static OnLoadDelegate OnLoad; - public static OnLoadDelegate OnReLoad; - - public static void Load() - { - var builder = new ConfigurationBuilder() - .AddJsonFile("appsettings.json", false, true) - .AddJsonFile("appsettings.env.json", true, true); - - Config = builder.Build(); - Token = Config.GetReloadToken(); - Token.RegisterChangeCallback(OnChange, null); - - OnLoad?.Invoke(); - } - - public static void OnChange(object state) - { - OnReLoad?.Invoke(); - } - - public static void Bind(object obj) - { - Config.Bind(obj); - } + Config.Bind(obj); } } diff --git a/src/Rasa.Utils/Config/SocketAsyncConfig.cs b/src/Rasa.Utils/Config/SocketAsyncConfig.cs index 04c5dee9..652c9a1d 100644 --- a/src/Rasa.Utils/Config/SocketAsyncConfig.cs +++ b/src/Rasa.Utils/Config/SocketAsyncConfig.cs @@ -1,9 +1,8 @@ -namespace Rasa.Config +namespace Rasa.Config; + +public class SocketAsyncConfig { - public class SocketAsyncConfig - { - public int BufferSize { get; set; } - public int MaxClients { get; set; } - public int ConcurrentOperationsByClient { get; set; } - } + public int BufferSize { get; set; } + public int MaxClients { get; set; } + public int ConcurrentOperationsByClient { get; set; } } diff --git a/src/Rasa.Utils/Cryptography/Auth/Blowfish.cs b/src/Rasa.Utils/Cryptography/Auth/Blowfish.cs index 8097eb97..1ef782fa 100644 --- a/src/Rasa.Utils/Cryptography/Auth/Blowfish.cs +++ b/src/Rasa.Utils/Cryptography/Auth/Blowfish.cs @@ -1,249 +1,248 @@ -namespace Rasa.Cryptography.Auth +namespace Rasa.Cryptography.Auth; + +public static class Blowfish { - public static class Blowfish + private static readonly uint[] SBox0 = { - private static readonly uint[] SBox0 = - { - 0x8F9ED754, 0xDE268B45, 0x8B603DE8, 0x7E830682, 0x4D8C92C2, 0x1F1F2E2F, 0x5F1B3F35, 0xD6173E34, 0xAFE00B88, 0xA1E325E3, - 0xC356434D, 0xB61201FF, 0xE58461CD, 0x4174E9C2, 0xD2CE47DA, 0x49F022B6, 0x5ECEF55B, 0x760A2EC9, 0x10B9E948, 0xFDE74C37, - 0x19979258, 0x02F3CB2E, 0xF8980DD2, 0x2DB527FB, 0x97062F82, 0x3C32D594, 0x1B5BDDE2, 0xF82971CF, 0x1F6F0878, 0x6D78BBD5, - 0x6196F89F, 0x569FD691, 0x03488E84, 0xE046D2F3, 0x535B17F5, 0x698A768D, 0xCC799496, 0x2BAEC634, 0x35581C0F, 0x55935259, - 0x0268020D, 0x752F43A1, 0x83B394D0, 0x3574D98B, 0x7C8B0790, 0x2750E170, 0xE6895DA3, 0x0F678CEE, 0x2E8CDD42, 0x9064E0AC, - 0xD6DD3731, 0x5C6DAC20, 0xF9CBF938, 0xC1900D84, 0x25367C97, 0xB3BDCF49, 0x7412F482, 0x3CD81738, 0x54F6CA51, 0x828BC795, - 0x566DAF91, 0xEB5696DB, 0xAACC3D6E, 0xAA14D97E, 0x3C4BB972, 0x0E121D89, 0xFC5031EA, 0x1299927A, 0x035557FE, 0x9C12D8B0, - 0x47352F1E, 0x1344F64F, 0x54BB93E6, 0x4D58422F, 0xE4C8CA2C, 0x2A0CD8B0, 0x383449D7, 0x94D97D61, 0xCEC43FA8, 0x9D23BC3B, - 0x17D1FD18, 0x7A2D2C34, 0xB376D8D4, 0xBDAE6456, 0xA62E9E8D, 0x891E0E89, 0xB056F7AF, 0xCD7CB83E, 0x524531BD, 0x3B74A510, - 0x8B40002C, 0x1A31D043, 0x124877B8, 0xC2D24143, 0xD577D373, 0x223947AA, 0x5AFF02F0, 0x305BE9F7, 0x56AFC75B, 0xB8F358B3, - 0x1CF0A301, 0x472BB05A, 0xF6F6ED5F, 0x02729272, 0x90A81579, 0xF4F8F16C, 0x2A233515, 0xF073FB22, 0x828A1C5F, 0x3DC85BB6, - 0xAF006F14, 0x9F78BCB3, 0x20375A44, 0x1DA3DE5C, 0x8A47CB7A, 0x4B3AED7A, 0x1B914FE6, 0x6C0826EE, 0x453D2CFE, 0xC8147FD3, - 0xA36209C0, 0x54976ECC, 0x6F1AE267, 0xE3BAF8BE, 0x3FAD1643, 0x74F58A2B, 0xD229B027, 0x63070149, 0x53608FC5, 0xFBD9542A, - 0x03315724, 0x4F3DC56A, 0x361EEF40, 0xFD860064, 0x6A942C64, 0xF77CC94F, 0x52A3F8B2, 0xA201CC09, 0xBF0F4778, 0x51327531, - 0x4F4F79F1, 0x044E7118, 0x99F72515, 0x3418106E, 0x51C4EE43, 0x779E88CE, 0x3FAF065B, 0x457D5482, 0xAFC496AC, 0x0289AF99, - 0xC3C19353, 0x79F74242, 0xF89F5D59, 0x96321B7A, 0x1F20FAB7, 0x21B5E67E, 0x02E3338F, 0x3C09A2A9, 0x64E717B4, 0x34E90333, - 0x13018018, 0x4E763E1C, 0xC6F51A99, 0xE822E779, 0x2BDCB520, 0xEBD4FF36, 0xF7E3F09B, 0x3C2945F9, 0x3B7E6D88, 0x5C974072, - 0x13AFEF9D, 0x67B557BD, 0xB16951C7, 0x8BD2684F, 0x7EBC9A05, 0x8D21C212, 0x6DFFEECF, 0x030DA6B6, 0xF7E19A75, 0xC0057743, - 0x2D235EFE, 0xB6CA5F71, 0x7B57A431, 0x43DC86C9, 0x7FEF171D, 0x393E9378, 0xCE80C227, 0x96ED3538, 0x120D6062, 0xA9D31954, - 0x86611B3B, 0x123670AD, 0x9B2A40D7, 0x50CF4A9F, 0xB9FCEDE4, 0xAEA71031, 0x5548214C, 0x8BEE614C, 0x06310727, 0xFE1113CD, - 0x19B1F144, 0x129F322A, 0x81E12C34, 0x5AD816EC, 0x84074DF2, 0x01902E4D, 0xEA209697, 0xA7C71FF1, 0xBC625F3C, 0xB50E8BA1, - 0x05185608, 0x0145B9E9, 0xC81E7A99, 0xE3B84F67, 0xAED399D5, 0xF38C66EC, 0x75D487A1, 0xEA78BD8C, 0xBE717AEE, 0x5A899BBE, - 0xFECDE525, 0x93754F27, 0xAD2A32C4, 0x058C4311, 0xD657FE29, 0x5006225F, 0xF6B32306, 0x38F4A913, 0x7F7DC390, 0x21A32A8D, - 0x5AFD5DC2, 0x9110F958, 0x19082856, 0x9231E09F, 0xB556B86E, 0x9FA974B0, 0x1BAFF685, 0xFD7C2874, 0x9CEEC30D, 0x8CFBE836, - 0xB64BCCE1, 0x592AA53A, 0x47140600, 0x50361A84, 0x9B7957EE, 0x259A238C, 0x1D814AFC, 0x736F7C8B, 0x53F88396, 0x45214287, - 0x37108BCC, 0xFEDB2BFC, 0xF79E9031, 0xEE776BD5, 0xC2F03D79, 0xC204F563 - }; - - private static readonly uint[] SBox1 = - { - 0xD34E8403, 0xBF03483E, 0xC6C09D77, 0xFA3FDD25, 0xFB248D64, 0xF6EC5848, 0x1E00FECA, 0x5A396266, 0x8A9F02C3, 0x34C17FA9, - 0xA3CBF5F1, 0xB3277677, 0xA516DE39, 0xA2F78346, 0x75D66F07, 0x5DD4EC0B, 0x8E498C1E, 0xDDB7EFF1, 0x8A7A684C, 0x2583A8CA, - 0x96799106, 0x9AB1B5CF, 0x88182015, 0xC8495BF4, 0xDAE57B55, 0xE1524CD8, 0xC68E8256, 0x0EA3AA51, 0x82399FC9, 0x02C20F89, - 0xE78C0156, 0x2FC648C5, 0x7501EBC8, 0x9184587E, 0xAC03BDB2, 0xB0EFA2D3, 0xB570F584, 0x50555B23, 0x72CA1DC9, 0xADD887D4, - 0x5D224173, 0xD0E23804, 0x2F382317, 0x11AE5FF1, 0x6B0F87A3, 0x0BCD7EA5, 0xAB217329, 0x87CF6DD2, 0x4B240D7E, 0xA13A6E7F, - 0x73BC1FA4, 0x2DB14A55, 0x0AADB1AE, 0x3EA165F8, 0x0FD1C4C2, 0xAB5D34EE, 0x963C233D, 0x3181A4D8, 0xE1974DB9, 0x5F6E8F9B, - 0x8FACDEAE, 0xD2AF3AC4, 0x1EF2D068, 0xBE30B53F, 0x1C85EF88, 0x5827088F, 0x2C2DF598, 0xEC93BD25, 0x638E94B8, 0x4273F25D, - 0xA0BA16DC, 0x20FE1F5B, 0xD803AE9A, 0xC8E51A79, 0x16D0B547, 0x8ACEB825, 0x2E753386, 0xB5A0D165, 0x3C0A3936, 0xA5A69665, - 0x5112622E, 0xCB14F3FE, 0x5220FB31, 0xACF6571F, 0xE1C4545D, 0x4AD1F627, 0x049969BE, 0xD86CE318, 0x0BA05692, 0x67A9EF1B, - 0x460D97C8, 0x63699147, 0xCB26D353, 0x4A04FAED, 0x406B5E1E, 0x451C90AA, 0x5BF82BD2, 0x3511819A, 0xA4C22A9B, 0xB63B1F90, - 0x11EC62E6, 0x3CE3B12D, 0xBC0BB19C, 0x2E3A6771, 0x751C66FB, 0xAC1E1C07, 0x5194970F, 0x30105C7D, 0x517D73C2, 0xF3687B1A, - 0x3B378F6D, 0x974E6FCE, 0xD4C9C4D6, 0x81474A4B, 0x0EFB98D7, 0xCB6E8DE7, 0xB1BC3374, 0x8B7CC90F, 0xC889EA3D, 0x5DCA7132, - 0xC86136E1, 0xE04D3E50, 0x82507591, 0x34D151DC, 0xB15A8467, 0x58ADBB11, 0x70A53704, 0x8683D2BF, 0x58C024A6, 0xFA2820B7, - 0x93D99E4B, 0x14C55615, 0x5E476521, 0x42E4FAC6, 0x979AF6B0, 0x1D6C9A2B, 0xF855EAE7, 0x4C5C7BC2, 0x96B69C00, 0x52BC9D74, - 0x7A4CED74, 0xEC4C6055, 0x19CB8441, 0x446FE6AE, 0xD7FAD48D, 0x588FC505, 0xB0EFFB52, 0x43161311, 0xEF23CC58, 0xE5A2BC7F, - 0xF9108822, 0x7984A3AC, 0x83429D92, 0x5123C11D, 0x44E1EC67, 0xF540A00D, 0x4512E4FF, 0x7147C169, 0x81A1CA2E, 0x2D3752A1, - 0x2F52DDD8, 0x3397FAA5, 0x3EB16270, 0xDD8CB3E4, 0x3075320B, 0x05C2776A, 0xF628203C, 0x4243A45C, 0x199B3F61, 0x25EFD41F, - 0x6259C453, 0x9CAADB4A, 0x1CDD27ED, 0x2ACD03FA, 0x36F183E1, 0xFB183183, 0xD2D616DD, 0x09CC2A91, 0x0E454E25, 0x71515F2B, - 0x024049D1, 0x4ECD9BEA, 0x655F6720, 0x08EE1543, 0x5C9671BD, 0x1B580057, 0xA91CD924, 0xE934B344, 0x8A527C52, 0x7A2F1E38, - 0xE19F70BD, 0x1F9BABDC, 0xA07342B1, 0x3AEE70CF, 0x06A493E7, 0xE51ABE3C, 0x35635F68, 0x75DB3F19, 0xD49C2E0F, 0x2B0436E1, - 0xD06BD8F7, 0x282B88CE, 0x3B544D02, 0xC30D588D, 0x11D742F1, 0x19EE7C89, 0x8B2283B4, 0xF86B33F6, 0xB5BF4BE3, 0x398D21CE, - 0x12D48FAE, 0x33AE1426, 0xF14AA6D8, 0xE76F4CB6, 0x9D0F0A45, 0x61F49691, 0x7E5B88D7, 0xF66F2C93, 0xA7BD4A69, 0xE4135254, - 0x586A904E, 0xCE6FF2FF, 0xEC15B527, 0x2F054B1A, 0xFFD9FDCB, 0x3BBD3D45, 0x7803085F, 0xE300E291, 0xBCF358D8, 0x35A425C5, - 0x51C1156C, 0x220D046B, 0x236F6A03, 0x7C1E1ADE, 0x1550E891, 0xAE876E17, 0xF4E76076, 0x785033A4, 0x9068DDDA, 0xAF97FF1C, - 0xCF6456F7, 0xFA3C0759, 0x989E6E4A, 0xFF430625, 0x1ED8108F, 0xBE434C75, 0xAAE89ED8, 0x54C23D46, 0x01448BB5, 0x0D5E491B, - 0xCD14A9D9, 0x62435446, 0x22F26922, 0x26B6868A, 0xDAB278CD, 0x6D761F30 - }; - - private static readonly uint[] SBox2 = - { - 0x8827EC01, 0xCF9DA39D, 0xE440EEFE, 0x57FA1D50, 0xBE8D60C4, 0xE7CA8452, 0x8B4563B5, 0x3D0BC2DB, 0x3CF23903, 0xF56FFA15, - 0xFEA3A963, 0x3E9B4C56, 0xCB630C3F, 0x4BDBD5DE, 0xD842E38C, 0xC27B2F0B, 0x366B4F72, 0xE7CE2382, 0xC598AD11, 0xD0B3907A, - 0x7096A464, 0x30039092, 0x3D0F0EE1, 0xE3DE8054, 0x74256D6A, 0x762E23D3, 0x1F018042, 0x8BB16D2F, 0xF28DFE28, 0xAE1B6BFC, - 0x758BBA20, 0x8B556E71, 0x52EA4BD8, 0x27019580, 0x6CA36CAC, 0x34ED1819, 0x52BEEAEE, 0xA2863969, 0x742CDCFD, 0x12A8575B, - 0x74C4A6C7, 0xEC58EC6A, 0x95015F78, 0x3974D185, 0x10930D31, 0x91403623, 0xA06108B7, 0x6BC0F09D, 0x51EA0BBA, 0x26E42E0C, - 0x72C2D8C2, 0x3FFB7D9D, 0x6DA018E8, 0x911898C1, 0x3B9E5E0A, 0x6F0A6651, 0xDAC883C1, 0x5EDA7E00, 0xC9D7D94D, 0xE594A5E3, - 0x5CD2EBCD, 0x522A38A9, 0x69DE4E27, 0xFB5A3764, 0x4FC3A97D, 0x8DED76BE, 0x64AD536F, 0xEA7D4239, 0x87250D95, 0x5C4EE072, - 0xC5A01A30, 0x32180EA3, 0x2F764CF2, 0x8641BBF6, 0x4AE31434, 0x8C816457, 0xB84D03FF, 0xFE33F1BA, 0x8B03BCEB, 0x623A74DB, - 0x3AD8BF5A, 0x8508B545, 0x2FBE42E5, 0x701A0E20, 0xA16F47A6, 0x88C90CE6, 0xB7FB8324, 0x6040F262, 0x85876170, 0x745E1CAF, - 0x26678A49, 0xB33E84C4, 0xEB2F4ABE, 0xAF2AD27A, 0x6F2DAC31, 0xA288FE23, 0x84772FE8, 0x364B5891, 0x337A337F, 0xF787B5AA, - 0xD46F21C7, 0xCB822929, 0x7D2B9A14, 0x669D3751, 0x1535FB1F, 0x6D25FD16, 0x03D3B457, 0xEE6F47AB, 0x144C86E2, 0x6DFEEA1F, - 0x5BC7C620, 0x15926631, 0xDCD00099, 0x3CAE2AA8, 0xF64BA88B, 0xAA26A82E, 0xFB6589A2, 0xE8D7E24F, 0xC7887C10, 0x1E9F0148, - 0x45D0FBBD, 0x11E79F21, 0x1B9B8D6E, 0x516C6B9C, 0x22EAA069, 0xC224E0A9, 0x9D3271FF, 0x1B645D6E, 0xC2269118, 0x6FE5B05E, - 0x116B9CB5, 0xFE09039C, 0x4B2F3EF5, 0xD4E6E014, 0xC06B3926, 0xA290733D, 0x5933F450, 0x0A430CEB, 0xD6D9AE99, 0xFE0FB248, - 0x0CBDED1F, 0xA7C42B0F, 0xCBF1DD67, 0x3AABC4DD, 0x202C46B0, 0x74FA6114, 0xDDDD0B81, 0x3D73D371, 0xFE3AA063, 0x06632C0D, - 0xD3F2CEC1, 0x75633E7A, 0x03C2680F, 0x6E57E6A0, 0x08E1CC02, 0xB7A1E1E7, 0x7841C231, 0xDFC6E45F, 0x7D6C3B45, 0x0A39A10E, - 0xAA43F0C9, 0x241B4681, 0x2D49C364, 0x14121072, 0xC6491219, 0x5BAECAA6, 0x6D6454D7, 0xA0EDD37B, 0x14F7C53A, 0xA7958956, - 0x5AEA9B5A, 0xA7B729DB, 0xE5C6F870, 0xF1EC12F0, 0x3AD09442, 0x37C3436C, 0x8AC1732B, 0x947172B3, 0xE37DE70F, 0x61918A84, - 0x8450DDF9, 0x7BB003D7, 0x453FAD19, 0x75741112, 0x3EF71741, 0xA1DD8929, 0x4AB2FC3D, 0x43DCB136, 0x9A3F11CE, 0xFFE78AE8, - 0x715D7A6C, 0x874E5B2F, 0x329D635C, 0xF81E3AFB, 0xAD36B9C6, 0xCA98651D, 0x62DA42B2, 0x4244E0B4, 0x9C3F58C7, 0x7CAD2631, - 0xFC145A29, 0x3F78A2CB, 0xA34E0474, 0xF1621CE6, 0xDBF434AA, 0xDCCDDED9, 0x9DE873AB, 0xBB612049, 0xF7A893F6, 0x7F28ED42, - 0xC1E4F486, 0x8C6E6433, 0xE4A56261, 0x81A8A755, 0x6E81EFA4, 0xFC48276D, 0x05E10E00, 0xE8E32846, 0x45A21ED4, 0xB7993920, - 0xC784A677, 0x28DD2691, 0x502D9009, 0xB46D43A4, 0x4B7568F9, 0xFD18FD42, 0x706C76CF, 0x38B971F5, 0xD67CD5EA, 0xBB67318C, - 0x6AC2CE3A, 0xCA6BD108, 0x40687C40, 0x4E6A0D94, 0x95F611BE, 0x44C69FC4, 0x20084E67, 0x7F035D80, 0x12FB31E5, 0x743109A8, - 0x423D111C, 0x3F2C68A2, 0xF899CCA4, 0xCCFD0B82, 0x4C102D3A, 0x7DBFAB46, 0xE43697CA, 0x8E9CF7C0, 0xC1E614E7, 0x88D6B104, - 0x7B9A9DC3, 0xB99DA600, 0x5D3F1D52, 0x8FADF78D, 0xFEDE4FEE, 0x5025AC81 - }; - - private static readonly uint[] SBox3 = - { - 0xAAE6F852, 0x753D5BA2, 0x34495010, 0xD0E618CF, 0xC9E43DCA, 0xBB63E9C0, 0x52CF10C8, 0xA410D859, 0xEF12A444, 0x737D3E2B, - 0x2C3C27C5, 0x234BC11C, 0x4AC9DEFD, 0x465B6E59, 0xF1B5156B, 0x14FEAE51, 0xD76B93AB, 0x57CAEB33, 0x2F44A9FF, 0x3F45F135, - 0xBCB372CA, 0x83E084E4, 0x7BFF6B7A, 0x39432B26, 0x40F65BFB, 0x24042E97, 0x1151BC51, 0xF0C12A3D, 0xF2335B74, 0x74EA34A4, - 0x49DCCE86, 0x9963260E, 0xE1667004, 0x0103BDFE, 0xFA597032, 0xFD4DE20E, 0x00485105, 0xA5D23BAE, 0xC37CFCA0, 0x440081E4, - 0xAB264B22, 0x0E6459A8, 0x4190A3C1, 0x442C8B86, 0x8902B297, 0x9BE6C831, 0x28F908D9, 0x4B346736, 0xC82D95CD, 0x0D87059B, - 0x29226AB3, 0x86D876B4, 0xE86A1280, 0x19CF1382, 0x6504C32F, 0xDDA19AAF, 0x2417F345, 0xF0EFED61, 0x4129EDD1, 0xEE154CD7, - 0xCE8C6231, 0x44E69BB8, 0x2B4189D4, 0x5156E779, 0x4FC32785, 0x4334E1C4, 0xD66BB347, 0x7104463E, 0x90FB6A38, 0x884977D8, - 0x620B647A, 0x1B83D9E1, 0x48F4B7AB, 0x134B9CC7, 0xDF67C5CE, 0x155FC624, 0xF674983D, 0x6F542DC8, 0x3A80CC22, 0xF8B53B0C, - 0x35883F85, 0xA9A4F8C3, 0x47BF7BDD, 0x726F7E95, 0x0A6F0147, 0xADFA327C, 0xAA42D26A, 0x5C24C2F8, 0xDF22EF5E, 0x2F245CAC, - 0x6F3AC577, 0x3C995DD0, 0x08931D80, 0x3179A274, 0x182641BE, 0x4B410C02, 0x2C7E6849, 0x05C8A035, 0x931C9CFB, 0xB93DF6C1, - 0xF61DF996, 0xE41D2366, 0x87B7906E, 0xBB0BEDB5, 0xA5D7F85C, 0xCF4EA254, 0x2F6245F4, 0x41EAB256, 0x20451B82, 0x8CB97B29, - 0xBA51158D, 0xE8E35361, 0xEAF22516, 0x327D9523, 0x1017F8BA, 0xF930F281, 0x8C44C91F, 0x3B738D2F, 0xA64AF845, 0x197EA779, - 0x511D5001, 0x9EA29B9F, 0x41862F0F, 0x1B3FA8C0, 0x433AE22F, 0xA0B55038, 0x7E6FE78F, 0xD6E55D13, 0x214207CE, 0x45744A04, - 0xB39EADEA, 0x7CE97F1F, 0x0989A02A, 0xD644F365, 0x6EFDB995, 0xB205CDD9, 0xB21B44A9, 0x57C5BB1F, 0x2C80920D, 0xB680273E, - 0x460B81CC, 0x012CA81A, 0x08BDF12A, 0x05433744, 0x2FC0DDE9, 0x09F72E23, 0xBEA49FC7, 0x5421A114, 0xC44DDA7B, 0xE49DBAB6, - 0x487B7377, 0xD282E10F, 0x6D0C3196, 0x61AE90BB, 0xBF348266, 0x30C75585, 0x2EAD11A5, 0xA53422FD, 0x989717D2, 0x2032CBD1, - 0x0C491518, 0xB02F4E56, 0x4DF3A162, 0xD40DA7E8, 0x8519BD5C, 0xEBC1FC82, 0x2FCAD29E, 0x4456139F, 0x186269F3, 0x4DCB58A5, - 0x6C8503F7, 0x8A04C438, 0x6A6B0044, 0xE05AA61A, 0xA29334C4, 0x8987A82E, 0xF0BA7EB7, 0xBD18C285, 0x06B0B028, 0xA0A66690, - 0x0F4BCA36, 0xD570CDCE, 0x1ECFFC31, 0xD601B847, 0x880F1BD8, 0x22D41437, 0x029BBDA9, 0xF2EDD463, 0x5A916D8A, 0xD704954F, - 0x30570329, 0x0BC2564E, 0xB44D946E, 0x26F727AC, 0x45657F92, 0x1AD11FB7, 0xB14F2F06, 0x891AF3ED, 0x994418B5, 0x9DC6E341, - 0x62BB4700, 0xDAE2A3E4, 0x07D27364, 0x2FD1F62F, 0x8957EA89, 0x2F6980C9, 0xB8BBF8F9, 0x5D02788A, 0xE5954184, 0x4308FE8D, - 0xD777F756, 0xE8D1FB93, 0x5504EF0A, 0x474B51C4, 0x5DA6017C, 0x5B156C13, 0xDE760633, 0xC17D04FE, 0xF25BEF47, 0x5F63CD38, - 0x4D43CCEB, 0xFE65C9C7, 0xF38F5ED6, 0x7F2E55D9, 0x75D19CC6, 0x03B6CE3F, 0x829A7880, 0xF8F658B5, 0x86C2468A, 0xD5C52A72, - 0xA73025EA, 0x091DDE9E, 0xA2C09F5D, 0xEBEBDBF0, 0xD60C9AEA, 0xEDB1C3D3, 0x202D9E65, 0x9DEF99BF, 0x306CFC61, 0x325BCAE1, - 0x570ABC2B, 0x9976F185, 0x4518E177, 0xAF5D0B2A, 0x17F9FDA0, 0x264AD959, 0x5A81DD68, 0xC921D161, 0xE1CE2049, 0xA3685311, - 0xFBFBBA97, 0x1A21E8AC, 0x5BCE2943, 0x7D758A7D, 0x5D598AA2, 0x8971150B - }; - - private static readonly uint[] PBox = - { - 0xAE915BC6, 0x15426B3F, 0x79ED8A9A, 0x0E1C4091, 0xFBB7286A, 0x1854506C, 0xF620245D, 0x9733B6DE, 0x6FB18C28, - 0x4C8B7C70, 0x85E2D4F6, 0xE4936A12, 0xAE6CDF53, 0x95CB3D66, 0xB43A52D3, 0xE9BDD2DE, 0xD138BDA0, 0x7B584F44 - }; - - /// - /// Encrypts the specified byte array with no offset and full length. - /// - /// The byte array to encrypt. - public static void Encrypt(byte[] data) - { - Encrypt(data, 0, data.Length); - } - - /// - /// Encrypts the specified byte array at a given offset for a given length. - /// - /// The byte array to encrypt. - /// The offset at which to begin. - /// The length for which to encrypt. - public static void Encrypt(byte[] data, int offset, int length) - { - var blocks = length >> 3; + 0x8F9ED754, 0xDE268B45, 0x8B603DE8, 0x7E830682, 0x4D8C92C2, 0x1F1F2E2F, 0x5F1B3F35, 0xD6173E34, 0xAFE00B88, 0xA1E325E3, + 0xC356434D, 0xB61201FF, 0xE58461CD, 0x4174E9C2, 0xD2CE47DA, 0x49F022B6, 0x5ECEF55B, 0x760A2EC9, 0x10B9E948, 0xFDE74C37, + 0x19979258, 0x02F3CB2E, 0xF8980DD2, 0x2DB527FB, 0x97062F82, 0x3C32D594, 0x1B5BDDE2, 0xF82971CF, 0x1F6F0878, 0x6D78BBD5, + 0x6196F89F, 0x569FD691, 0x03488E84, 0xE046D2F3, 0x535B17F5, 0x698A768D, 0xCC799496, 0x2BAEC634, 0x35581C0F, 0x55935259, + 0x0268020D, 0x752F43A1, 0x83B394D0, 0x3574D98B, 0x7C8B0790, 0x2750E170, 0xE6895DA3, 0x0F678CEE, 0x2E8CDD42, 0x9064E0AC, + 0xD6DD3731, 0x5C6DAC20, 0xF9CBF938, 0xC1900D84, 0x25367C97, 0xB3BDCF49, 0x7412F482, 0x3CD81738, 0x54F6CA51, 0x828BC795, + 0x566DAF91, 0xEB5696DB, 0xAACC3D6E, 0xAA14D97E, 0x3C4BB972, 0x0E121D89, 0xFC5031EA, 0x1299927A, 0x035557FE, 0x9C12D8B0, + 0x47352F1E, 0x1344F64F, 0x54BB93E6, 0x4D58422F, 0xE4C8CA2C, 0x2A0CD8B0, 0x383449D7, 0x94D97D61, 0xCEC43FA8, 0x9D23BC3B, + 0x17D1FD18, 0x7A2D2C34, 0xB376D8D4, 0xBDAE6456, 0xA62E9E8D, 0x891E0E89, 0xB056F7AF, 0xCD7CB83E, 0x524531BD, 0x3B74A510, + 0x8B40002C, 0x1A31D043, 0x124877B8, 0xC2D24143, 0xD577D373, 0x223947AA, 0x5AFF02F0, 0x305BE9F7, 0x56AFC75B, 0xB8F358B3, + 0x1CF0A301, 0x472BB05A, 0xF6F6ED5F, 0x02729272, 0x90A81579, 0xF4F8F16C, 0x2A233515, 0xF073FB22, 0x828A1C5F, 0x3DC85BB6, + 0xAF006F14, 0x9F78BCB3, 0x20375A44, 0x1DA3DE5C, 0x8A47CB7A, 0x4B3AED7A, 0x1B914FE6, 0x6C0826EE, 0x453D2CFE, 0xC8147FD3, + 0xA36209C0, 0x54976ECC, 0x6F1AE267, 0xE3BAF8BE, 0x3FAD1643, 0x74F58A2B, 0xD229B027, 0x63070149, 0x53608FC5, 0xFBD9542A, + 0x03315724, 0x4F3DC56A, 0x361EEF40, 0xFD860064, 0x6A942C64, 0xF77CC94F, 0x52A3F8B2, 0xA201CC09, 0xBF0F4778, 0x51327531, + 0x4F4F79F1, 0x044E7118, 0x99F72515, 0x3418106E, 0x51C4EE43, 0x779E88CE, 0x3FAF065B, 0x457D5482, 0xAFC496AC, 0x0289AF99, + 0xC3C19353, 0x79F74242, 0xF89F5D59, 0x96321B7A, 0x1F20FAB7, 0x21B5E67E, 0x02E3338F, 0x3C09A2A9, 0x64E717B4, 0x34E90333, + 0x13018018, 0x4E763E1C, 0xC6F51A99, 0xE822E779, 0x2BDCB520, 0xEBD4FF36, 0xF7E3F09B, 0x3C2945F9, 0x3B7E6D88, 0x5C974072, + 0x13AFEF9D, 0x67B557BD, 0xB16951C7, 0x8BD2684F, 0x7EBC9A05, 0x8D21C212, 0x6DFFEECF, 0x030DA6B6, 0xF7E19A75, 0xC0057743, + 0x2D235EFE, 0xB6CA5F71, 0x7B57A431, 0x43DC86C9, 0x7FEF171D, 0x393E9378, 0xCE80C227, 0x96ED3538, 0x120D6062, 0xA9D31954, + 0x86611B3B, 0x123670AD, 0x9B2A40D7, 0x50CF4A9F, 0xB9FCEDE4, 0xAEA71031, 0x5548214C, 0x8BEE614C, 0x06310727, 0xFE1113CD, + 0x19B1F144, 0x129F322A, 0x81E12C34, 0x5AD816EC, 0x84074DF2, 0x01902E4D, 0xEA209697, 0xA7C71FF1, 0xBC625F3C, 0xB50E8BA1, + 0x05185608, 0x0145B9E9, 0xC81E7A99, 0xE3B84F67, 0xAED399D5, 0xF38C66EC, 0x75D487A1, 0xEA78BD8C, 0xBE717AEE, 0x5A899BBE, + 0xFECDE525, 0x93754F27, 0xAD2A32C4, 0x058C4311, 0xD657FE29, 0x5006225F, 0xF6B32306, 0x38F4A913, 0x7F7DC390, 0x21A32A8D, + 0x5AFD5DC2, 0x9110F958, 0x19082856, 0x9231E09F, 0xB556B86E, 0x9FA974B0, 0x1BAFF685, 0xFD7C2874, 0x9CEEC30D, 0x8CFBE836, + 0xB64BCCE1, 0x592AA53A, 0x47140600, 0x50361A84, 0x9B7957EE, 0x259A238C, 0x1D814AFC, 0x736F7C8B, 0x53F88396, 0x45214287, + 0x37108BCC, 0xFEDB2BFC, 0xF79E9031, 0xEE776BD5, 0xC2F03D79, 0xC204F563 + }; + + private static readonly uint[] SBox1 = + { + 0xD34E8403, 0xBF03483E, 0xC6C09D77, 0xFA3FDD25, 0xFB248D64, 0xF6EC5848, 0x1E00FECA, 0x5A396266, 0x8A9F02C3, 0x34C17FA9, + 0xA3CBF5F1, 0xB3277677, 0xA516DE39, 0xA2F78346, 0x75D66F07, 0x5DD4EC0B, 0x8E498C1E, 0xDDB7EFF1, 0x8A7A684C, 0x2583A8CA, + 0x96799106, 0x9AB1B5CF, 0x88182015, 0xC8495BF4, 0xDAE57B55, 0xE1524CD8, 0xC68E8256, 0x0EA3AA51, 0x82399FC9, 0x02C20F89, + 0xE78C0156, 0x2FC648C5, 0x7501EBC8, 0x9184587E, 0xAC03BDB2, 0xB0EFA2D3, 0xB570F584, 0x50555B23, 0x72CA1DC9, 0xADD887D4, + 0x5D224173, 0xD0E23804, 0x2F382317, 0x11AE5FF1, 0x6B0F87A3, 0x0BCD7EA5, 0xAB217329, 0x87CF6DD2, 0x4B240D7E, 0xA13A6E7F, + 0x73BC1FA4, 0x2DB14A55, 0x0AADB1AE, 0x3EA165F8, 0x0FD1C4C2, 0xAB5D34EE, 0x963C233D, 0x3181A4D8, 0xE1974DB9, 0x5F6E8F9B, + 0x8FACDEAE, 0xD2AF3AC4, 0x1EF2D068, 0xBE30B53F, 0x1C85EF88, 0x5827088F, 0x2C2DF598, 0xEC93BD25, 0x638E94B8, 0x4273F25D, + 0xA0BA16DC, 0x20FE1F5B, 0xD803AE9A, 0xC8E51A79, 0x16D0B547, 0x8ACEB825, 0x2E753386, 0xB5A0D165, 0x3C0A3936, 0xA5A69665, + 0x5112622E, 0xCB14F3FE, 0x5220FB31, 0xACF6571F, 0xE1C4545D, 0x4AD1F627, 0x049969BE, 0xD86CE318, 0x0BA05692, 0x67A9EF1B, + 0x460D97C8, 0x63699147, 0xCB26D353, 0x4A04FAED, 0x406B5E1E, 0x451C90AA, 0x5BF82BD2, 0x3511819A, 0xA4C22A9B, 0xB63B1F90, + 0x11EC62E6, 0x3CE3B12D, 0xBC0BB19C, 0x2E3A6771, 0x751C66FB, 0xAC1E1C07, 0x5194970F, 0x30105C7D, 0x517D73C2, 0xF3687B1A, + 0x3B378F6D, 0x974E6FCE, 0xD4C9C4D6, 0x81474A4B, 0x0EFB98D7, 0xCB6E8DE7, 0xB1BC3374, 0x8B7CC90F, 0xC889EA3D, 0x5DCA7132, + 0xC86136E1, 0xE04D3E50, 0x82507591, 0x34D151DC, 0xB15A8467, 0x58ADBB11, 0x70A53704, 0x8683D2BF, 0x58C024A6, 0xFA2820B7, + 0x93D99E4B, 0x14C55615, 0x5E476521, 0x42E4FAC6, 0x979AF6B0, 0x1D6C9A2B, 0xF855EAE7, 0x4C5C7BC2, 0x96B69C00, 0x52BC9D74, + 0x7A4CED74, 0xEC4C6055, 0x19CB8441, 0x446FE6AE, 0xD7FAD48D, 0x588FC505, 0xB0EFFB52, 0x43161311, 0xEF23CC58, 0xE5A2BC7F, + 0xF9108822, 0x7984A3AC, 0x83429D92, 0x5123C11D, 0x44E1EC67, 0xF540A00D, 0x4512E4FF, 0x7147C169, 0x81A1CA2E, 0x2D3752A1, + 0x2F52DDD8, 0x3397FAA5, 0x3EB16270, 0xDD8CB3E4, 0x3075320B, 0x05C2776A, 0xF628203C, 0x4243A45C, 0x199B3F61, 0x25EFD41F, + 0x6259C453, 0x9CAADB4A, 0x1CDD27ED, 0x2ACD03FA, 0x36F183E1, 0xFB183183, 0xD2D616DD, 0x09CC2A91, 0x0E454E25, 0x71515F2B, + 0x024049D1, 0x4ECD9BEA, 0x655F6720, 0x08EE1543, 0x5C9671BD, 0x1B580057, 0xA91CD924, 0xE934B344, 0x8A527C52, 0x7A2F1E38, + 0xE19F70BD, 0x1F9BABDC, 0xA07342B1, 0x3AEE70CF, 0x06A493E7, 0xE51ABE3C, 0x35635F68, 0x75DB3F19, 0xD49C2E0F, 0x2B0436E1, + 0xD06BD8F7, 0x282B88CE, 0x3B544D02, 0xC30D588D, 0x11D742F1, 0x19EE7C89, 0x8B2283B4, 0xF86B33F6, 0xB5BF4BE3, 0x398D21CE, + 0x12D48FAE, 0x33AE1426, 0xF14AA6D8, 0xE76F4CB6, 0x9D0F0A45, 0x61F49691, 0x7E5B88D7, 0xF66F2C93, 0xA7BD4A69, 0xE4135254, + 0x586A904E, 0xCE6FF2FF, 0xEC15B527, 0x2F054B1A, 0xFFD9FDCB, 0x3BBD3D45, 0x7803085F, 0xE300E291, 0xBCF358D8, 0x35A425C5, + 0x51C1156C, 0x220D046B, 0x236F6A03, 0x7C1E1ADE, 0x1550E891, 0xAE876E17, 0xF4E76076, 0x785033A4, 0x9068DDDA, 0xAF97FF1C, + 0xCF6456F7, 0xFA3C0759, 0x989E6E4A, 0xFF430625, 0x1ED8108F, 0xBE434C75, 0xAAE89ED8, 0x54C23D46, 0x01448BB5, 0x0D5E491B, + 0xCD14A9D9, 0x62435446, 0x22F26922, 0x26B6868A, 0xDAB278CD, 0x6D761F30 + }; + + private static readonly uint[] SBox2 = + { + 0x8827EC01, 0xCF9DA39D, 0xE440EEFE, 0x57FA1D50, 0xBE8D60C4, 0xE7CA8452, 0x8B4563B5, 0x3D0BC2DB, 0x3CF23903, 0xF56FFA15, + 0xFEA3A963, 0x3E9B4C56, 0xCB630C3F, 0x4BDBD5DE, 0xD842E38C, 0xC27B2F0B, 0x366B4F72, 0xE7CE2382, 0xC598AD11, 0xD0B3907A, + 0x7096A464, 0x30039092, 0x3D0F0EE1, 0xE3DE8054, 0x74256D6A, 0x762E23D3, 0x1F018042, 0x8BB16D2F, 0xF28DFE28, 0xAE1B6BFC, + 0x758BBA20, 0x8B556E71, 0x52EA4BD8, 0x27019580, 0x6CA36CAC, 0x34ED1819, 0x52BEEAEE, 0xA2863969, 0x742CDCFD, 0x12A8575B, + 0x74C4A6C7, 0xEC58EC6A, 0x95015F78, 0x3974D185, 0x10930D31, 0x91403623, 0xA06108B7, 0x6BC0F09D, 0x51EA0BBA, 0x26E42E0C, + 0x72C2D8C2, 0x3FFB7D9D, 0x6DA018E8, 0x911898C1, 0x3B9E5E0A, 0x6F0A6651, 0xDAC883C1, 0x5EDA7E00, 0xC9D7D94D, 0xE594A5E3, + 0x5CD2EBCD, 0x522A38A9, 0x69DE4E27, 0xFB5A3764, 0x4FC3A97D, 0x8DED76BE, 0x64AD536F, 0xEA7D4239, 0x87250D95, 0x5C4EE072, + 0xC5A01A30, 0x32180EA3, 0x2F764CF2, 0x8641BBF6, 0x4AE31434, 0x8C816457, 0xB84D03FF, 0xFE33F1BA, 0x8B03BCEB, 0x623A74DB, + 0x3AD8BF5A, 0x8508B545, 0x2FBE42E5, 0x701A0E20, 0xA16F47A6, 0x88C90CE6, 0xB7FB8324, 0x6040F262, 0x85876170, 0x745E1CAF, + 0x26678A49, 0xB33E84C4, 0xEB2F4ABE, 0xAF2AD27A, 0x6F2DAC31, 0xA288FE23, 0x84772FE8, 0x364B5891, 0x337A337F, 0xF787B5AA, + 0xD46F21C7, 0xCB822929, 0x7D2B9A14, 0x669D3751, 0x1535FB1F, 0x6D25FD16, 0x03D3B457, 0xEE6F47AB, 0x144C86E2, 0x6DFEEA1F, + 0x5BC7C620, 0x15926631, 0xDCD00099, 0x3CAE2AA8, 0xF64BA88B, 0xAA26A82E, 0xFB6589A2, 0xE8D7E24F, 0xC7887C10, 0x1E9F0148, + 0x45D0FBBD, 0x11E79F21, 0x1B9B8D6E, 0x516C6B9C, 0x22EAA069, 0xC224E0A9, 0x9D3271FF, 0x1B645D6E, 0xC2269118, 0x6FE5B05E, + 0x116B9CB5, 0xFE09039C, 0x4B2F3EF5, 0xD4E6E014, 0xC06B3926, 0xA290733D, 0x5933F450, 0x0A430CEB, 0xD6D9AE99, 0xFE0FB248, + 0x0CBDED1F, 0xA7C42B0F, 0xCBF1DD67, 0x3AABC4DD, 0x202C46B0, 0x74FA6114, 0xDDDD0B81, 0x3D73D371, 0xFE3AA063, 0x06632C0D, + 0xD3F2CEC1, 0x75633E7A, 0x03C2680F, 0x6E57E6A0, 0x08E1CC02, 0xB7A1E1E7, 0x7841C231, 0xDFC6E45F, 0x7D6C3B45, 0x0A39A10E, + 0xAA43F0C9, 0x241B4681, 0x2D49C364, 0x14121072, 0xC6491219, 0x5BAECAA6, 0x6D6454D7, 0xA0EDD37B, 0x14F7C53A, 0xA7958956, + 0x5AEA9B5A, 0xA7B729DB, 0xE5C6F870, 0xF1EC12F0, 0x3AD09442, 0x37C3436C, 0x8AC1732B, 0x947172B3, 0xE37DE70F, 0x61918A84, + 0x8450DDF9, 0x7BB003D7, 0x453FAD19, 0x75741112, 0x3EF71741, 0xA1DD8929, 0x4AB2FC3D, 0x43DCB136, 0x9A3F11CE, 0xFFE78AE8, + 0x715D7A6C, 0x874E5B2F, 0x329D635C, 0xF81E3AFB, 0xAD36B9C6, 0xCA98651D, 0x62DA42B2, 0x4244E0B4, 0x9C3F58C7, 0x7CAD2631, + 0xFC145A29, 0x3F78A2CB, 0xA34E0474, 0xF1621CE6, 0xDBF434AA, 0xDCCDDED9, 0x9DE873AB, 0xBB612049, 0xF7A893F6, 0x7F28ED42, + 0xC1E4F486, 0x8C6E6433, 0xE4A56261, 0x81A8A755, 0x6E81EFA4, 0xFC48276D, 0x05E10E00, 0xE8E32846, 0x45A21ED4, 0xB7993920, + 0xC784A677, 0x28DD2691, 0x502D9009, 0xB46D43A4, 0x4B7568F9, 0xFD18FD42, 0x706C76CF, 0x38B971F5, 0xD67CD5EA, 0xBB67318C, + 0x6AC2CE3A, 0xCA6BD108, 0x40687C40, 0x4E6A0D94, 0x95F611BE, 0x44C69FC4, 0x20084E67, 0x7F035D80, 0x12FB31E5, 0x743109A8, + 0x423D111C, 0x3F2C68A2, 0xF899CCA4, 0xCCFD0B82, 0x4C102D3A, 0x7DBFAB46, 0xE43697CA, 0x8E9CF7C0, 0xC1E614E7, 0x88D6B104, + 0x7B9A9DC3, 0xB99DA600, 0x5D3F1D52, 0x8FADF78D, 0xFEDE4FEE, 0x5025AC81 + }; + + private static readonly uint[] SBox3 = + { + 0xAAE6F852, 0x753D5BA2, 0x34495010, 0xD0E618CF, 0xC9E43DCA, 0xBB63E9C0, 0x52CF10C8, 0xA410D859, 0xEF12A444, 0x737D3E2B, + 0x2C3C27C5, 0x234BC11C, 0x4AC9DEFD, 0x465B6E59, 0xF1B5156B, 0x14FEAE51, 0xD76B93AB, 0x57CAEB33, 0x2F44A9FF, 0x3F45F135, + 0xBCB372CA, 0x83E084E4, 0x7BFF6B7A, 0x39432B26, 0x40F65BFB, 0x24042E97, 0x1151BC51, 0xF0C12A3D, 0xF2335B74, 0x74EA34A4, + 0x49DCCE86, 0x9963260E, 0xE1667004, 0x0103BDFE, 0xFA597032, 0xFD4DE20E, 0x00485105, 0xA5D23BAE, 0xC37CFCA0, 0x440081E4, + 0xAB264B22, 0x0E6459A8, 0x4190A3C1, 0x442C8B86, 0x8902B297, 0x9BE6C831, 0x28F908D9, 0x4B346736, 0xC82D95CD, 0x0D87059B, + 0x29226AB3, 0x86D876B4, 0xE86A1280, 0x19CF1382, 0x6504C32F, 0xDDA19AAF, 0x2417F345, 0xF0EFED61, 0x4129EDD1, 0xEE154CD7, + 0xCE8C6231, 0x44E69BB8, 0x2B4189D4, 0x5156E779, 0x4FC32785, 0x4334E1C4, 0xD66BB347, 0x7104463E, 0x90FB6A38, 0x884977D8, + 0x620B647A, 0x1B83D9E1, 0x48F4B7AB, 0x134B9CC7, 0xDF67C5CE, 0x155FC624, 0xF674983D, 0x6F542DC8, 0x3A80CC22, 0xF8B53B0C, + 0x35883F85, 0xA9A4F8C3, 0x47BF7BDD, 0x726F7E95, 0x0A6F0147, 0xADFA327C, 0xAA42D26A, 0x5C24C2F8, 0xDF22EF5E, 0x2F245CAC, + 0x6F3AC577, 0x3C995DD0, 0x08931D80, 0x3179A274, 0x182641BE, 0x4B410C02, 0x2C7E6849, 0x05C8A035, 0x931C9CFB, 0xB93DF6C1, + 0xF61DF996, 0xE41D2366, 0x87B7906E, 0xBB0BEDB5, 0xA5D7F85C, 0xCF4EA254, 0x2F6245F4, 0x41EAB256, 0x20451B82, 0x8CB97B29, + 0xBA51158D, 0xE8E35361, 0xEAF22516, 0x327D9523, 0x1017F8BA, 0xF930F281, 0x8C44C91F, 0x3B738D2F, 0xA64AF845, 0x197EA779, + 0x511D5001, 0x9EA29B9F, 0x41862F0F, 0x1B3FA8C0, 0x433AE22F, 0xA0B55038, 0x7E6FE78F, 0xD6E55D13, 0x214207CE, 0x45744A04, + 0xB39EADEA, 0x7CE97F1F, 0x0989A02A, 0xD644F365, 0x6EFDB995, 0xB205CDD9, 0xB21B44A9, 0x57C5BB1F, 0x2C80920D, 0xB680273E, + 0x460B81CC, 0x012CA81A, 0x08BDF12A, 0x05433744, 0x2FC0DDE9, 0x09F72E23, 0xBEA49FC7, 0x5421A114, 0xC44DDA7B, 0xE49DBAB6, + 0x487B7377, 0xD282E10F, 0x6D0C3196, 0x61AE90BB, 0xBF348266, 0x30C75585, 0x2EAD11A5, 0xA53422FD, 0x989717D2, 0x2032CBD1, + 0x0C491518, 0xB02F4E56, 0x4DF3A162, 0xD40DA7E8, 0x8519BD5C, 0xEBC1FC82, 0x2FCAD29E, 0x4456139F, 0x186269F3, 0x4DCB58A5, + 0x6C8503F7, 0x8A04C438, 0x6A6B0044, 0xE05AA61A, 0xA29334C4, 0x8987A82E, 0xF0BA7EB7, 0xBD18C285, 0x06B0B028, 0xA0A66690, + 0x0F4BCA36, 0xD570CDCE, 0x1ECFFC31, 0xD601B847, 0x880F1BD8, 0x22D41437, 0x029BBDA9, 0xF2EDD463, 0x5A916D8A, 0xD704954F, + 0x30570329, 0x0BC2564E, 0xB44D946E, 0x26F727AC, 0x45657F92, 0x1AD11FB7, 0xB14F2F06, 0x891AF3ED, 0x994418B5, 0x9DC6E341, + 0x62BB4700, 0xDAE2A3E4, 0x07D27364, 0x2FD1F62F, 0x8957EA89, 0x2F6980C9, 0xB8BBF8F9, 0x5D02788A, 0xE5954184, 0x4308FE8D, + 0xD777F756, 0xE8D1FB93, 0x5504EF0A, 0x474B51C4, 0x5DA6017C, 0x5B156C13, 0xDE760633, 0xC17D04FE, 0xF25BEF47, 0x5F63CD38, + 0x4D43CCEB, 0xFE65C9C7, 0xF38F5ED6, 0x7F2E55D9, 0x75D19CC6, 0x03B6CE3F, 0x829A7880, 0xF8F658B5, 0x86C2468A, 0xD5C52A72, + 0xA73025EA, 0x091DDE9E, 0xA2C09F5D, 0xEBEBDBF0, 0xD60C9AEA, 0xEDB1C3D3, 0x202D9E65, 0x9DEF99BF, 0x306CFC61, 0x325BCAE1, + 0x570ABC2B, 0x9976F185, 0x4518E177, 0xAF5D0B2A, 0x17F9FDA0, 0x264AD959, 0x5A81DD68, 0xC921D161, 0xE1CE2049, 0xA3685311, + 0xFBFBBA97, 0x1A21E8AC, 0x5BCE2943, 0x7D758A7D, 0x5D598AA2, 0x8971150B + }; + + private static readonly uint[] PBox = + { + 0xAE915BC6, 0x15426B3F, 0x79ED8A9A, 0x0E1C4091, 0xFBB7286A, 0x1854506C, 0xF620245D, 0x9733B6DE, 0x6FB18C28, + 0x4C8B7C70, 0x85E2D4F6, 0xE4936A12, 0xAE6CDF53, 0x95CB3D66, 0xB43A52D3, 0xE9BDD2DE, 0xD138BDA0, 0x7B584F44 + }; + + /// + /// Encrypts the specified byte array with no offset and full length. + /// + /// The byte array to encrypt. + public static void Encrypt(byte[] data) + { + Encrypt(data, 0, data.Length); + } - for (var k = 0; k < blocks; k++) - { - var p = offset + (k << 3); + /// + /// Encrypts the specified byte array at a given offset for a given length. + /// + /// The byte array to encrypt. + /// The offset at which to begin. + /// The length for which to encrypt. + public static void Encrypt(byte[] data, int offset, int length) + { + var blocks = length >> 3; - var xl = (uint) (data[p ] | (data[p + 1] << 8) | (data[p + 2] << 16) | (data[p + 3] << 24)); - var xr = (uint) (data[p + 4] | (data[p + 5] << 8) | (data[p + 6] << 16) | (data[p + 7] << 24)); + for (var k = 0; k < blocks; k++) + { + var p = offset + (k << 3); - uint tmp; + var xl = (uint) (data[p ] | (data[p + 1] << 8) | (data[p + 2] << 16) | (data[p + 3] << 24)); + var xr = (uint) (data[p + 4] | (data[p + 5] << 8) | (data[p + 6] << 16) | (data[p + 7] << 24)); - for (var i = 0; i < 16; i++) - { - tmp = xl ^ PBox[i]; - xl = F(tmp) ^ xr; - xr = tmp; - } + uint tmp; - tmp = xl; - xl = xr; + for (var i = 0; i < 16; i++) + { + tmp = xl ^ PBox[i]; + xl = F(tmp) ^ xr; xr = tmp; - xr ^= PBox[16]; - xl ^= PBox[17]; - - data[p ] = (byte)( xl & 0xFF); - data[p + 1] = (byte)((xl >> 8) & 0xFF); - data[p + 2] = (byte)((xl >> 16) & 0xFF); - data[p + 3] = (byte)((xl >> 24) & 0xFF); - data[p + 4] = (byte)( xr & 0xFF); - data[p + 5] = (byte)((xr >> 8) & 0xFF); - data[p + 6] = (byte)((xr >> 16) & 0xFF); - data[p + 7] = (byte)((xr >> 24) & 0xFF); } - } - /// - /// Decrypts the specified byte array with no offset and full length. - /// - /// The byte array to encrypt. - public static void Decrypt(byte[] data) - { - Decrypt(data, 0, data.Length); + tmp = xl; + xl = xr; + xr = tmp; + xr ^= PBox[16]; + xl ^= PBox[17]; + + data[p ] = (byte)( xl & 0xFF); + data[p + 1] = (byte)((xl >> 8) & 0xFF); + data[p + 2] = (byte)((xl >> 16) & 0xFF); + data[p + 3] = (byte)((xl >> 24) & 0xFF); + data[p + 4] = (byte)( xr & 0xFF); + data[p + 5] = (byte)((xr >> 8) & 0xFF); + data[p + 6] = (byte)((xr >> 16) & 0xFF); + data[p + 7] = (byte)((xr >> 24) & 0xFF); } + } - /// - /// Decrypts the specified byte array at a given offset for a given length. - /// - /// The byte array to decrypt. - /// The offset at which to begin. - /// The length for which to decrypt. - public static void Decrypt(byte[] data, int offset, int length) - { - var blocks = length >> 3; + /// + /// Decrypts the specified byte array with no offset and full length. + /// + /// The byte array to encrypt. + public static void Decrypt(byte[] data) + { + Decrypt(data, 0, data.Length); + } - for (var k = 0; k < blocks; k++) - { - var p = offset + (k << 3); + /// + /// Decrypts the specified byte array at a given offset for a given length. + /// + /// The byte array to decrypt. + /// The offset at which to begin. + /// The length for which to decrypt. + public static void Decrypt(byte[] data, int offset, int length) + { + var blocks = length >> 3; - var lb = (uint) (data[p ] | (data[p + 1] << 8) | (data[p + 2] << 16) | (data[p + 3] << 24)); - var rb = (uint) (data[p + 4] | (data[p + 5] << 8) | (data[p + 6] << 16) | (data[p + 7] << 24)); - uint tmp; + for (var k = 0; k < blocks; k++) + { + var p = offset + (k << 3); - for (var i = 17; i > 1; i--) - { - tmp = lb ^ PBox[i]; - lb = F(tmp) ^ rb; - rb = tmp; - } + var lb = (uint) (data[p ] | (data[p + 1] << 8) | (data[p + 2] << 16) | (data[p + 3] << 24)); + var rb = (uint) (data[p + 4] | (data[p + 5] << 8) | (data[p + 6] << 16) | (data[p + 7] << 24)); + uint tmp; - tmp = lb; - lb = rb; + for (var i = 17; i > 1; i--) + { + tmp = lb ^ PBox[i]; + lb = F(tmp) ^ rb; rb = tmp; - rb ^= PBox[1]; - lb ^= PBox[0]; - - data[p ] = (byte) ( lb & 0xFF); - data[p + 1] = (byte) ((lb >> 8) & 0xFF); - data[p + 2] = (byte) ((lb >> 16) & 0xFF); - data[p + 3] = (byte) ((lb >> 24) & 0xFF); - data[p + 4] = (byte) ( rb & 0xFF); - data[p + 5] = (byte) ((rb >> 8) & 0xFF); - data[p + 6] = (byte) ((rb >> 16) & 0xFF); - data[p + 7] = (byte) ((rb >> 24) & 0xFF); } + + tmp = lb; + lb = rb; + rb = tmp; + rb ^= PBox[1]; + lb ^= PBox[0]; + + data[p ] = (byte) ( lb & 0xFF); + data[p + 1] = (byte) ((lb >> 8) & 0xFF); + data[p + 2] = (byte) ((lb >> 16) & 0xFF); + data[p + 3] = (byte) ((lb >> 24) & 0xFF); + data[p + 4] = (byte) ( rb & 0xFF); + data[p + 5] = (byte) ((rb >> 8) & 0xFF); + data[p + 6] = (byte) ((rb >> 16) & 0xFF); + data[p + 7] = (byte) ((rb >> 24) & 0xFF); } + } - /// - /// The round (Feistel) function of the Cipher. - /// - /// - /// - private static uint F(uint x) - { - var y = SBox0[(x >> 24) & 0xff]; - y += SBox1[(x >> 16) & 0xff]; - y ^= SBox2[(x >> 8) & 0xff]; - y += SBox3[x & 0xff]; + /// + /// The round (Feistel) function of the Cipher. + /// + /// + /// + private static uint F(uint x) + { + var y = SBox0[(x >> 24) & 0xff]; + y += SBox1[(x >> 16) & 0xff]; + y ^= SBox2[(x >> 8) & 0xff]; + y += SBox3[x & 0xff]; - return y; - } + return y; } } diff --git a/src/Rasa.Utils/Cryptography/AuthCryptManager.cs b/src/Rasa.Utils/Cryptography/AuthCryptManager.cs index 443444a8..f9bfd790 100644 --- a/src/Rasa.Utils/Cryptography/AuthCryptManager.cs +++ b/src/Rasa.Utils/Cryptography/AuthCryptManager.cs @@ -1,64 +1,61 @@ -using System; +namespace Rasa.Cryptography; -namespace Rasa.Cryptography -{ - using Auth; +using Rasa.Cryptography.Auth; - public static class AuthCryptManager +public static class AuthCryptManager +{ + public static bool Decrypt(byte[] data, int offset, int length, ClientCryptData cryptData = null) { - public static bool Decrypt(byte[] data, int offset, int length, ClientCryptData cryptData = null) - { - if (length % 8 != 0) - throw new ArgumentOutOfRangeException(nameof(length), "The lenght must be a multiple of 8!"); + if (length % 8 != 0) + throw new ArgumentOutOfRangeException(nameof(length), "The lenght must be a multiple of 8!"); - Blowfish.Decrypt(data, offset, length); + Blowfish.Decrypt(data, offset, length); - return VerifyChecksum(data, offset, length); - } + return VerifyChecksum(data, offset, length); + } - public static void Encrypt(byte[] data, int offset, ref int length, int maxLength, ClientCryptData cryptData = null) - { - var oldLen = length; + public static void Encrypt(byte[] data, int offset, ref int length, int maxLength, ClientCryptData cryptData = null) + { + var oldLen = length; - // Make the length a multiple of 8 - var rem = length % 8; - if (rem != 0) - length += 8 - rem; + // Make the length a multiple of 8 + var rem = length % 8; + if (rem != 0) + length += 8 - rem; - if (length + 8 > maxLength) - throw new ArgumentOutOfRangeException(nameof(length), "The length can't exceed the maximal buffer length!"); + if (length + 8 > maxLength) + throw new ArgumentOutOfRangeException(nameof(length), "The length can't exceed the maximal buffer length!"); - // Fill up extra padding bytes - for (var i = oldLen; i < length; ++i) - data[offset + i] = 0xCC; + // Fill up extra padding bytes + for (var i = oldLen; i < length; ++i) + data[offset + i] = 0xCC; - // Add checksum bytes to the length - length += 8; + // Add checksum bytes to the length + length += 8; - AppendChecksum(data, offset, length); + AppendChecksum(data, offset, length); - Blowfish.Encrypt(data, offset, length); - } + Blowfish.Encrypt(data, offset, length); + } - private static bool VerifyChecksum(byte[] data, int offset, int length) - { - long chksum = 0; + private static bool VerifyChecksum(byte[] data, int offset, int length) + { + long chksum = 0; - for (var i = offset; i < (length - 4); i += 4) - chksum ^= BitConverter.ToUInt32(data, i); + for (var i = offset; i < (length - 4); i += 4) + chksum ^= BitConverter.ToUInt32(data, i); - return 0 == chksum; - } + return 0 == chksum; + } - private static void AppendChecksum(byte[] data, int offset, int length) - { - var chksum = 0U; - var dataEnd = length - 8; + private static void AppendChecksum(byte[] data, int offset, int length) + { + var chksum = 0U; + var dataEnd = length - 8; - for (var i = 0; i < dataEnd; i += 4) - chksum ^= BitConverter.ToUInt32(data, offset + i); + for (var i = 0; i < dataEnd; i += 4) + chksum ^= BitConverter.ToUInt32(data, offset + i); - Array.Copy(BitConverter.GetBytes(chksum), 0, data, offset + dataEnd, 4); - } + Array.Copy(BitConverter.GetBytes(chksum), 0, data, offset + dataEnd, 4); } } diff --git a/src/Rasa.Utils/Cryptography/BigNum.cs b/src/Rasa.Utils/Cryptography/BigNum.cs index 77e0d958..4558c795 100644 --- a/src/Rasa.Utils/Cryptography/BigNum.cs +++ b/src/Rasa.Utils/Cryptography/BigNum.cs @@ -1,365 +1,362 @@ -using System; +namespace Rasa.Cryptography; -namespace Rasa.Cryptography +public class BigNum { - public class BigNum + private const int BignumSize = 256; //Wert: 0 - 2^65536 + + public byte[] Content { get; } = new byte[BignumSize]; + + public bool Reset() { - private const int BignumSize = 256; //Wert: 0 - 2^65536 + Array.Clear(Content, 0, Content.Length); + return true; + } - public byte[] Content { get; } = new byte[BignumSize]; + public bool SetUInt32(uint val) + { + Reset(); + Array.Copy(BitConverter.GetBytes(val), Content, 4); + return true; + } - public bool Reset() - { - Array.Clear(Content, 0, Content.Length); - return true; - } + public bool Copy(BigNum src) + { + Array.Copy(src.Content, Content, src.Content.Length); + return true; + } - public bool SetUInt32(uint val) - { - Reset(); - Array.Copy(BitConverter.GetBytes(val), Content, 4); - return true; - } + //Addiert zwei Bignums (A = B + C), gibt den Überlauf zurück + public uint Add(BigNum b, BigNum c) + { + var overflow = 0U; - public bool Copy(BigNum src) + for (var i = 0; i < BignumSize; ++i) { - Array.Copy(src.Content, Content, src.Content.Length); - return true; + //Addiere zu overflow die beiden BigNum Ziffern + overflow += (uint)b.Content[i] + c.Content[i]; + + //Speichere aktuellen Ziffernwert + Content[i] = (byte)(overflow & 0xFF); + + overflow = overflow >> 8; } - //Addiert zwei Bignums (A = B + C), gibt den Überlauf zurück - public uint Add(BigNum b, BigNum c) - { - var overflow = 0U; + return overflow; + } - for (var i = 0; i < BignumSize; ++i) - { - //Addiere zu overflow die beiden BigNum Ziffern - overflow += (uint)b.Content[i] + c.Content[i]; + //Subtrahiert zwei Bignums (Result = B - C), gibt den Überlauf zurück + public uint Sub(BigNum b, BigNum c) + { + var overflow = 1U; - //Speichere aktuellen Ziffernwert - Content[i] = (byte)(overflow & 0xFF); + for (var i = 0; i < BignumSize; i++) + { + //Addiere zu overflow die beiden BigNum Ziffern b + ~d + overflow += b.Content[i] + (uint)((~c.Content[i]) & 0xFF); - overflow = overflow >> 8; - } + //Speichere aktuellen Ziffernwert + Content[i] = (byte)(overflow & 0xFF); - return overflow; + //Rücke overflow Wert + overflow = overflow >> 8; } - //Subtrahiert zwei Bignums (Result = B - C), gibt den Überlauf zurück - public uint Sub(BigNum b, BigNum c) - { - var overflow = 1U; + return overflow; + } - for (var i = 0; i < BignumSize; i++) - { - //Addiere zu overflow die beiden BigNum Ziffern b + ~d - overflow += b.Content[i] + (uint)((~c.Content[i]) & 0xFF); + //Multipliziert zwei Bignums (result = a * b) + public bool Mul(BigNum a, BigNum b) + { + //Zwischenspeicher für Ziffern-Multiplikationsergebniss + var storer = new BigNum(); + var resultnew = new BigNum(); - //Speichere aktuellen Ziffernwert - Content[i] = (byte)(overflow & 0xFF); + var o1 = new BigNum(); + var o2 = new BigNum(); - //Rücke overflow Wert - overflow = overflow >> 8; - } + o1.Copy(a); + o2.Copy(b); - return overflow; - } + //Ziffernwertspeicher + resultnew.Reset(); - //Multipliziert zwei Bignums (result = a * b) - public bool Mul(BigNum a, BigNum b) + for (var i = 0; i < BignumSize; ++i) { - //Zwischenspeicher für Ziffern-Multiplikationsergebniss - var storer = new BigNum(); - var resultnew = new BigNum(); + //Setze storer und overflow auf 0 + storer.Reset(); - var o1 = new BigNum(); - var o2 = new BigNum(); + var overflow = 0U; - o1.Copy(a); - o2.Copy(b); + //Berechne Ziffernmultiplikation + for (var i2 = 0; i2 < (BignumSize - i); ++i2) + { + //Multipliziere Ziffern + overflow += o1.Content[i] * (uint)o2.Content[i2]; - //Ziffernwertspeicher - resultnew.Reset(); + //Speichere Ziffer + storer.Content[i + i2] = (byte)(overflow & 0xFF); - for (var i = 0; i < BignumSize; ++i) - { - //Setze storer und overflow auf 0 - storer.Reset(); + //Schiebe Ziffern + overflow = overflow >> 8; + } + //Addiere Ziffernprodukt zu result + resultnew.Add(resultnew, storer); + } - var overflow = 0U; + //Kopiere Ergebniss + Copy(resultnew); - //Berechne Ziffernmultiplikation - for (var i2 = 0; i2 < (BignumSize - i); ++i2) - { - //Multipliziere Ziffern - overflow += o1.Content[i] * (uint)o2.Content[i2]; + //Return erfolg + return true; + } - //Speichere Ziffer - storer.Content[i + i2] = (byte)(overflow & 0xFF); + //Dividiert einen BigNum (result = a / c) + public bool Div(BigNum a, BigNum b) + { + var o1 = new BigNum(); + var o2 = new BigNum(); - //Schiebe Ziffern - overflow = overflow >> 8; - } - //Addiere Ziffernprodukt zu result - resultnew.Add(resultnew, storer); - } + Reset(); - //Kopiere Ergebniss - Copy(resultnew); + o1.Copy(a); + o2.Copy(b); - //Return erfolg - return true; - } + //Fange falsche Werte ab + if (o1.IsZero() || o2.IsZero()) + return false; - //Dividiert einen BigNum (result = a / c) - public bool Div(BigNum a, BigNum b) + //Suche maximum + var shiftCount = 0; + while (o1.Compare(o2) >= 0 && (o2.Content[BignumSize - 1] & 0x80) == 0) { - var o1 = new BigNum(); - var o2 = new BigNum(); - - Reset(); + ++shiftCount; + o2.Double(); + } - o1.Copy(a); - o2.Copy(b); + //Mache den letzten Verdoppler Rückgängig + o2.Half(); - //Fange falsche Werte ab - if (o1.IsZero() || o2.IsZero()) - return false; + //Solange b ist nicht Null + while (shiftCount > 0) + { + //Rücke result + Double(); - //Suche maximum - var shiftCount = 0; - while (o1.Compare(o2) >= 0 && (o2.Content[BignumSize - 1] & 0x80) == 0) + //Passt b in a? + if (o1.Compare(o2) >= 0) // (a-b)>=0 { - ++shiftCount; - o2.Double(); + //Subtrahiere von a + o1.Sub(o1, o2); + + //Setze Result + Content[0] |= 1; } - //Mache den letzten Verdoppler Rückgängig + //Halbiere b o2.Half(); - //Solange b ist nicht Null - while (shiftCount > 0) - { - //Rücke result - Double(); + //Zähle shiftanzahl + --shiftCount; + } - //Passt b in a? - if (o1.Compare(o2) >= 0) // (a-b)>=0 - { - //Subtrahiere von a - o1.Sub(o1, o2); + //Return erfolg + return true; + } - //Setze Result - Content[0] |= 1; - } + //Berechnet den Modulo einer Bignumdivision (result = A%B) + public bool Mod(BigNum a, BigNum b) + { + var factor = new BigNum(); - //Halbiere b - o2.Half(); + //Runde Factor auf a/b*b + factor.Div(a, b); + factor.Mul(factor, b); - //Zähle shiftanzahl - --shiftCount; - } + //Berechne Rest + Sub(a, factor); - //Return erfolg - return true; - } + //Return Erfolg + return true; + } - //Berechnet den Modulo einer Bignumdivision (result = A%B) - public bool Mod(BigNum a, BigNum b) - { - var factor = new BigNum(); + //Modulare Exponentiation (result = (B^E)%N) + public bool ModExp(BigNum b, BigNum e, BigNum n) + { + var p = new BigNum(); + var exponent = new BigNum(); - //Runde Factor auf a/b*b - factor.Div(a, b); - factor.Mul(factor, b); + var bitCount = e.CountBits(); - //Berechne Rest - Sub(a, factor); + //Setze p auf 1 + p.Reset(); + p.SetUInt32(0x01); - //Return Erfolg - return true; - } + //Kopiere Exponent + exponent.Copy(e); - //Modulare Exponentiation (result = (B^E)%N) - public bool ModExp(BigNum b, BigNum e, BigNum n) + //Beginne schleife + while (bitCount >= 0) { - var p = new BigNum(); - var exponent = new BigNum(); - - var bitCount = e.CountBits(); + p.Mul(p, p); + p.Mod(p, n); - //Setze p auf 1 - p.Reset(); - p.SetUInt32(0x01); - - //Kopiere Exponent - exponent.Copy(e); - - //Beginne schleife - while (bitCount >= 0) + //Falls ungerade multiplizierte mit Basis + if ((exponent.Content[bitCount / 8] & (1 << (bitCount % 8))) != 0) { - p.Mul(p, p); + p.Mul(p, b); p.Mod(p, n); - - //Falls ungerade multiplizierte mit Basis - if ((exponent.Content[bitCount / 8] & (1 << (bitCount % 8))) != 0) - { - p.Mul(p, b); - p.Mod(p, n); - } - - //Halbiere exponent - //Bignum_Half(&exponent); - --bitCount; } - //Kopiere Ergebniss - Copy(p); - - //Return erfolg - return true; + //Halbiere exponent + //Bignum_Half(&exponent); + --bitCount; } - //Halbiert einen BigNum (a = a / 2) - public bool Half() - { - //Shiftbit ist 0 - byte shiftbit = 0; - for (var i = BignumSize - 1; i >= 0; --i) - { - //Errechne neuen Ziffernwert - var newvalue = (byte)((Content[i] >> 1) | (shiftbit << 7)); + //Kopiere Ergebniss + Copy(p); - //Merke shiftbit - shiftbit = (byte)(Content[i] & 0x01); + //Return erfolg + return true; + } - //Setze neuen Ziffernwert - Content[i] = newvalue; - } + //Halbiert einen BigNum (a = a / 2) + public bool Half() + { + //Shiftbit ist 0 + byte shiftbit = 0; + for (var i = BignumSize - 1; i >= 0; --i) + { + //Errechne neuen Ziffernwert + var newvalue = (byte)((Content[i] >> 1) | (shiftbit << 7)); - //Return erfolg - return true; + //Merke shiftbit + shiftbit = (byte)(Content[i] & 0x01); + + //Setze neuen Ziffernwert + Content[i] = newvalue; } - //Verdoppelt einen BigNum (a = a * 2) - public bool Double() - { - //Shiftbit ist 0 - byte shiftbit = 0; + //Return erfolg + return true; + } - for (var i = 0; i < BignumSize; ++i) - { - //Errechne neuen Ziffernwert - var newvalue = (byte)((Content[i] << 1) | (shiftbit >> 7)); + //Verdoppelt einen BigNum (a = a * 2) + public bool Double() + { + //Shiftbit ist 0 + byte shiftbit = 0; - //Merke shiftbit - shiftbit = (byte)(Content[i] & 0x80); + for (var i = 0; i < BignumSize; ++i) + { + //Errechne neuen Ziffernwert + var newvalue = (byte)((Content[i] << 1) | (shiftbit >> 7)); - //Setze neuen Ziffernwert - Content[i] = newvalue; - } + //Merke shiftbit + shiftbit = (byte)(Content[i] & 0x80); - //Return erfolg - return true; + //Setze neuen Ziffernwert + Content[i] = newvalue; } - //Bignumvergleiche + //Return erfolg + return true; + } - //Vergleicht zwei Bignums (-1,0,1) - public int Compare(BigNum b) - { - for (var i = (BignumSize - 1); i >= 0; --i) - { - var vergleich = Content[i] - b.Content[i]; + //Bignumvergleiche - //Falls unterschiedlich, gib Unterschied zurück - if (vergleich != 0) - return vergleich; - } + //Vergleicht zwei Bignums (-1,0,1) + public int Compare(BigNum b) + { + for (var i = (BignumSize - 1); i >= 0; --i) + { + var vergleich = Content[i] - b.Content[i]; - //Return gleich - return 0; + //Falls unterschiedlich, gib Unterschied zurück + if (vergleich != 0) + return vergleich; } - //Vergleicht einen BigNum mit 0 - public bool IsZero() - { - //Für alle Ziffern - for (var i = 0; i < BignumSize; ++i) - if (Content[i] != 0) - return false; //Return false falls Ziffer ungleich 0 + //Return gleich + return 0; + } - return true; - } + //Vergleicht einen BigNum mit 0 + public bool IsZero() + { + //Für alle Ziffern + for (var i = 0; i < BignumSize; ++i) + if (Content[i] != 0) + return false; //Return false falls Ziffer ungleich 0 - //Gibt die Stelle des ersten Bits zurück(Bsp: 0x100 wäre 8) - public int CountBits() - { - for (var i = (BignumSize - 1) * 8; i >= 0; --i) - if ((Content[i / 8] & (1 << (i % 8))) != 0) - return i; + return true; + } - return 0; - } + //Gibt die Stelle des ersten Bits zurück(Bsp: 0x100 wäre 8) + public int CountBits() + { + for (var i = (BignumSize - 1) * 8; i >= 0; --i) + if ((Content[i / 8] & (1 << (i % 8))) != 0) + return i; - //Liest einen BigNum aus dem Speicher - public bool Read(byte[] p, int offset, int digitCount) - { - Reset(); + return 0; + } - for (var i = 0; i < digitCount; ++i) - Content[i] = p[offset + i]; + //Liest einen BigNum aus dem Speicher + public bool Read(byte[] p, int offset, int digitCount) + { + Reset(); - //Return Erfolg - return true; - } + for (var i = 0; i < digitCount; ++i) + Content[i] = p[offset + i]; - //Liest einen BigNum aus dem Speicher im Big Endian Format. - public bool ReadBigEndian(byte[] p, int offset, int digitCount) - { - Reset(); + //Return Erfolg + return true; + } - for (var i = 0; i < digitCount; ++i) - Content[digitCount - i - 1] = p[offset + i]; + //Liest einen BigNum aus dem Speicher im Big Endian Format. + public bool ReadBigEndian(byte[] p, int offset, int digitCount) + { + Reset(); - //Return Erfolg - return true; - } + for (var i = 0; i < digitCount; ++i) + Content[digitCount - i - 1] = p[offset + i]; - //Schreibt einen BigNum in den Speicher - public bool WriteTo(byte[] p, int off, int digitCount) - { - Array.Clear(p, off, digitCount); + //Return Erfolg + return true; + } - for (var i = 0; i < digitCount; ++i) - p[off + i] = Content[i]; + //Schreibt einen BigNum in den Speicher + public bool WriteTo(byte[] p, int off, int digitCount) + { + Array.Clear(p, off, digitCount); - //Return Erfolg - return true; - } + for (var i = 0; i < digitCount; ++i) + p[off + i] = Content[i]; - //Schreibt einen BigNum in den Speicher im Big Endian Format - //Achtung: Funktioniert nicht ganz fehlerfrei wenn DigitCount > Eigentliche Anzahl der Stellen - public bool WriteToBigEndian(byte[] p, int off, int digitCount) - { - Array.Clear(p, off, digitCount); + //Return Erfolg + return true; + } - for (var i = 0; i < digitCount; ++i) - p[off + i] = Content[digitCount - i - 1]; + //Schreibt einen BigNum in den Speicher im Big Endian Format + //Achtung: Funktioniert nicht ganz fehlerfrei wenn DigitCount > Eigentliche Anzahl der Stellen + public bool WriteToBigEndian(byte[] p, int off, int digitCount) + { + Array.Clear(p, off, digitCount); - //Return Erfolg - return true; - } + for (var i = 0; i < digitCount; ++i) + p[off + i] = Content[digitCount - i - 1]; - //Gibt die Länge eines BigNum in Byte-Stellen zurück - public int Length() - { - for (var i = (BignumSize - 1); i >= 0; --i) - if (Content[i] != 0) - return i + 1; + //Return Erfolg + return true; + } - return 0; - } + //Gibt die Länge eines BigNum in Byte-Stellen zurück + public int Length() + { + for (var i = (BignumSize - 1); i >= 0; --i) + if (Content[i] != 0) + return i + 1; + + return 0; } } diff --git a/src/Rasa.Utils/Cryptography/BlowfishData.cs b/src/Rasa.Utils/Cryptography/BlowfishData.cs index 2cd0dcb3..b73f69d3 100644 --- a/src/Rasa.Utils/Cryptography/BlowfishData.cs +++ b/src/Rasa.Utils/Cryptography/BlowfishData.cs @@ -1,8 +1,7 @@ -namespace Rasa.Cryptography +namespace Rasa.Cryptography; + +public class BlowfishData { - public class BlowfishData - { - public uint[] P { get; set; } = new uint[6]; - public uint[] S { get; set; } = new uint[1024]; - } + public uint[] P { get; set; } = new uint[6]; + public uint[] S { get; set; } = new uint[1024]; } diff --git a/src/Rasa.Utils/Cryptography/ClientCryptData.cs b/src/Rasa.Utils/Cryptography/ClientCryptData.cs index 0dff4a74..c8627800 100644 --- a/src/Rasa.Utils/Cryptography/ClientCryptData.cs +++ b/src/Rasa.Utils/Cryptography/ClientCryptData.cs @@ -1,9 +1,8 @@ -namespace Rasa.Cryptography +namespace Rasa.Cryptography; + +public class ClientCryptData { - public class ClientCryptData - { - public BlowfishData Key { get; } = new BlowfishData(); - public byte[] MD5 { get; } = new byte[16]; - public byte[] K { get; } = new byte[64]; - } + public BlowfishData Key { get; } = new BlowfishData(); + public byte[] MD5 { get; } = new byte[16]; + public byte[] K { get; } = new byte[64]; } diff --git a/src/Rasa.Utils/Cryptography/DHKeyExchange.cs b/src/Rasa.Utils/Cryptography/DHKeyExchange.cs index 60f0d00d..71ee5dad 100644 --- a/src/Rasa.Utils/Cryptography/DHKeyExchange.cs +++ b/src/Rasa.Utils/Cryptography/DHKeyExchange.cs @@ -1,41 +1,40 @@ -namespace Rasa.Cryptography +namespace Rasa.Cryptography; + +public static class DHKeyExchange { - public static class DHKeyExchange + public static readonly byte[] ConstantPrime = + { + 0x98, 0x0F, 0x91, 0xEA, 0xAD, 0xAD, 0x8E, 0x7D, 0xF9, 0xEC, 0x43, 0x1D, 0xD4, 0x1C, 0xEF, 0x3F, + 0xBE, 0xCF, 0xD1, 0xAE, 0xD2, 0x77, 0x1C, 0xCF, 0xF8, 0x5E, 0xF8, 0x85, 0x3E, 0x2F, 0x9B, 0xC8, + 0x30, 0x2E, 0xD3, 0xC4, 0x7F, 0xE6, 0x29, 0x72, 0xE0, 0x08, 0xE9, 0x32, 0x53, 0x97, 0xDB, 0x41, + 0x37, 0x98, 0xB3, 0x8A, 0xDC, 0xB8, 0xAF, 0xD3, 0x6A, 0x69, 0xD5, 0x12, 0xEC, 0x32, 0x61, 0xAF + }; + public static readonly byte[] ConstantGenerator = { 5 }; + + // ReSharper disable InconsistentNaming + public static void GeneratePrivateAndPublicA(BigNum a, BigNum A) + // ReSharper restore InconsistentNaming { - public static readonly byte[] ConstantPrime = - { - 0x98, 0x0F, 0x91, 0xEA, 0xAD, 0xAD, 0x8E, 0x7D, 0xF9, 0xEC, 0x43, 0x1D, 0xD4, 0x1C, 0xEF, 0x3F, - 0xBE, 0xCF, 0xD1, 0xAE, 0xD2, 0x77, 0x1C, 0xCF, 0xF8, 0x5E, 0xF8, 0x85, 0x3E, 0x2F, 0x9B, 0xC8, - 0x30, 0x2E, 0xD3, 0xC4, 0x7F, 0xE6, 0x29, 0x72, 0xE0, 0x08, 0xE9, 0x32, 0x53, 0x97, 0xDB, 0x41, - 0x37, 0x98, 0xB3, 0x8A, 0xDC, 0xB8, 0xAF, 0xD3, 0x6A, 0x69, 0xD5, 0x12, 0xEC, 0x32, 0x61, 0xAF - }; - public static readonly byte[] ConstantGenerator = { 5 }; - - // ReSharper disable InconsistentNaming - public static void GeneratePrivateAndPublicA(BigNum a, BigNum A) - // ReSharper restore InconsistentNaming - { - var prime = new BigNum(); - var generator = new BigNum(); - - prime.ReadBigEndian(ConstantPrime, 0, ConstantPrime.Length); - generator.ReadBigEndian(ConstantGenerator, 0, ConstantGenerator.Length); - - //Ok we are lame we just set a, to something low - //Bignum_SetUsint32(a, 5 + (GetTickCount()&0xFFFF)); - a.SetUInt32(19234); //Hardcoded for testing purposes - - //A = G ^ a mod P - A.ModExp(generator, a, prime); - } - - public static void GenerateServerK(BigNum a, BigNum b, BigNum k) - { - var prime = new BigNum(); - - prime.ReadBigEndian(ConstantPrime, 0, ConstantPrime.Length); - - k.ModExp(b, a, prime); - } + var prime = new BigNum(); + var generator = new BigNum(); + + prime.ReadBigEndian(ConstantPrime, 0, ConstantPrime.Length); + generator.ReadBigEndian(ConstantGenerator, 0, ConstantGenerator.Length); + + //Ok we are lame we just set a, to something low + //Bignum_SetUsint32(a, 5 + (GetTickCount()&0xFFFF)); + a.SetUInt32(19234); //Hardcoded for testing purposes + + //A = G ^ a mod P + A.ModExp(generator, a, prime); + } + + public static void GenerateServerK(BigNum a, BigNum b, BigNum k) + { + var prime = new BigNum(); + + prime.ReadBigEndian(ConstantPrime, 0, ConstantPrime.Length); + + k.ModExp(b, a, prime); } } diff --git a/src/Rasa.Utils/Cryptography/Game/Blowfish.cs b/src/Rasa.Utils/Cryptography/Game/Blowfish.cs index 44f84e38..0b2e0eed 100644 --- a/src/Rasa.Utils/Cryptography/Game/Blowfish.cs +++ b/src/Rasa.Utils/Cryptography/Game/Blowfish.cs @@ -1,227 +1,224 @@ -using System; +namespace Rasa.Cryptography.Game; -namespace Rasa.Cryptography.Game +public static class Blowfish { - public static class Blowfish + #region Const data init + private static readonly BlowfishData BfInit = new BlowfishData { - #region Const data init - private static readonly BlowfishData BfInit = new BlowfishData - { - P = new[] { 0x243F6A88U, 0x85A308D3U, 0x13198A2EU, 0x03707344U, 0x9216D5D9U, 0x8979FB1BU }, - S = new[] { - 0xD1310BA6U, 0x98DFB5ACU, 0x2FFD72DBU, 0xD01ADFB7U, 0xB8E1AFEDU, 0x6A267E96U, 0xBA7C9045U, 0xF12C7F99U, 0x24A19947U, 0xB3916CF7U, - 0x0801F2E2U, 0x858EFC16U, 0x636920D8U, 0x71574E69U, 0xA458FEA3U, 0xF4933D7EU, 0x0D95748FU, 0x728EB658U, 0x718BCD58U, 0x82154AEEU, - 0x7B54A41DU, 0xC25A59B5U, 0x9C30D539U, 0x2AF26013U, 0xC5D1B023U, 0x286085F0U, 0xCA417918U, 0xB8DB38EFU, 0x8E79DCB0U, 0x603A180EU, - 0x6C9E0E8BU, 0xB01E8A3EU, 0xD71577C1U, 0xBD314B27U, 0x78AF2FDAU, 0x55605C60U, 0xE65525F3U, 0xAA55AB94U, 0x57489862U, 0x63E81440U, - 0x55CA396AU, 0x2AAB10B6U, 0xB4CC5C34U, 0x1141E8CEU, 0xA15486AFU, 0x7C72E993U, 0xB3EE1411U, 0x636FBC2AU, 0x2BA9C55DU, 0x741831F6U, - 0xCE5C3E16U, 0x9B87931EU, 0xAFD6BA33U, 0x6C24CF5CU, 0x7A325381U, 0x28958677U, 0x3B8F4898U, 0x6B4BB9AFU, 0xC4BFE81BU, 0x66282193U, - 0x61D809CCU, 0xFB21A991U, 0x487CAC60U, 0x5DEC8032U, 0xEF845D5DU, 0xE98575B1U, 0xDC262302U, 0xEB651B88U, 0x23893E81U, 0xD396ACC5U, - 0x0F6D6FF3U, 0x83F44239U, 0x2E0B4482U, 0xA4842004U, 0x69C8F04AU, 0x9E1F9B5EU, 0x21C66842U, 0xF6E96C9AU, 0x670C9C61U, 0xABD388F0U, - 0x6A51A0D2U, 0xD8542F68U, 0x960FA728U, 0xAB5133A3U, 0x6EEF0B6CU, 0x137A3BE4U, 0xBA3BF050U, 0x7EFB2A98U, 0xA1F1651DU, 0x39AF0176U, - 0x66CA593EU, 0x82430E88U, 0x8CEE8619U, 0x456F9FB4U, 0x7D84A5C3U, 0x3B8B5EBEU, 0xE06F75D8U, 0x85C12073U, 0x401A449FU, 0x56C16AA6U, - 0x4ED3AA62U, 0x363F7706U, 0x1BFEDF72U, 0x429B023DU, 0x37D0D724U, 0xD00A1248U, 0xDB0FEAD3U, 0x49F1C09BU, 0x075372C9U, 0x80991B7BU, - 0x25D479D8U, 0xF6E8DEF7U, 0xE3FE501AU, 0xB6794C3BU, 0x976CE0BDU, 0x04C006BAU, 0xC1A94FB6U, 0x409F60C4U, 0x5E5C9EC2U, 0x196A2463U, - 0x68FB6FAFU, 0x3E6C53B5U, 0x1339B2EBU, 0x3B52EC6FU, 0x6DFC511FU, 0x9B30952CU, 0xCC814544U, 0xAF5EBD09U, 0xBEE3D004U, 0xDE334AFDU, - 0x660F2807U, 0x192E4BB3U, 0xC0CBA857U, 0x45C8740FU, 0xD20B5F39U, 0xB9D3FBDBU, 0x5579C0BDU, 0x1A60320AU, 0xD6A100C6U, 0x402C7279U, - 0x679F25FEU, 0xFB1FA3CCU, 0x8EA5E9F8U, 0xDB3222F8U, 0x3C7516DFU, 0xFD616B15U, 0x2F501EC8U, 0xAD0552ABU, 0x323DB5FAU, 0xFD238760U, - 0x53317B48U, 0x3E00DF82U, 0x9E5C57BBU, 0xCA6F8CA0U, 0x1A87562EU, 0xDF1769DBU, 0xD542A8F6U, 0x287EFFC3U, 0xAC6732C6U, 0x8C4F5573U, - 0x695B27B0U, 0xBBCA58C8U, 0xE1FFA35DU, 0xB8F011A0U, 0x10FA3D98U, 0xFD2183B8U, 0x4AFCB56CU, 0x2DD1D35BU, 0x9A53E479U, 0xB6F84565U, - 0xD28E49BCU, 0x4BFB9790U, 0xE1DDF2DAU, 0xA4CB7E33U, 0x62FB1341U, 0xCEE4C6E8U, 0xEF20CADAU, 0x36774C01U, 0xD07E9EFEU, 0x2BF11FB4U, - 0x95DBDA4DU, 0xAE909198U, 0xEAAD8E71U, 0x6B93D5A0U, 0xD08ED1D0U, 0xAFC725E0U, 0x8E3C5B2FU, 0x8E7594B7U, 0x8FF6E2FBU, 0xF2122B64U, - 0x8888B812U, 0x900DF01CU, 0x4FAD5EA0U, 0x688FC31CU, 0xD1CFF191U, 0xB3A8C1ADU, 0x2F2F2218U, 0xBE0E1777U, 0xEA752DFEU, 0x8B021FA1U, - 0xE5A0CC0FU, 0xB56F74E8U, 0x18ACF3D6U, 0xCE89E299U, 0xB4A84FE0U, 0xFD13E0B7U, 0x7CC43B81U, 0xD2ADA8D9U, 0x165FA266U, 0x80957705U, - 0x93CC7314U, 0x211A1477U, 0xE6AD2065U, 0x77B5FA86U, 0xC75442F5U, 0xFB9D35CFU, 0xEBCDAF0CU, 0x7B3E89A0U, 0xD6411BD3U, 0xAE1E7E49U, - 0x00250E2DU, 0x2071B35EU, 0x226800BBU, 0x57B8E0AFU, 0x2464369BU, 0xF009B91EU, 0x5563911DU, 0x59DFA6AAU, 0x78C14389U, 0xD95A537FU, - 0x207D5BA2U, 0x02E5B9C5U, 0x83260376U, 0x6295CFA9U, 0x11C81968U, 0x4E734A41U, 0xB3472DCAU, 0x7B14A94AU, 0x1B510052U, 0x9A532915U, - 0xD60F573FU, 0xBC9BC6E4U, 0x2B60A476U, 0x81E67400U, 0x08BA6FB5U, 0x571BE91FU, 0xF296EC6BU, 0x2A0DD915U, 0xB6636521U, 0xE7B9F9B6U, - 0xFF34052EU, 0xC5855664U, 0x53B02D5DU, 0xA99F8FA1U, 0x08BA4799U, 0x6E85076AU, 0x4B7A70E9U, 0xB5B32944U, 0xDB75092EU, 0xC4192623U, - 0xAD6EA6B0U, 0x49A7DF7DU, 0x9CEE60B8U, 0x8FEDB266U, 0xECAA8C71U, 0x699A17FFU, 0x5664526CU, 0xC2B19EE1U, 0x193602A5U, 0x75094C29U, - 0xA0591340U, 0xE4183A3EU, 0x3F54989AU, 0x5B429D65U, 0x6B8FE4D6U, 0x99F73FD6U, 0xA1D29C07U, 0xEFE830F5U, 0x4D2D38E6U, 0xF0255DC1U, - 0x4CDD2086U, 0x8470EB26U, 0x6382E9C6U, 0x021ECC5EU, 0x09686B3FU, 0x3EBAEFC9U, 0x3C971814U, 0x6B6A70A1U, 0x687F3584U, 0x52A0E286U, - 0xB79C5305U, 0xAA500737U, 0x3E07841CU, 0x7FDEAE5CU, 0x8E7D44ECU, 0x5716F2B8U, 0xB03ADA37U, 0xF0500C0DU, 0xF01C1F04U, 0x0200B3FFU, - 0xAE0CF51AU, 0x3CB574B2U, 0x25837A58U, 0xDC0921BDU, 0xD19113F9U, 0x7CA92FF6U, 0x94324773U, 0x22F54701U, 0x3AE5E581U, 0x37C2DADCU, - 0xC8B57634U, 0x9AF3DDA7U, 0xA9446146U, 0x0FD0030EU, 0xECC8C73EU, 0xA4751E41U, 0xE238CD99U, 0x3BEA0E2FU, 0x3280BBA1U, 0x183EB331U, - 0x4E548B38U, 0x4F6DB908U, 0x6F420D03U, 0xF60A04BFU, 0x2CB81290U, 0x24977C79U, 0x5679B072U, 0xBCAF89AFU, 0xDE9A771FU, 0xD9930810U, - 0xB38BAE12U, 0xDCCF3F2EU, 0x5512721FU, 0x2E6B7124U, 0x501ADDE6U, 0x9F84CD87U, 0x7A584718U, 0x7408DA17U, 0xBC9F9ABCU, 0xE94B7D8CU, - 0xEC7AEC3AU, 0xDB851DFAU, 0x63094366U, 0xC464C3D2U, 0xEF1C1847U, 0x3215D908U, 0xDD433B37U, 0x24C2BA16U, 0x12A14D43U, 0x2A65C451U, - 0x50940002U, 0x133AE4DDU, 0x71DFF89EU, 0x10314E55U, 0x81AC77D6U, 0x5F11199BU, 0x043556F1U, 0xD7A3C76BU, 0x3C11183BU, 0x5924A509U, - 0xF28FE6EDU, 0x97F1FBFAU, 0x9EBABF2CU, 0x1E153C6EU, 0x86E34570U, 0xEAE96FB1U, 0x860E5E0AU, 0x5A3E2AB3U, 0x771FE71CU, 0x4E3D06FAU, - 0x2965DCB9U, 0x99E71D0FU, 0x803E89D6U, 0x5266C825U, 0x2E4CC978U, 0x9C10B36AU, 0xC6150EBAU, 0x94E2EA78U, 0xA5FC3C53U, 0x1E0A2DF4U, - 0xF2F74EA7U, 0x361D2B3DU, 0x1939260FU, 0x19C27960U, 0x5223A708U, 0xF71312B6U, 0xEBADFE6EU, 0xEAC31F66U, 0xE3BC4595U, 0xA67BC883U, - 0xB17F37D1U, 0x018CFF28U, 0xC332DDEFU, 0xBE6C5AA5U, 0x65582185U, 0x68AB9802U, 0xEECEA50FU, 0xDB2F953BU, 0x2AEF7DADU, 0x5B6E2F84U, - 0x1521B628U, 0x29076170U, 0xECDD4775U, 0x619F1510U, 0x13CCA830U, 0xEB61BD96U, 0x0334FE1EU, 0xAA0363CFU, 0xB5735C90U, 0x4C70A239U, - 0xD59E9E0BU, 0xCBAADE14U, 0xEECC86BCU, 0x60622CA7U, 0x9CAB5CABU, 0xB2F3846EU, 0x648B1EAFU, 0x19BDF0CAU, 0xA02369B9U, 0x655ABB50U, - 0x40685A32U, 0x3C2AB4B3U, 0x319EE9D5U, 0xC021B8F7U, 0x9B540B19U, 0x875FA099U, 0x95F7997EU, 0x623D7DA8U, 0xF837889AU, 0x97E32D77U, - 0x11ED935FU, 0x16681281U, 0x0E358829U, 0xC7E61FD6U, 0x96DEDFA1U, 0x7858BA99U, 0x57F584A5U, 0x1B227263U, 0x9B83C3FFU, 0x1AC24696U, - 0xCDB30AEBU, 0x532E3054U, 0x8FD948E4U, 0x6DBC3128U, 0x58EBF2EFU, 0x34C6FFEAU, 0xFE28ED61U, 0xEE7C3C73U, 0x5D4A14D9U, 0xE864B7E3U, - 0x42105D14U, 0x203E13E0U, 0x45EEE2B6U, 0xA3AAABEAU, 0xDB6C4F15U, 0xFACB4FD0U, 0xC742F442U, 0xEF6ABBB5U, 0x654F3B1DU, 0x41CD2105U, - 0xD81E799EU, 0x86854DC7U, 0xE44B476AU, 0x3D816250U, 0xCF62A1F2U, 0x5B8D2646U, 0xFC8883A0U, 0xC1C7B6A3U, 0x7F1524C3U, 0x69CB7492U, - 0x47848A0BU, 0x5692B285U, 0x095BBF00U, 0xAD19489DU, 0x1462B174U, 0x23820E00U, 0x58428D2AU, 0x0C55F5EAU, 0x1DADF43EU, 0x233F7061U, - 0x3372F092U, 0x8D937E41U, 0xD65FECF1U, 0x6C223BDBU, 0x7CDE3759U, 0xCBEE7460U, 0x4085F2A7U, 0xCE77326EU, 0xA6078084U, 0x19F8509EU, - 0xE8EFD855U, 0x61D99735U, 0xA969A7AAU, 0xC50C06C2U, 0x5A04ABFCU, 0x800BCADCU, 0x9E447A2EU, 0xC3453484U, 0xFDD56705U, 0x0E1E9EC9U, - 0xDB73DBD3U, 0x105588CDU, 0x675FDA79U, 0xE3674340U, 0xC5C43465U, 0x713E38D8U, 0x3D28F89EU, 0xF16DFF20U, 0x153E21E7U, 0x8FB03D4AU, - 0xE6E39F2BU, 0xDB83ADF7U, 0xE93D5A68U, 0x948140F7U, 0xF64C261CU, 0x94692934U, 0x411520F7U, 0x7602D4F7U, 0xBCF46B2EU, 0xD4A20068U, - 0xD4082471U, 0x3320F46AU, 0x43B7D4B7U, 0x500061AFU, 0x1E39F62EU, 0x97244546U, 0x14214F74U, 0xBF8B8840U, 0x4D95FC1DU, 0x96B591AFU, - 0x70F4DDD3U, 0x66A02F45U, 0xBFBC09ECU, 0x03BD9785U, 0x7FAC6DD0U, 0x31CB8504U, 0x96EB27B3U, 0x55FD3941U, 0xDA2547E6U, 0xABCA0A9AU, - 0x28507825U, 0x530429F4U, 0x0A2C86DAU, 0xE9B66DFBU, 0x68DC1462U, 0xD7486900U, 0x680EC0A4U, 0x27A18DEEU, 0x4F3FFEA2U, 0xE887AD8CU, - 0xB58CE006U, 0x7AF4D6B6U, 0xAACE1E7CU, 0xD3375FECU, 0xCE78A399U, 0x406B2A42U, 0x20FE9E35U, 0xD9F385B9U, 0xEE39D7ABU, 0x3B124E8BU, - 0x1DC9FAF7U, 0x4B6D1856U, 0x26A36631U, 0xEAE397B2U, 0x3A6EFA74U, 0xDD5B4332U, 0x6841E7F7U, 0xCA7820FBU, 0xFB0AF54EU, 0xD8FEB397U, - 0x454056ACU, 0xBA489527U, 0x55533A3AU, 0x20838D87U, 0xFE6BA9B7U, 0xD096954BU, 0x55A867BCU, 0xA1159A58U, 0xCCA92963U, 0x99E1DB33U, - 0xA62A4A56U, 0x3F3125F9U, 0x5EF47E1CU, 0x9029317CU, 0xFDF8E802U, 0x04272F70U, 0x80BB155CU, 0x05282CE3U, 0x95C11548U, 0xE4C66D22U, - 0x48C1133FU, 0xC70F86DCU, 0x07F9C9EEU, 0x41041F0FU, 0x404779A4U, 0x5D886E17U, 0x325F51EBU, 0xD59BC0D1U, 0xF2BCC18FU, 0x41113564U, - 0x257B7834U, 0x602A9C60U, 0xDFF8E8A3U, 0x1F636C1BU, 0x0E12B4C2U, 0x02E1329EU, 0xAF664FD1U, 0xCAD18115U, 0x6B2395E0U, 0x333E92E1U, - 0x3B240B62U, 0xEEBEB922U, 0x85B2A20EU, 0xE6BA0D99U, 0xDE720C8CU, 0x2DA2F728U, 0xD0127845U, 0x95B794FDU, 0x647D0862U, 0xE7CCF5F0U, - 0x5449A36FU, 0x877D48FAU, 0xC39DFD27U, 0xF33E8D1EU, 0x0A476341U, 0x992EFF74U, 0x3A6F6EABU, 0xF4F8FD37U, 0xA812DC60U, 0xA1EBDDF8U, - 0x991BE14CU, 0xDB6E6B0DU, 0xC67B5510U, 0x6D672C37U, 0x2765D43BU, 0xDCD0E804U, 0xF1290DC7U, 0xCC00FFA3U, 0xB5390F92U, 0x690FED0BU, - 0x667B9FFBU, 0xCEDB7D9CU, 0xA091CF0BU, 0xD9155EA3U, 0xBB132F88U, 0x515BAD24U, 0x7B9479BFU, 0x763BD6EBU, 0x37392EB3U, 0xCC115979U, - 0x8026E297U, 0xF42E312DU, 0x6842ADA7U, 0xC66A2B3BU, 0x12754CCCU, 0x782EF11CU, 0x6A124237U, 0xB79251E7U, 0x06A1BBE6U, 0x4BFB6350U, - 0x1A6B1018U, 0x11CAEDFAU, 0x3D25BDD8U, 0xE2E1C3C9U, 0x44421659U, 0x0A121386U, 0xD90CEC6EU, 0xD5ABEA2AU, 0x64AF674EU, 0xDA86A85FU, - 0xBEBFE988U, 0x64E4C3FEU, 0x9DBC8057U, 0xF0F7C086U, 0x60787BF8U, 0x6003604DU, 0xD1FD8346U, 0xF6381FB0U, 0x7745AE04U, 0xD736FCCCU, - 0x83426B33U, 0xF01EAB71U, 0xB0804187U, 0x3C005E5FU, 0x77A057BEU, 0xBDE8AE24U, 0x55464299U, 0xBF582E61U, 0x4E58F48FU, 0xF2DDFDA2U, - 0xF474EF38U, 0x8789BDC2U, 0x5366F9C3U, 0xC8B38E74U, 0xB475F255U, 0x46FCD9B9U, 0x7AEB2661U, 0x8B1DDF84U, 0x846A0E79U, 0x915F95E2U, - 0x466E598EU, 0x20B45770U, 0x8CD55591U, 0xC902DE4CU, 0xB90BACE1U, 0xBB8205D0U, 0x11A86248U, 0x7574A99EU, 0xB77F19B6U, 0xE0A9DC09U, - 0x662D09A1U, 0xC4324633U, 0xE85A1F02U, 0x09F0BE8CU, 0x4A99A025U, 0x1D6EFE10U, 0x1AB93D1DU, 0x0BA5A4DFU, 0xA186F20FU, 0x2868F169U, - 0xDCB7DA83U, 0x573906FEU, 0xA1E2CE9BU, 0x4FCD7F52U, 0x50115E01U, 0xA70683FAU, 0xA002B5C4U, 0x0DE6D027U, 0x9AF88C27U, 0x773F8641U, - 0xC3604C06U, 0x61A806B5U, 0xF0177A28U, 0xC0F586E0U, 0x006058AAU, 0x30DC7D62U, 0x11E69ED7U, 0x2338EA63U, 0x53C2DD94U, 0xC2C21634U, - 0xBBCBEE56U, 0x90BCB6DEU, 0xEBFC7DA1U, 0xCE591D76U, 0x6F05E409U, 0x4B7C0188U, 0x39720A3DU, 0x7C927C24U, 0x86E3725FU, 0x724D9DB9U, - 0x1AC15BB4U, 0xD39EB8FCU, 0xED545578U, 0x08FCA5B5U, 0xD83D7CD3U, 0x4DAD0FC4U, 0x1E50EF5EU, 0xB161E6F8U, 0xA28514D9U, 0x6C51133CU, - 0x6FD5C7E7U, 0x56E14EC4U, 0x362ABFCEU, 0xDDC6C837U, 0xD79A3234U, 0x92638212U, 0x670EFA8EU, 0x406000E0U, 0x3A39CE37U, 0xD3FAF5CFU, - 0xABC27737U, 0x5AC52D1BU, 0x5CB0679EU, 0x4FA33742U, 0xD3822740U, 0x99BC9BBEU, 0xD5118E9DU, 0xBF0F7315U, 0xD62D1C7EU, 0xC700C47BU, - 0xB78C1B6BU, 0x21A19045U, 0xB26EB1BEU, 0x6A366EB4U, 0x5748AB2FU, 0xBC946E79U, 0xC6A376D2U, 0x6549C2C8U, 0x530FF8EEU, 0x468DDE7DU, - 0xD5730A1DU, 0x4CD04DC6U, 0x2939BBDBU, 0xA9BA4650U, 0xAC9526E8U, 0xBE5EE304U, 0xA1FAD5F0U, 0x6A2D519AU, 0x63EF8CE2U, 0x9A86EE22U, - 0xC089C2B8U, 0x43242EF6U, 0xA51E03AAU, 0x9CF2D0A4U, 0x83C061BAU, 0x9BE96A4DU, 0x8FE51550U, 0xBA645BD6U, 0x2826A2F9U, 0xA73A3AE1U, - 0x4BA99586U, 0xEF5562E9U, 0xC72FEFD3U, 0xF752F7DAU, 0x3F046F69U, 0x77FA0A59U, 0x80E4A915U, 0x87B08601U, 0x9B09E6ADU, 0x3B3EE593U, - 0xE990FD5AU, 0x9E34D797U, 0x2CF0B7D9U, 0x022B8B51U, 0x96D5AC3AU, 0x017DA67DU, 0xD1CF3ED6U, 0x7C7D2D28U, 0x1F9F25CFU, 0xADF2B89BU, - 0x5AD6B472U, 0x5A88F54CU, 0xE029AC71U, 0xE019A5E6U, 0x47B0ACFDU, 0xED93FA9BU, 0xE8D3C48DU, 0x283B57CCU, 0xF8D56629U, 0x79132E28U, - 0x785F0191U, 0xED756055U, 0xF7960E44U, 0xE3D35E8CU, 0x15056DD4U, 0x88F46DBAU, 0x03A16125U, 0x0564F0BDU, 0xC3EB9E15U, 0x3C9057A2U, - 0x97271AECU, 0xA93A072AU, 0x1B3F6D9BU, 0x1E6321F5U, 0xF59C66FBU, 0x26DCF319U, 0x7533D928U, 0xB155FDF5U, 0x03563482U, 0x8ABA3CBBU, - 0x28517711U, 0xC20AD9F8U, 0xABCC5167U, 0xCCAD925FU, 0x4DE81751U, 0x3830DC8EU, 0x379D5862U, 0x9320F991U, 0xEA7A90C2U, 0xFB3E7BCEU, - 0x5121CE64U, 0x774FBE32U, 0xA8B6E37EU, 0xC3293D46U, 0x48DE5369U, 0x6413E680U, 0xA2AE0810U, 0xDD6DB224U, 0x69852DFDU, 0x09072166U, - 0xB39A460AU, 0x6445C0DDU, 0x586CDECFU, 0x1C20C8AEU, 0x5BBEF7DDU, 0x1B588D40U, 0xCCD2017FU, 0x6BB4E3BBU, 0xDDA26A7EU, 0x3A59FF45U, - 0x3E350A44U, 0xBCB4CDD5U, 0x72EACEA8U, 0xFA6484BBU, 0x8D6612AEU, 0xBF3C6F47U, 0xD29BE463U, 0x542F5D9EU, 0xAEC2771BU, 0xF64E6370U, - 0x740E0D8DU, 0xE75B1357U, 0xF8721671U, 0xAF537D5DU, 0x4040CB08U, 0x4EB4E2CCU, 0x34D2466AU, 0x0115AF84U, 0xE1B00428U, 0x95983A1DU, - 0x06B89FB4U, 0xCE6EA048U, 0x6F3F3B82U, 0x3520AB82U, 0x011A1D4BU, 0x277227F8U, 0x611560B1U, 0xE7933FDCU, 0xBB3A792BU, 0x344525BDU, - 0xA08839E1U, 0x51CE794BU, 0x2F32C9B7U, 0xA01FBAC9U, 0xE01CC87EU, 0xBCC7D1F6U, 0xCF0111C3U, 0xA1E8AAC7U, 0x1A908749U, 0xD44FBD9AU, - 0xD0DADECBU, 0xD50ADA38U, 0x0339C32AU, 0xC6913667U, 0x8DF9317CU, 0xE0B12B4FU, 0xF79E59B7U, 0x43F5BB3AU, 0xF2D519FFU, 0x27D9459CU, - 0xBF97222CU, 0x15E6FC2AU, 0x0F91FC71U, 0x9B941525U, 0xFAE59361U, 0xCEB69CEBU, 0xC2A86459U, 0x12BAA8D1U, 0xB6C1075EU, 0xE3056A0CU, - 0x10D25065U, 0xCB03A442U, 0xE0EC6E0EU, 0x1698DB3BU, 0x4C98A0BEU, 0x3278E964U, 0x9F1F9532U, 0xE0D392DFU, 0xD3A0342BU, 0x8971F21EU, - 0x1B0A7441U, 0x4BA3348CU, 0xC5BE7120U, 0xC37632D8U, 0xDF359F8DU, 0x9B992F2EU, 0xE60B6F47U, 0x0FE3F11DU, 0xE54CDA54U, 0x1EDAD891U, - 0xCE6279CFU, 0xCD3E7E6FU, 0x1618B166U, 0xFD2C1D05U, 0x848FD2C5U, 0xF6FB2299U, 0xF523F357U, 0xA6327623U, 0x93A83531U, 0x56CCCD02U, - 0xACF08162U, 0x5A75EBB5U, 0x6E163697U, 0x88D273CCU, 0xDE966292U, 0x81B949D0U, 0x4C50901BU, 0x71C65614U, 0xE6C6C7BDU, 0x327A140AU, - 0x45E1D006U, 0xC3F27B9AU, 0xC9AA53FDU, 0x62A80F00U, 0xBB25BFE2U, 0x35BDD2F6U, 0x71126905U, 0xB2040222U, 0xB6CBCF7CU, 0xCD769C2BU, - 0x53113EC0U, 0x1640E3D3U, 0x38ABBD60U, 0x2547ADF0U, 0xBA38209CU, 0xF746CE76U, 0x77AFA1C5U, 0x20756060U, 0x85CBFE4EU, 0x8AE88DD8U, - 0x7AAAF9B0U, 0x4CF9AA7EU, 0x1948C25CU, 0x02FB8A8CU, 0x01C36AE4U, 0xD6EBE1F9U, 0x90D4F869U, 0xA65CDEA0U, 0x3F09252DU, 0xC208E69FU, - 0xB74E6132U, 0xCE77E25BU, 0x578FDFE3U, 0x3AC372E6U - } - }; - - private const int BfRounds = 4; - #endregion - - private static void Enc(ref uint ll, uint r, BlowfishData key, int pi) - { - ll ^= key.P[pi]; + P = new[] { 0x243F6A88U, 0x85A308D3U, 0x13198A2EU, 0x03707344U, 0x9216D5D9U, 0x8979FB1BU }, + S = new[] { + 0xD1310BA6U, 0x98DFB5ACU, 0x2FFD72DBU, 0xD01ADFB7U, 0xB8E1AFEDU, 0x6A267E96U, 0xBA7C9045U, 0xF12C7F99U, 0x24A19947U, 0xB3916CF7U, + 0x0801F2E2U, 0x858EFC16U, 0x636920D8U, 0x71574E69U, 0xA458FEA3U, 0xF4933D7EU, 0x0D95748FU, 0x728EB658U, 0x718BCD58U, 0x82154AEEU, + 0x7B54A41DU, 0xC25A59B5U, 0x9C30D539U, 0x2AF26013U, 0xC5D1B023U, 0x286085F0U, 0xCA417918U, 0xB8DB38EFU, 0x8E79DCB0U, 0x603A180EU, + 0x6C9E0E8BU, 0xB01E8A3EU, 0xD71577C1U, 0xBD314B27U, 0x78AF2FDAU, 0x55605C60U, 0xE65525F3U, 0xAA55AB94U, 0x57489862U, 0x63E81440U, + 0x55CA396AU, 0x2AAB10B6U, 0xB4CC5C34U, 0x1141E8CEU, 0xA15486AFU, 0x7C72E993U, 0xB3EE1411U, 0x636FBC2AU, 0x2BA9C55DU, 0x741831F6U, + 0xCE5C3E16U, 0x9B87931EU, 0xAFD6BA33U, 0x6C24CF5CU, 0x7A325381U, 0x28958677U, 0x3B8F4898U, 0x6B4BB9AFU, 0xC4BFE81BU, 0x66282193U, + 0x61D809CCU, 0xFB21A991U, 0x487CAC60U, 0x5DEC8032U, 0xEF845D5DU, 0xE98575B1U, 0xDC262302U, 0xEB651B88U, 0x23893E81U, 0xD396ACC5U, + 0x0F6D6FF3U, 0x83F44239U, 0x2E0B4482U, 0xA4842004U, 0x69C8F04AU, 0x9E1F9B5EU, 0x21C66842U, 0xF6E96C9AU, 0x670C9C61U, 0xABD388F0U, + 0x6A51A0D2U, 0xD8542F68U, 0x960FA728U, 0xAB5133A3U, 0x6EEF0B6CU, 0x137A3BE4U, 0xBA3BF050U, 0x7EFB2A98U, 0xA1F1651DU, 0x39AF0176U, + 0x66CA593EU, 0x82430E88U, 0x8CEE8619U, 0x456F9FB4U, 0x7D84A5C3U, 0x3B8B5EBEU, 0xE06F75D8U, 0x85C12073U, 0x401A449FU, 0x56C16AA6U, + 0x4ED3AA62U, 0x363F7706U, 0x1BFEDF72U, 0x429B023DU, 0x37D0D724U, 0xD00A1248U, 0xDB0FEAD3U, 0x49F1C09BU, 0x075372C9U, 0x80991B7BU, + 0x25D479D8U, 0xF6E8DEF7U, 0xE3FE501AU, 0xB6794C3BU, 0x976CE0BDU, 0x04C006BAU, 0xC1A94FB6U, 0x409F60C4U, 0x5E5C9EC2U, 0x196A2463U, + 0x68FB6FAFU, 0x3E6C53B5U, 0x1339B2EBU, 0x3B52EC6FU, 0x6DFC511FU, 0x9B30952CU, 0xCC814544U, 0xAF5EBD09U, 0xBEE3D004U, 0xDE334AFDU, + 0x660F2807U, 0x192E4BB3U, 0xC0CBA857U, 0x45C8740FU, 0xD20B5F39U, 0xB9D3FBDBU, 0x5579C0BDU, 0x1A60320AU, 0xD6A100C6U, 0x402C7279U, + 0x679F25FEU, 0xFB1FA3CCU, 0x8EA5E9F8U, 0xDB3222F8U, 0x3C7516DFU, 0xFD616B15U, 0x2F501EC8U, 0xAD0552ABU, 0x323DB5FAU, 0xFD238760U, + 0x53317B48U, 0x3E00DF82U, 0x9E5C57BBU, 0xCA6F8CA0U, 0x1A87562EU, 0xDF1769DBU, 0xD542A8F6U, 0x287EFFC3U, 0xAC6732C6U, 0x8C4F5573U, + 0x695B27B0U, 0xBBCA58C8U, 0xE1FFA35DU, 0xB8F011A0U, 0x10FA3D98U, 0xFD2183B8U, 0x4AFCB56CU, 0x2DD1D35BU, 0x9A53E479U, 0xB6F84565U, + 0xD28E49BCU, 0x4BFB9790U, 0xE1DDF2DAU, 0xA4CB7E33U, 0x62FB1341U, 0xCEE4C6E8U, 0xEF20CADAU, 0x36774C01U, 0xD07E9EFEU, 0x2BF11FB4U, + 0x95DBDA4DU, 0xAE909198U, 0xEAAD8E71U, 0x6B93D5A0U, 0xD08ED1D0U, 0xAFC725E0U, 0x8E3C5B2FU, 0x8E7594B7U, 0x8FF6E2FBU, 0xF2122B64U, + 0x8888B812U, 0x900DF01CU, 0x4FAD5EA0U, 0x688FC31CU, 0xD1CFF191U, 0xB3A8C1ADU, 0x2F2F2218U, 0xBE0E1777U, 0xEA752DFEU, 0x8B021FA1U, + 0xE5A0CC0FU, 0xB56F74E8U, 0x18ACF3D6U, 0xCE89E299U, 0xB4A84FE0U, 0xFD13E0B7U, 0x7CC43B81U, 0xD2ADA8D9U, 0x165FA266U, 0x80957705U, + 0x93CC7314U, 0x211A1477U, 0xE6AD2065U, 0x77B5FA86U, 0xC75442F5U, 0xFB9D35CFU, 0xEBCDAF0CU, 0x7B3E89A0U, 0xD6411BD3U, 0xAE1E7E49U, + 0x00250E2DU, 0x2071B35EU, 0x226800BBU, 0x57B8E0AFU, 0x2464369BU, 0xF009B91EU, 0x5563911DU, 0x59DFA6AAU, 0x78C14389U, 0xD95A537FU, + 0x207D5BA2U, 0x02E5B9C5U, 0x83260376U, 0x6295CFA9U, 0x11C81968U, 0x4E734A41U, 0xB3472DCAU, 0x7B14A94AU, 0x1B510052U, 0x9A532915U, + 0xD60F573FU, 0xBC9BC6E4U, 0x2B60A476U, 0x81E67400U, 0x08BA6FB5U, 0x571BE91FU, 0xF296EC6BU, 0x2A0DD915U, 0xB6636521U, 0xE7B9F9B6U, + 0xFF34052EU, 0xC5855664U, 0x53B02D5DU, 0xA99F8FA1U, 0x08BA4799U, 0x6E85076AU, 0x4B7A70E9U, 0xB5B32944U, 0xDB75092EU, 0xC4192623U, + 0xAD6EA6B0U, 0x49A7DF7DU, 0x9CEE60B8U, 0x8FEDB266U, 0xECAA8C71U, 0x699A17FFU, 0x5664526CU, 0xC2B19EE1U, 0x193602A5U, 0x75094C29U, + 0xA0591340U, 0xE4183A3EU, 0x3F54989AU, 0x5B429D65U, 0x6B8FE4D6U, 0x99F73FD6U, 0xA1D29C07U, 0xEFE830F5U, 0x4D2D38E6U, 0xF0255DC1U, + 0x4CDD2086U, 0x8470EB26U, 0x6382E9C6U, 0x021ECC5EU, 0x09686B3FU, 0x3EBAEFC9U, 0x3C971814U, 0x6B6A70A1U, 0x687F3584U, 0x52A0E286U, + 0xB79C5305U, 0xAA500737U, 0x3E07841CU, 0x7FDEAE5CU, 0x8E7D44ECU, 0x5716F2B8U, 0xB03ADA37U, 0xF0500C0DU, 0xF01C1F04U, 0x0200B3FFU, + 0xAE0CF51AU, 0x3CB574B2U, 0x25837A58U, 0xDC0921BDU, 0xD19113F9U, 0x7CA92FF6U, 0x94324773U, 0x22F54701U, 0x3AE5E581U, 0x37C2DADCU, + 0xC8B57634U, 0x9AF3DDA7U, 0xA9446146U, 0x0FD0030EU, 0xECC8C73EU, 0xA4751E41U, 0xE238CD99U, 0x3BEA0E2FU, 0x3280BBA1U, 0x183EB331U, + 0x4E548B38U, 0x4F6DB908U, 0x6F420D03U, 0xF60A04BFU, 0x2CB81290U, 0x24977C79U, 0x5679B072U, 0xBCAF89AFU, 0xDE9A771FU, 0xD9930810U, + 0xB38BAE12U, 0xDCCF3F2EU, 0x5512721FU, 0x2E6B7124U, 0x501ADDE6U, 0x9F84CD87U, 0x7A584718U, 0x7408DA17U, 0xBC9F9ABCU, 0xE94B7D8CU, + 0xEC7AEC3AU, 0xDB851DFAU, 0x63094366U, 0xC464C3D2U, 0xEF1C1847U, 0x3215D908U, 0xDD433B37U, 0x24C2BA16U, 0x12A14D43U, 0x2A65C451U, + 0x50940002U, 0x133AE4DDU, 0x71DFF89EU, 0x10314E55U, 0x81AC77D6U, 0x5F11199BU, 0x043556F1U, 0xD7A3C76BU, 0x3C11183BU, 0x5924A509U, + 0xF28FE6EDU, 0x97F1FBFAU, 0x9EBABF2CU, 0x1E153C6EU, 0x86E34570U, 0xEAE96FB1U, 0x860E5E0AU, 0x5A3E2AB3U, 0x771FE71CU, 0x4E3D06FAU, + 0x2965DCB9U, 0x99E71D0FU, 0x803E89D6U, 0x5266C825U, 0x2E4CC978U, 0x9C10B36AU, 0xC6150EBAU, 0x94E2EA78U, 0xA5FC3C53U, 0x1E0A2DF4U, + 0xF2F74EA7U, 0x361D2B3DU, 0x1939260FU, 0x19C27960U, 0x5223A708U, 0xF71312B6U, 0xEBADFE6EU, 0xEAC31F66U, 0xE3BC4595U, 0xA67BC883U, + 0xB17F37D1U, 0x018CFF28U, 0xC332DDEFU, 0xBE6C5AA5U, 0x65582185U, 0x68AB9802U, 0xEECEA50FU, 0xDB2F953BU, 0x2AEF7DADU, 0x5B6E2F84U, + 0x1521B628U, 0x29076170U, 0xECDD4775U, 0x619F1510U, 0x13CCA830U, 0xEB61BD96U, 0x0334FE1EU, 0xAA0363CFU, 0xB5735C90U, 0x4C70A239U, + 0xD59E9E0BU, 0xCBAADE14U, 0xEECC86BCU, 0x60622CA7U, 0x9CAB5CABU, 0xB2F3846EU, 0x648B1EAFU, 0x19BDF0CAU, 0xA02369B9U, 0x655ABB50U, + 0x40685A32U, 0x3C2AB4B3U, 0x319EE9D5U, 0xC021B8F7U, 0x9B540B19U, 0x875FA099U, 0x95F7997EU, 0x623D7DA8U, 0xF837889AU, 0x97E32D77U, + 0x11ED935FU, 0x16681281U, 0x0E358829U, 0xC7E61FD6U, 0x96DEDFA1U, 0x7858BA99U, 0x57F584A5U, 0x1B227263U, 0x9B83C3FFU, 0x1AC24696U, + 0xCDB30AEBU, 0x532E3054U, 0x8FD948E4U, 0x6DBC3128U, 0x58EBF2EFU, 0x34C6FFEAU, 0xFE28ED61U, 0xEE7C3C73U, 0x5D4A14D9U, 0xE864B7E3U, + 0x42105D14U, 0x203E13E0U, 0x45EEE2B6U, 0xA3AAABEAU, 0xDB6C4F15U, 0xFACB4FD0U, 0xC742F442U, 0xEF6ABBB5U, 0x654F3B1DU, 0x41CD2105U, + 0xD81E799EU, 0x86854DC7U, 0xE44B476AU, 0x3D816250U, 0xCF62A1F2U, 0x5B8D2646U, 0xFC8883A0U, 0xC1C7B6A3U, 0x7F1524C3U, 0x69CB7492U, + 0x47848A0BU, 0x5692B285U, 0x095BBF00U, 0xAD19489DU, 0x1462B174U, 0x23820E00U, 0x58428D2AU, 0x0C55F5EAU, 0x1DADF43EU, 0x233F7061U, + 0x3372F092U, 0x8D937E41U, 0xD65FECF1U, 0x6C223BDBU, 0x7CDE3759U, 0xCBEE7460U, 0x4085F2A7U, 0xCE77326EU, 0xA6078084U, 0x19F8509EU, + 0xE8EFD855U, 0x61D99735U, 0xA969A7AAU, 0xC50C06C2U, 0x5A04ABFCU, 0x800BCADCU, 0x9E447A2EU, 0xC3453484U, 0xFDD56705U, 0x0E1E9EC9U, + 0xDB73DBD3U, 0x105588CDU, 0x675FDA79U, 0xE3674340U, 0xC5C43465U, 0x713E38D8U, 0x3D28F89EU, 0xF16DFF20U, 0x153E21E7U, 0x8FB03D4AU, + 0xE6E39F2BU, 0xDB83ADF7U, 0xE93D5A68U, 0x948140F7U, 0xF64C261CU, 0x94692934U, 0x411520F7U, 0x7602D4F7U, 0xBCF46B2EU, 0xD4A20068U, + 0xD4082471U, 0x3320F46AU, 0x43B7D4B7U, 0x500061AFU, 0x1E39F62EU, 0x97244546U, 0x14214F74U, 0xBF8B8840U, 0x4D95FC1DU, 0x96B591AFU, + 0x70F4DDD3U, 0x66A02F45U, 0xBFBC09ECU, 0x03BD9785U, 0x7FAC6DD0U, 0x31CB8504U, 0x96EB27B3U, 0x55FD3941U, 0xDA2547E6U, 0xABCA0A9AU, + 0x28507825U, 0x530429F4U, 0x0A2C86DAU, 0xE9B66DFBU, 0x68DC1462U, 0xD7486900U, 0x680EC0A4U, 0x27A18DEEU, 0x4F3FFEA2U, 0xE887AD8CU, + 0xB58CE006U, 0x7AF4D6B6U, 0xAACE1E7CU, 0xD3375FECU, 0xCE78A399U, 0x406B2A42U, 0x20FE9E35U, 0xD9F385B9U, 0xEE39D7ABU, 0x3B124E8BU, + 0x1DC9FAF7U, 0x4B6D1856U, 0x26A36631U, 0xEAE397B2U, 0x3A6EFA74U, 0xDD5B4332U, 0x6841E7F7U, 0xCA7820FBU, 0xFB0AF54EU, 0xD8FEB397U, + 0x454056ACU, 0xBA489527U, 0x55533A3AU, 0x20838D87U, 0xFE6BA9B7U, 0xD096954BU, 0x55A867BCU, 0xA1159A58U, 0xCCA92963U, 0x99E1DB33U, + 0xA62A4A56U, 0x3F3125F9U, 0x5EF47E1CU, 0x9029317CU, 0xFDF8E802U, 0x04272F70U, 0x80BB155CU, 0x05282CE3U, 0x95C11548U, 0xE4C66D22U, + 0x48C1133FU, 0xC70F86DCU, 0x07F9C9EEU, 0x41041F0FU, 0x404779A4U, 0x5D886E17U, 0x325F51EBU, 0xD59BC0D1U, 0xF2BCC18FU, 0x41113564U, + 0x257B7834U, 0x602A9C60U, 0xDFF8E8A3U, 0x1F636C1BU, 0x0E12B4C2U, 0x02E1329EU, 0xAF664FD1U, 0xCAD18115U, 0x6B2395E0U, 0x333E92E1U, + 0x3B240B62U, 0xEEBEB922U, 0x85B2A20EU, 0xE6BA0D99U, 0xDE720C8CU, 0x2DA2F728U, 0xD0127845U, 0x95B794FDU, 0x647D0862U, 0xE7CCF5F0U, + 0x5449A36FU, 0x877D48FAU, 0xC39DFD27U, 0xF33E8D1EU, 0x0A476341U, 0x992EFF74U, 0x3A6F6EABU, 0xF4F8FD37U, 0xA812DC60U, 0xA1EBDDF8U, + 0x991BE14CU, 0xDB6E6B0DU, 0xC67B5510U, 0x6D672C37U, 0x2765D43BU, 0xDCD0E804U, 0xF1290DC7U, 0xCC00FFA3U, 0xB5390F92U, 0x690FED0BU, + 0x667B9FFBU, 0xCEDB7D9CU, 0xA091CF0BU, 0xD9155EA3U, 0xBB132F88U, 0x515BAD24U, 0x7B9479BFU, 0x763BD6EBU, 0x37392EB3U, 0xCC115979U, + 0x8026E297U, 0xF42E312DU, 0x6842ADA7U, 0xC66A2B3BU, 0x12754CCCU, 0x782EF11CU, 0x6A124237U, 0xB79251E7U, 0x06A1BBE6U, 0x4BFB6350U, + 0x1A6B1018U, 0x11CAEDFAU, 0x3D25BDD8U, 0xE2E1C3C9U, 0x44421659U, 0x0A121386U, 0xD90CEC6EU, 0xD5ABEA2AU, 0x64AF674EU, 0xDA86A85FU, + 0xBEBFE988U, 0x64E4C3FEU, 0x9DBC8057U, 0xF0F7C086U, 0x60787BF8U, 0x6003604DU, 0xD1FD8346U, 0xF6381FB0U, 0x7745AE04U, 0xD736FCCCU, + 0x83426B33U, 0xF01EAB71U, 0xB0804187U, 0x3C005E5FU, 0x77A057BEU, 0xBDE8AE24U, 0x55464299U, 0xBF582E61U, 0x4E58F48FU, 0xF2DDFDA2U, + 0xF474EF38U, 0x8789BDC2U, 0x5366F9C3U, 0xC8B38E74U, 0xB475F255U, 0x46FCD9B9U, 0x7AEB2661U, 0x8B1DDF84U, 0x846A0E79U, 0x915F95E2U, + 0x466E598EU, 0x20B45770U, 0x8CD55591U, 0xC902DE4CU, 0xB90BACE1U, 0xBB8205D0U, 0x11A86248U, 0x7574A99EU, 0xB77F19B6U, 0xE0A9DC09U, + 0x662D09A1U, 0xC4324633U, 0xE85A1F02U, 0x09F0BE8CU, 0x4A99A025U, 0x1D6EFE10U, 0x1AB93D1DU, 0x0BA5A4DFU, 0xA186F20FU, 0x2868F169U, + 0xDCB7DA83U, 0x573906FEU, 0xA1E2CE9BU, 0x4FCD7F52U, 0x50115E01U, 0xA70683FAU, 0xA002B5C4U, 0x0DE6D027U, 0x9AF88C27U, 0x773F8641U, + 0xC3604C06U, 0x61A806B5U, 0xF0177A28U, 0xC0F586E0U, 0x006058AAU, 0x30DC7D62U, 0x11E69ED7U, 0x2338EA63U, 0x53C2DD94U, 0xC2C21634U, + 0xBBCBEE56U, 0x90BCB6DEU, 0xEBFC7DA1U, 0xCE591D76U, 0x6F05E409U, 0x4B7C0188U, 0x39720A3DU, 0x7C927C24U, 0x86E3725FU, 0x724D9DB9U, + 0x1AC15BB4U, 0xD39EB8FCU, 0xED545578U, 0x08FCA5B5U, 0xD83D7CD3U, 0x4DAD0FC4U, 0x1E50EF5EU, 0xB161E6F8U, 0xA28514D9U, 0x6C51133CU, + 0x6FD5C7E7U, 0x56E14EC4U, 0x362ABFCEU, 0xDDC6C837U, 0xD79A3234U, 0x92638212U, 0x670EFA8EU, 0x406000E0U, 0x3A39CE37U, 0xD3FAF5CFU, + 0xABC27737U, 0x5AC52D1BU, 0x5CB0679EU, 0x4FA33742U, 0xD3822740U, 0x99BC9BBEU, 0xD5118E9DU, 0xBF0F7315U, 0xD62D1C7EU, 0xC700C47BU, + 0xB78C1B6BU, 0x21A19045U, 0xB26EB1BEU, 0x6A366EB4U, 0x5748AB2FU, 0xBC946E79U, 0xC6A376D2U, 0x6549C2C8U, 0x530FF8EEU, 0x468DDE7DU, + 0xD5730A1DU, 0x4CD04DC6U, 0x2939BBDBU, 0xA9BA4650U, 0xAC9526E8U, 0xBE5EE304U, 0xA1FAD5F0U, 0x6A2D519AU, 0x63EF8CE2U, 0x9A86EE22U, + 0xC089C2B8U, 0x43242EF6U, 0xA51E03AAU, 0x9CF2D0A4U, 0x83C061BAU, 0x9BE96A4DU, 0x8FE51550U, 0xBA645BD6U, 0x2826A2F9U, 0xA73A3AE1U, + 0x4BA99586U, 0xEF5562E9U, 0xC72FEFD3U, 0xF752F7DAU, 0x3F046F69U, 0x77FA0A59U, 0x80E4A915U, 0x87B08601U, 0x9B09E6ADU, 0x3B3EE593U, + 0xE990FD5AU, 0x9E34D797U, 0x2CF0B7D9U, 0x022B8B51U, 0x96D5AC3AU, 0x017DA67DU, 0xD1CF3ED6U, 0x7C7D2D28U, 0x1F9F25CFU, 0xADF2B89BU, + 0x5AD6B472U, 0x5A88F54CU, 0xE029AC71U, 0xE019A5E6U, 0x47B0ACFDU, 0xED93FA9BU, 0xE8D3C48DU, 0x283B57CCU, 0xF8D56629U, 0x79132E28U, + 0x785F0191U, 0xED756055U, 0xF7960E44U, 0xE3D35E8CU, 0x15056DD4U, 0x88F46DBAU, 0x03A16125U, 0x0564F0BDU, 0xC3EB9E15U, 0x3C9057A2U, + 0x97271AECU, 0xA93A072AU, 0x1B3F6D9BU, 0x1E6321F5U, 0xF59C66FBU, 0x26DCF319U, 0x7533D928U, 0xB155FDF5U, 0x03563482U, 0x8ABA3CBBU, + 0x28517711U, 0xC20AD9F8U, 0xABCC5167U, 0xCCAD925FU, 0x4DE81751U, 0x3830DC8EU, 0x379D5862U, 0x9320F991U, 0xEA7A90C2U, 0xFB3E7BCEU, + 0x5121CE64U, 0x774FBE32U, 0xA8B6E37EU, 0xC3293D46U, 0x48DE5369U, 0x6413E680U, 0xA2AE0810U, 0xDD6DB224U, 0x69852DFDU, 0x09072166U, + 0xB39A460AU, 0x6445C0DDU, 0x586CDECFU, 0x1C20C8AEU, 0x5BBEF7DDU, 0x1B588D40U, 0xCCD2017FU, 0x6BB4E3BBU, 0xDDA26A7EU, 0x3A59FF45U, + 0x3E350A44U, 0xBCB4CDD5U, 0x72EACEA8U, 0xFA6484BBU, 0x8D6612AEU, 0xBF3C6F47U, 0xD29BE463U, 0x542F5D9EU, 0xAEC2771BU, 0xF64E6370U, + 0x740E0D8DU, 0xE75B1357U, 0xF8721671U, 0xAF537D5DU, 0x4040CB08U, 0x4EB4E2CCU, 0x34D2466AU, 0x0115AF84U, 0xE1B00428U, 0x95983A1DU, + 0x06B89FB4U, 0xCE6EA048U, 0x6F3F3B82U, 0x3520AB82U, 0x011A1D4BU, 0x277227F8U, 0x611560B1U, 0xE7933FDCU, 0xBB3A792BU, 0x344525BDU, + 0xA08839E1U, 0x51CE794BU, 0x2F32C9B7U, 0xA01FBAC9U, 0xE01CC87EU, 0xBCC7D1F6U, 0xCF0111C3U, 0xA1E8AAC7U, 0x1A908749U, 0xD44FBD9AU, + 0xD0DADECBU, 0xD50ADA38U, 0x0339C32AU, 0xC6913667U, 0x8DF9317CU, 0xE0B12B4FU, 0xF79E59B7U, 0x43F5BB3AU, 0xF2D519FFU, 0x27D9459CU, + 0xBF97222CU, 0x15E6FC2AU, 0x0F91FC71U, 0x9B941525U, 0xFAE59361U, 0xCEB69CEBU, 0xC2A86459U, 0x12BAA8D1U, 0xB6C1075EU, 0xE3056A0CU, + 0x10D25065U, 0xCB03A442U, 0xE0EC6E0EU, 0x1698DB3BU, 0x4C98A0BEU, 0x3278E964U, 0x9F1F9532U, 0xE0D392DFU, 0xD3A0342BU, 0x8971F21EU, + 0x1B0A7441U, 0x4BA3348CU, 0xC5BE7120U, 0xC37632D8U, 0xDF359F8DU, 0x9B992F2EU, 0xE60B6F47U, 0x0FE3F11DU, 0xE54CDA54U, 0x1EDAD891U, + 0xCE6279CFU, 0xCD3E7E6FU, 0x1618B166U, 0xFD2C1D05U, 0x848FD2C5U, 0xF6FB2299U, 0xF523F357U, 0xA6327623U, 0x93A83531U, 0x56CCCD02U, + 0xACF08162U, 0x5A75EBB5U, 0x6E163697U, 0x88D273CCU, 0xDE966292U, 0x81B949D0U, 0x4C50901BU, 0x71C65614U, 0xE6C6C7BDU, 0x327A140AU, + 0x45E1D006U, 0xC3F27B9AU, 0xC9AA53FDU, 0x62A80F00U, 0xBB25BFE2U, 0x35BDD2F6U, 0x71126905U, 0xB2040222U, 0xB6CBCF7CU, 0xCD769C2BU, + 0x53113EC0U, 0x1640E3D3U, 0x38ABBD60U, 0x2547ADF0U, 0xBA38209CU, 0xF746CE76U, 0x77AFA1C5U, 0x20756060U, 0x85CBFE4EU, 0x8AE88DD8U, + 0x7AAAF9B0U, 0x4CF9AA7EU, 0x1948C25CU, 0x02FB8A8CU, 0x01C36AE4U, 0xD6EBE1F9U, 0x90D4F869U, 0xA65CDEA0U, 0x3F09252DU, 0xC208E69FU, + 0xB74E6132U, 0xCE77E25BU, 0x578FDFE3U, 0x3AC372E6U + } + }; - var t = key.S[0 + ((r >> 24) & 0xFFU)]; - t += key.S[256 + ((r >> 16) & 0xFFU)]; - t ^= key.S[512 + ((r >> 8) & 0xFFU)]; - t += key.S[768 + (r & 0xFFU)]; + private const int BfRounds = 4; + #endregion - ll ^= t; - } + private static void Enc(ref uint ll, uint r, BlowfishData key, int pi) + { + ll ^= key.P[pi]; - public static void Encrypt(uint[] data, int offset, BlowfishData key) - { - var l = data[offset]; - var r = data[offset + 1]; + var t = key.S[0 + ((r >> 24) & 0xFFU)]; + t += key.S[256 + ((r >> 16) & 0xFFU)]; + t ^= key.S[512 + ((r >> 8) & 0xFFU)]; + t += key.S[768 + (r & 0xFFU)]; - l ^= key.P[0]; + ll ^= t; + } - Enc(ref r, l, key, 1); - Enc(ref l, r, key, 2); - Enc(ref r, l, key, 3); - Enc(ref l, r, key, 4); + public static void Encrypt(uint[] data, int offset, BlowfishData key) + { + var l = data[offset]; + var r = data[offset + 1]; - r ^= key.P[BfRounds + 1]; + l ^= key.P[0]; - data[offset + 1] = l & 0xFFFFFFFFU; - data[offset] = r & 0xFFFFFFFFU; - } + Enc(ref r, l, key, 1); + Enc(ref l, r, key, 2); + Enc(ref r, l, key, 3); + Enc(ref l, r, key, 4); - public static void Decrypt(uint[] data, int offset, BlowfishData key) - { - var l = data[offset]; - var r = data[offset + 1]; + r ^= key.P[BfRounds + 1]; - l ^= key.P[BfRounds + 1]; + data[offset + 1] = l & 0xFFFFFFFFU; + data[offset] = r & 0xFFFFFFFFU; + } - Enc(ref r, l, key, 4); - Enc(ref l, r, key, 3); - Enc(ref r, l, key, 2); - Enc(ref l, r, key, 1); + public static void Decrypt(uint[] data, int offset, BlowfishData key) + { + var l = data[offset]; + var r = data[offset + 1]; - r ^= key.P[0]; + l ^= key.P[BfRounds + 1]; - data[offset + 1] = l & 0xFFFFFFFFU; - data[offset] = r & 0xFFFFFFFFU; - } + Enc(ref r, l, key, 4); + Enc(ref l, r, key, 3); + Enc(ref r, l, key, 2); + Enc(ref l, r, key, 1); - public static void SetKey(byte[] data, BlowfishData key) - { - byte d = 0; - const byte end = 8; + r ^= key.P[0]; - uint[] im = { 0U, 0U }; + data[offset + 1] = l & 0xFFFFFFFFU; + data[offset] = r & 0xFFFFFFFFU; + } - Array.Copy(BfInit.P, key.P, BfInit.P.Length); - Array.Copy(BfInit.S, key.S, BfInit.S.Length); + public static void SetKey(byte[] data, BlowfishData key) + { + byte d = 0; + const byte end = 8; - for (var i = 0; i < 6; ++i) - { - uint ri = data[d++]; + uint[] im = { 0U, 0U }; - if (d >= end) - d = 0; + Array.Copy(BfInit.P, key.P, BfInit.P.Length); + Array.Copy(BfInit.S, key.S, BfInit.S.Length); - ri <<= 8; - ri |= data[d++]; + for (var i = 0; i < 6; ++i) + { + uint ri = data[d++]; - if (d >= end) - d = 0; + if (d >= end) + d = 0; - ri <<= 8; - ri |= data[d++]; + ri <<= 8; + ri |= data[d++]; - if (d >= end) - d = 0; + if (d >= end) + d = 0; - ri <<= 8; - ri |= data[d++]; + ri <<= 8; + ri |= data[d++]; - if (d >= end) - d = 0; + if (d >= end) + d = 0; - key.P[i] ^= ri; - } + ri <<= 8; + ri |= data[d++]; - im[0] = 0; - im[1] = 0; + if (d >= end) + d = 0; - for (var ii = 0; ii < 6; ii += 2) - { - Encrypt(im, 0, key); + key.P[i] ^= ri; + } - key.P[ii] = im[0]; - key.P[ii + 1] = im[1]; - } + im[0] = 0; + im[1] = 0; - for (var k = 0; k < 1024; k += 2) - { - Encrypt(im, 0, key); + for (var ii = 0; ii < 6; ii += 2) + { + Encrypt(im, 0, key); + + key.P[ii] = im[0]; + key.P[ii + 1] = im[1]; + } + + for (var k = 0; k < 1024; k += 2) + { + Encrypt(im, 0, key); - key.S[k] = im[0]; - key.S[k + 1] = im[1]; - } + key.S[k] = im[0]; + key.S[k + 1] = im[1]; } } } diff --git a/src/Rasa.Utils/Cryptography/GameCryptManager.cs b/src/Rasa.Utils/Cryptography/GameCryptManager.cs index c850051f..a3407143 100644 --- a/src/Rasa.Utils/Cryptography/GameCryptManager.cs +++ b/src/Rasa.Utils/Cryptography/GameCryptManager.cs @@ -1,110 +1,106 @@ -using System; -using System.Security.Cryptography; +using System.Security.Cryptography; -namespace Rasa.Cryptography -{ - using Game; - - public static class GameCryptManager - { - public static void Initialize(ClientCryptData cryptData, byte[] inputK) - { - Blowfish.SetKey(inputK, cryptData.Key); +namespace Rasa.Cryptography; - using (var md5 = MD5.Create()) - Array.Copy(md5.ComputeHash(inputK), cryptData.MD5, 0x10); +using Rasa.Cryptography.Game; - Array.Copy(inputK, cryptData.K, 0x40); - } +public static class GameCryptManager +{ + public static void Initialize(ClientCryptData cryptData, byte[] inputK) + { + Blowfish.SetKey(inputK, cryptData.Key); - public static void Encrypt(byte[] data, int offset, ref int length, int maxLength, ClientCryptData cryptData) - { - var oldLen = length; + Array.Copy(MD5.HashData(inputK), cryptData.MD5, 0x10); + Array.Copy(inputK, cryptData.K, 0x40); + } - // Make the length a multiple of 8 - var rem = length % 8; - if (rem != 0) - length += 8 - rem; + public static void Encrypt(byte[] data, int offset, ref int length, int maxLength, ClientCryptData cryptData) + { + var oldLen = length; - if (length > maxLength) - throw new ArgumentOutOfRangeException(nameof(length), "The length can't exceed the maximal buffer length!"); + // Make the length a multiple of 8 + var rem = length % 8; + if (rem != 0) + length += 8 - rem; - // Fill up extra padding bytes - for (var i = oldLen; i < length; ++i) - data[offset + i] = 0xCC; + if (length > maxLength) + throw new ArgumentOutOfRangeException(nameof(length), "The length can't exceed the maximal buffer length!"); - var uintData = new uint[length / 4]; - Buffer.BlockCopy(data, offset, uintData, 0, length); + // Fill up extra padding bytes + for (var i = oldLen; i < length; ++i) + data[offset + i] = 0xCC; - var x = SwitchEndianInt(BitConverter.ToUInt32(cryptData.MD5, 0)); - var y = SwitchEndianInt(BitConverter.ToUInt32(cryptData.MD5, 4)); + var uintData = new uint[length / 4]; + Buffer.BlockCopy(data, offset, uintData, 0, length); - for (var i = 0; i < (length / 8); ++i) - { - var a2 = i * 2; + var x = SwitchEndianInt(BitConverter.ToUInt32(cryptData.MD5, 0)); + var y = SwitchEndianInt(BitConverter.ToUInt32(cryptData.MD5, 4)); - uintData[a2] = SwitchEndianInt(uintData[a2]); - uintData[a2 + 1] = SwitchEndianInt(uintData[a2 + 1]); - uintData[a2] ^= x; - uintData[a2 + 1] ^= y; + for (var i = 0; i < (length / 8); ++i) + { + var a2 = i * 2; - Blowfish.Encrypt(uintData, a2, cryptData.Key); + uintData[a2] = SwitchEndianInt(uintData[a2]); + uintData[a2 + 1] = SwitchEndianInt(uintData[a2 + 1]); + uintData[a2] ^= x; + uintData[a2 + 1] ^= y; - x = uintData[a2]; - y = uintData[a2 + 1]; + Blowfish.Encrypt(uintData, a2, cryptData.Key); - uintData[a2] = SwitchEndianInt(uintData[a2]); - uintData[a2 + 1] = SwitchEndianInt(uintData[a2 + 1]); - } + x = uintData[a2]; + y = uintData[a2 + 1]; - Buffer.BlockCopy(uintData, 0, data, offset, length); + uintData[a2] = SwitchEndianInt(uintData[a2]); + uintData[a2 + 1] = SwitchEndianInt(uintData[a2 + 1]); } - public static bool Decrypt(byte[] data, int offset, int length, ClientCryptData cryptData) - { - if (length % 8 != 0) - throw new ArgumentOutOfRangeException(nameof(length), "The lenght must be a multiple of 8!"); - - var uintData = new uint[length / 4]; - Buffer.BlockCopy(data, offset, uintData, 0, length); + Buffer.BlockCopy(uintData, 0, data, offset, length); + } - var x = SwitchEndianInt(BitConverter.ToUInt32(cryptData.MD5, 0)); - var y = SwitchEndianInt(BitConverter.ToUInt32(cryptData.MD5, 4)); + public static bool Decrypt(byte[] data, int offset, int length, ClientCryptData cryptData) + { + if (length % 8 != 0) + throw new ArgumentOutOfRangeException(nameof(length), "The lenght must be a multiple of 8!"); - for (var i = 0; i < (length / 8); ++i) - { - //Switch endian first - var a2 = i * 2; + var uintData = new uint[length / 4]; + Buffer.BlockCopy(data, offset, uintData, 0, length); - uintData[a2] = SwitchEndianInt(uintData[a2]); - uintData[a2 + 1] = SwitchEndianInt(uintData[a2 + 1]); + var x = SwitchEndianInt(BitConverter.ToUInt32(cryptData.MD5, 0)); + var y = SwitchEndianInt(BitConverter.ToUInt32(cryptData.MD5, 4)); - //Store new XOR - var x2 = uintData[a2]; - var y2 = uintData[a2 + 1]; + for (var i = 0; i < (length / 8); ++i) + { + //Switch endian first + var a2 = i * 2; - Blowfish.Decrypt(uintData, a2, cryptData.Key); + uintData[a2] = SwitchEndianInt(uintData[a2]); + uintData[a2 + 1] = SwitchEndianInt(uintData[a2 + 1]); - uintData[a2] ^= x; - uintData[a2 + 1] ^= y; + //Store new XOR + var x2 = uintData[a2]; + var y2 = uintData[a2 + 1]; - //Update XOR - x = x2; - y = y2; + Blowfish.Decrypt(uintData, a2, cryptData.Key); - //Switch endian now - uintData[a2] = SwitchEndianInt(uintData[a2]); - uintData[a2 + 1] = SwitchEndianInt(uintData[a2 + 1]); - } + uintData[a2] ^= x; + uintData[a2 + 1] ^= y; - Buffer.BlockCopy(uintData, 0, data, offset, length); + //Update XOR + x = x2; + y = y2; - return true; + //Switch endian now + uintData[a2] = SwitchEndianInt(uintData[a2]); + uintData[a2 + 1] = SwitchEndianInt(uintData[a2 + 1]); } - private static uint SwitchEndianInt(uint value) - { - return ((value & 0x000000FFU) << 24) | ((value & 0x0000FF00U) << 8) | ((value & 0x00FF0000U) >> 8) | ((value & 0xFF000000U) >> 24); - } + Buffer.BlockCopy(uintData, 0, data, offset, length); + + return true; + } + + private static uint SwitchEndianInt(uint value) + { + return ((value & 0x000000FFU) << 24) | ((value & 0x0000FF00U) << 8) | ((value & 0x00FF0000U) >> 8) | ((value & 0xFF000000U) >> 24); } } diff --git a/src/Rasa.Utils/Cryptography/ICryptoManager.cs b/src/Rasa.Utils/Cryptography/ICryptoManager.cs index e651577c..e18dc657 100644 --- a/src/Rasa.Utils/Cryptography/ICryptoManager.cs +++ b/src/Rasa.Utils/Cryptography/ICryptoManager.cs @@ -1,10 +1,7 @@ -namespace Rasa.Cryptography -{ - using Game; +namespace Rasa.Cryptography; - public interface ICryptoManager - { - void Encrypt(byte[] data, int offset, ref int length, int maxLength, ClientCryptData cryptData = null); - bool Decrypt(byte[] data, int offset, int length, ClientCryptData cryptData = null); - } +public interface ICryptoManager +{ + void Encrypt(byte[] data, int offset, ref int length, int maxLength, ClientCryptData? cryptData = null); + bool Decrypt(byte[] data, int offset, int length, ClientCryptData? cryptData = null); } diff --git a/src/Rasa.Utils/Extensions/BinaryReaderExtensions.cs b/src/Rasa.Utils/Extensions/BinaryReaderExtensions.cs index 70b8483a..496572d6 100644 --- a/src/Rasa.Utils/Extensions/BinaryReaderExtensions.cs +++ b/src/Rasa.Utils/Extensions/BinaryReaderExtensions.cs @@ -1,26 +1,23 @@ -using System; -using System.IO; -using System.Text; +using System.IO; -namespace Rasa.Extensions +namespace Rasa.Extensions; + +public static class BinaryReaderExtensions { - public static class BinaryReaderExtensions + public static string ReadLengthedString(this BinaryReader reader) { - public static string ReadLengthedString(this BinaryReader reader) - { - var len = reader.ReadInt32(); - return len == 0 ? "" : Encoding.UTF8.GetString(reader.ReadBytes(len)); - } + var len = reader.ReadInt32(); + return len == 0 ? string.Empty : Encoding.UTF8.GetString(reader.ReadBytes(len)); + } - public static string ReadUtf8StringOn(this BinaryReader reader, int length) - { - var bytes = reader.ReadBytes(length); + public static string ReadUtf8StringOn(this BinaryReader reader, int length) + { + var bytes = reader.ReadBytes(length); - var index = Array.IndexOf(bytes, 0); - if (index == -1) - index = bytes.Length; + var index = Array.IndexOf(bytes, 0); + if (index == -1) + index = bytes.Length; - return index == 0 ? "" : Encoding.UTF8.GetString(bytes, 0, index); - } + return index == 0 ? string.Empty : Encoding.UTF8.GetString(bytes, 0, index); } } diff --git a/src/Rasa.Utils/Extensions/BinaryWriterExtensions.cs b/src/Rasa.Utils/Extensions/BinaryWriterExtensions.cs index 423d290b..21853f48 100644 --- a/src/Rasa.Utils/Extensions/BinaryWriterExtensions.cs +++ b/src/Rasa.Utils/Extensions/BinaryWriterExtensions.cs @@ -1,149 +1,147 @@ using System.IO; -using System.Text; -namespace Rasa.Extensions +namespace Rasa.Extensions; + +public static class BinaryWriterExtensions { - public static class BinaryWriterExtensions + public static void WriteLengthedString(this BinaryWriter writer, string text) { - public static void WriteLengthedString(this BinaryWriter writer, string text) + if (string.IsNullOrEmpty(text)) { - if (string.IsNullOrEmpty(text)) - { - writer.Write(0); - return; - } - - writer.Write(text.Length); - writer.WriteUtf8StringOn(text); + writer.Write(0); + return; } - public static void WriteUtf8String(this BinaryWriter writer, string text) - { - writer.WriteUtf8StringOn(text); - } + writer.Write(text.Length); + writer.WriteUtf8StringOn(text); + } - public static void WriteUtf8StringOn(this BinaryWriter writer, string text, int length = -1) - { - if (length == -1) - length = text.Length; + public static void WriteUtf8String(this BinaryWriter writer, string text) + { + writer.WriteUtf8StringOn(text); + } - writer.Write(Encoding.UTF8.GetBytes(text)); + public static void WriteUtf8StringOn(this BinaryWriter writer, string text, int length = -1) + { + if (length == -1) + length = text.Length; - if (length <= text.Length) - return; + writer.Write(Encoding.UTF8.GetBytes(text)); - for (var i = 0; i < length - text.Length; ++i) - writer.Write((byte) 0); - } + if (length <= text.Length) + return; - public static void WriteAt(this BinaryWriter writer, byte value, long position) - { - var currentPosition = writer.BaseStream.Position; + for (var i = 0; i < length - text.Length; ++i) + writer.Write((byte) 0); + } - writer.BaseStream.Position = position; + public static void WriteAt(this BinaryWriter writer, byte value, long position) + { + var currentPosition = writer.BaseStream.Position; - writer.Write(value); + writer.BaseStream.Position = position; - writer.BaseStream.Position = currentPosition; - } + writer.Write(value); - public static void WriteAt(this BinaryWriter writer, sbyte value, long position) - { - var currentPosition = writer.BaseStream.Position; + writer.BaseStream.Position = currentPosition; + } - writer.BaseStream.Position = position; + public static void WriteAt(this BinaryWriter writer, sbyte value, long position) + { + var currentPosition = writer.BaseStream.Position; - writer.Write(value); + writer.BaseStream.Position = position; - writer.BaseStream.Position = currentPosition; - } + writer.Write(value); - public static void WriteAt(this BinaryWriter writer, short value, long position) - { - var currentPosition = writer.BaseStream.Position; + writer.BaseStream.Position = currentPosition; + } - writer.BaseStream.Position = position; + public static void WriteAt(this BinaryWriter writer, short value, long position) + { + var currentPosition = writer.BaseStream.Position; - writer.Write(value); + writer.BaseStream.Position = position; - writer.BaseStream.Position = currentPosition; - } + writer.Write(value); - public static void WriteAt(this BinaryWriter writer, ushort value, long position) - { - var currentPosition = writer.BaseStream.Position; + writer.BaseStream.Position = currentPosition; + } - writer.BaseStream.Position = position; + public static void WriteAt(this BinaryWriter writer, ushort value, long position) + { + var currentPosition = writer.BaseStream.Position; - writer.Write(value); + writer.BaseStream.Position = position; - writer.BaseStream.Position = currentPosition; - } + writer.Write(value); - public static void WriteAt(this BinaryWriter writer, int value, long position) - { - var currentPosition = writer.BaseStream.Position; + writer.BaseStream.Position = currentPosition; + } - writer.BaseStream.Position = position; + public static void WriteAt(this BinaryWriter writer, int value, long position) + { + var currentPosition = writer.BaseStream.Position; - writer.Write(value); + writer.BaseStream.Position = position; - writer.BaseStream.Position = currentPosition; - } + writer.Write(value); - public static void WriteAt(this BinaryWriter writer, uint value, long position) - { - var currentPosition = writer.BaseStream.Position; + writer.BaseStream.Position = currentPosition; + } - writer.BaseStream.Position = position; + public static void WriteAt(this BinaryWriter writer, uint value, long position) + { + var currentPosition = writer.BaseStream.Position; - writer.Write(value); + writer.BaseStream.Position = position; - writer.BaseStream.Position = currentPosition; - } + writer.Write(value); - public static void WriteAt(this BinaryWriter writer, long value, long position) - { - var currentPosition = writer.BaseStream.Position; + writer.BaseStream.Position = currentPosition; + } - writer.BaseStream.Position = position; + public static void WriteAt(this BinaryWriter writer, long value, long position) + { + var currentPosition = writer.BaseStream.Position; - writer.Write(value); + writer.BaseStream.Position = position; - writer.BaseStream.Position = currentPosition; - } + writer.Write(value); - public static void WriteAt(this BinaryWriter writer, ulong value, long position) - { - var currentPosition = writer.BaseStream.Position; + writer.BaseStream.Position = currentPosition; + } - writer.BaseStream.Position = position; + public static void WriteAt(this BinaryWriter writer, ulong value, long position) + { + var currentPosition = writer.BaseStream.Position; - writer.Write(value); + writer.BaseStream.Position = position; - writer.BaseStream.Position = currentPosition; - } + writer.Write(value); - public static void WriteAt(this BinaryWriter writer, float value, long position) - { - var currentPosition = writer.BaseStream.Position; + writer.BaseStream.Position = currentPosition; + } + + public static void WriteAt(this BinaryWriter writer, float value, long position) + { + var currentPosition = writer.BaseStream.Position; - writer.BaseStream.Position = position; + writer.BaseStream.Position = position; - writer.Write(value); + writer.Write(value); - writer.BaseStream.Position = currentPosition; - } + writer.BaseStream.Position = currentPosition; + } - public static void WriteAt(this BinaryWriter writer, double value, long position) - { - var currentPosition = writer.BaseStream.Position; + public static void WriteAt(this BinaryWriter writer, double value, long position) + { + var currentPosition = writer.BaseStream.Position; - writer.BaseStream.Position = position; + writer.BaseStream.Position = position; - writer.Write(value); + writer.Write(value); - writer.BaseStream.Position = currentPosition; - } + writer.BaseStream.Position = currentPosition; } } diff --git a/src/Rasa.Utils/Extensions/RandomExtensions.cs b/src/Rasa.Utils/Extensions/RandomExtensions.cs index 070b87f3..2f1f3f03 100644 --- a/src/Rasa.Utils/Extensions/RandomExtensions.cs +++ b/src/Rasa.Utils/Extensions/RandomExtensions.cs @@ -1,12 +1,9 @@ -using System; +namespace Rasa.Extensions; -namespace Rasa.Extensions +public static class RandomExtensions { - public static class RandomExtensions + public static uint NextUInt(this Random rand) { - public static uint NextUInt(this Random rand) - { - return (uint) rand.Next(); - } + return (uint) rand.Next(); } } diff --git a/src/Rasa.Utils/Extensions/SocketAsyncEventArgsExtensions.cs b/src/Rasa.Utils/Extensions/SocketAsyncEventArgsExtensions.cs index d6d99bf8..779c585d 100644 --- a/src/Rasa.Utils/Extensions/SocketAsyncEventArgsExtensions.cs +++ b/src/Rasa.Utils/Extensions/SocketAsyncEventArgsExtensions.cs @@ -1,12 +1,11 @@ using System.Net.Sockets; -namespace Rasa.Extensions +namespace Rasa.Extensions; + +public static class SocketAsyncEventArgsExtensions { - public static class SocketAsyncEventArgsExtensions + public static T? GetUserToken(this SocketAsyncEventArgs args) where T : class { - public static T GetUserToken(this SocketAsyncEventArgs args) where T : class - { - return args.UserToken as T; - } + return args.UserToken as T; } } diff --git a/src/Rasa.Utils/GlobalUsings.cs b/src/Rasa.Utils/GlobalUsings.cs new file mode 100644 index 00000000..e6a8e0f2 --- /dev/null +++ b/src/Rasa.Utils/GlobalUsings.cs @@ -0,0 +1,4 @@ +global using System; +global using System.Collections.Generic; +global using System.Linq; +global using System.Text; diff --git a/src/Rasa.Utils/Hosting/IRasaServer.cs b/src/Rasa.Utils/Hosting/IRasaServer.cs index 1e149caa..5d9a8dce 100644 --- a/src/Rasa.Utils/Hosting/IRasaServer.cs +++ b/src/Rasa.Utils/Hosting/IRasaServer.cs @@ -1,11 +1,10 @@ -namespace Rasa.Hosting +namespace Rasa.Hosting; + +public interface IRasaServer { - public interface IRasaServer - { - string ServerType { get; } + string ServerType { get; } - bool Start(); + bool Start(); - bool Running { get; } - } + bool Running { get; } } \ No newline at end of file diff --git a/src/Rasa.Utils/Hosting/RasaHost.cs b/src/Rasa.Utils/Hosting/RasaHost.cs index a42098a3..c681af10 100644 --- a/src/Rasa.Utils/Hosting/RasaHost.cs +++ b/src/Rasa.Utils/Hosting/RasaHost.cs @@ -1,72 +1,69 @@ -using System; -using System.Threading; +using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.Hosting; -namespace Rasa.Hosting +namespace Rasa.Hosting; + +using Commands; + +public class RasaHost : BackgroundService { - using Commands; + private readonly IRasaServer _rasaServer; - public class RasaHost : BackgroundService + public RasaHost(IRasaServer rasaServer) { - private readonly IRasaServer _rasaServer; + _rasaServer = rasaServer; + } - public RasaHost(IRasaServer rasaServer) - { - _rasaServer = rasaServer; - } + protected override async Task ExecuteAsync(CancellationToken stoppingToken) + { + Logger.WriteLog(LogType.File, "Application startup!"); - protected override async Task ExecuteAsync(CancellationToken stoppingToken) - { - Logger.WriteLog(LogType.File, "Application startup!"); + InitConsole(_rasaServer.ServerType); - InitConsole(_rasaServer.ServerType); + Logger.WriteLog(LogType.Initialize, "*** Initialized {0} Server...", _rasaServer.ServerType); - Logger.WriteLog(LogType.Initialize, "*** Initialized {0} Server...", _rasaServer.ServerType); + if (!_rasaServer.Start()) + { + Logger.WriteLog(LogType.Error, "Unable to start server!"); + return; + } - if (!_rasaServer.Start()) - { - Logger.WriteLog(LogType.Error, "Unable to start server!"); - return; - } + await ProcessCommandsSafe(stoppingToken); + } - await ProcessCommandsSafe(stoppingToken); + private async Task ProcessCommandsSafe(CancellationToken stoppingToken) + { + try + { + await ProcessCommands(stoppingToken); } - - private async Task ProcessCommandsSafe(CancellationToken stoppingToken) + catch (OperationCanceledException) { - try - { - await ProcessCommands(stoppingToken); - } - catch (OperationCanceledException) - { - // cancellationToken was fired - } + // cancellationToken was fired } + } - private async Task ProcessCommands(CancellationToken stoppingToken) + private async Task ProcessCommands(CancellationToken stoppingToken) + { + while (_rasaServer.Running && !stoppingToken.IsCancellationRequested) { - - while (_rasaServer.Running && !stoppingToken.IsCancellationRequested) - { - CommandProcessor.ProcessCommand(stoppingToken); - await Task.Delay(25, stoppingToken); - } + CommandProcessor.ProcessCommand(stoppingToken); + await Task.Delay(25, stoppingToken); } + } - private void InitConsole(string type) - { - Console.Title = $"Rasa.NET - {type} Server"; + private static void InitConsole(string type) + { + Console.Title = $"Rasa.NET - {type} Server"; - Logger.WriteLog(LogType.Initialize, @" _____ _ _ ______ _______ "); - Logger.WriteLog(LogType.Initialize, @" | __ \ | \ | | ____|__ __|"); - Logger.WriteLog(LogType.Initialize, @" | |__) |__ _ ___ __ _ | \| | |__ | | "); - Logger.WriteLog(LogType.Initialize, @" | _ // _` / __|/ _` | | . ` | __| | | "); - Logger.WriteLog(LogType.Initialize, @" | | \ \ (_| \__ \ (_| |_| |\ | |____ | | "); - Logger.WriteLog(LogType.Initialize, @" |_| \_\__,_|___/\__,_(_)_| \_|______| |_| "); - Logger.WriteLog(LogType.Initialize, $@" Tabula Rasa server - Rasa.NET - {type}"); - Logger.WriteLog(LogType.Initialize, ""); - } + Logger.WriteLog(LogType.Initialize, @" _____ _ _ ______ _______ "); + Logger.WriteLog(LogType.Initialize, @" | __ \ | \ | | ____|__ __|"); + Logger.WriteLog(LogType.Initialize, @" | |__) |__ _ ___ __ _ | \| | |__ | | "); + Logger.WriteLog(LogType.Initialize, @" | _ // _` / __|/ _` | | . ` | __| | | "); + Logger.WriteLog(LogType.Initialize, @" | | \ \ (_| \__ \ (_| |_| |\ | |____ | | "); + Logger.WriteLog(LogType.Initialize, @" |_| \_\__,_|___/\__,_(_)_| \_|______| |_| "); + Logger.WriteLog(LogType.Initialize, $@" Tabula Rasa server - Rasa.NET - {type}"); + Logger.WriteLog(LogType.Initialize, ""); } } \ No newline at end of file diff --git a/src/Rasa.Utils/Initialization/IInitializable.cs b/src/Rasa.Utils/Initialization/IInitializable.cs index 43f0e38b..4d0856d4 100644 --- a/src/Rasa.Utils/Initialization/IInitializable.cs +++ b/src/Rasa.Utils/Initialization/IInitializable.cs @@ -1,7 +1,6 @@ -namespace Rasa.Initialization +namespace Rasa.Initialization; + +public interface IInitializable { - public interface IInitializable - { - void Initialize(); - } + void Initialize(); } \ No newline at end of file diff --git a/src/Rasa.Utils/Initialization/IInitializer.cs b/src/Rasa.Utils/Initialization/IInitializer.cs index 4a4f7f16..82bc6c05 100644 --- a/src/Rasa.Utils/Initialization/IInitializer.cs +++ b/src/Rasa.Utils/Initialization/IInitializer.cs @@ -1,7 +1,6 @@ -namespace Rasa.Initialization +namespace Rasa.Initialization; + +public interface IInitializer { - public interface IInitializer - { - void Execute(); - } + void Execute(); } \ No newline at end of file diff --git a/src/Rasa.Utils/Initialization/Initializer.cs b/src/Rasa.Utils/Initialization/Initializer.cs index 106d5550..5591f4e4 100644 --- a/src/Rasa.Utils/Initialization/Initializer.cs +++ b/src/Rasa.Utils/Initialization/Initializer.cs @@ -1,22 +1,17 @@ -using System.Collections.Generic; +namespace Rasa.Initialization; -namespace Rasa.Initialization +public class Initializer : IInitializer { - public class Initializer : IInitializer - { - private readonly IEnumerable _initializables; + private readonly IEnumerable _initializables; - public Initializer(IEnumerable initializables) - { - _initializables = initializables; - } + public Initializer(IEnumerable initializables) + { + _initializables = initializables; + } - public void Execute() - { - foreach (var initializable in _initializables) - { - initializable.Initialize(); - } - } + public void Execute() + { + foreach (var initializable in _initializables) + initializable.Initialize(); } } \ No newline at end of file diff --git a/src/Rasa.Utils/Logger.cs b/src/Rasa.Utils/Logger.cs index 0d50d40a..8daebce2 100644 --- a/src/Rasa.Utils/Logger.cs +++ b/src/Rasa.Utils/Logger.cs @@ -1,158 +1,149 @@ -using System; -using System.IO; +using System.IO; -namespace Rasa +namespace Rasa; + +public enum LogType { - public enum LogType - { - Debug, - AI, - Network, - Error, - Test, - Initialize, - Command, - File, - Security, - None, - ExportData, - Communicator - } + Debug, + AI, + Network, + Error, + Test, + Initialize, + Command, + File, + Security, + None, + ExportData, + Communicator +} - public class Logger - { - public static LoggerConfig Config { get; private set; } +public class Logger +{ + public static LoggerConfig? Config { get; private set; } - private static StreamWriter _logWriter; + private static StreamWriter? _logWriter; - public static void UpdateConfig(LoggerConfig config) - { - Config = config; + public static void UpdateConfig(LoggerConfig config) + { + Config = config; - if (Config.LogToFile && _logWriter == null && !string.IsNullOrWhiteSpace(Config.LogFilePath)) + if (Config.LogToFile && _logWriter == null && !string.IsNullOrWhiteSpace(Config.LogFilePath)) + { + _logWriter = new StreamWriter(new FileStream(Config.LogFilePath, FileMode.Append, FileAccess.Write, FileShare.Read)) { - _logWriter = new StreamWriter(new FileStream(Config.LogFilePath, FileMode.Append, FileAccess.Write, FileShare.Read)) - { - AutoFlush = true - }; + AutoFlush = true + }; - // Add a new line, if the file had content already - if (_logWriter.BaseStream.Position != 0) - _logWriter.WriteLine(); + // Add a new line, if the file had content already + if (_logWriter.BaseStream.Position != 0) + _logWriter.WriteLine(); - WriteLog(LogType.File, "Logging system startup!"); - } - else if (!Config.LogToFile) + WriteLog(LogType.File, "Logging system startup!"); + } + else if (!Config.LogToFile) + { + if (_logWriter != null) { - if (_logWriter != null) - { - WriteLog(LogType.File, "Logging system shutdown!"); + WriteLog(LogType.File, "Logging system shutdown!"); - _logWriter.Flush(); - _logWriter.Dispose(); - } - - _logWriter = null; + _logWriter.Flush(); + _logWriter.Dispose(); } - } - public static void WriteLog(LogType type, object log) - { - WriteLog(type, log?.ToString() ?? "null"); + _logWriter = null; } + } - public static void WriteLog(LogType type, string log) - { - string prefix; - ConsoleColor desiredColor; + public static void WriteLog(LogType type, string log) + { + string prefix; + ConsoleColor desiredColor; - switch (type) - { - case LogType.AI: - desiredColor = ConsoleColor.Yellow; - prefix = "AI"; - break; - - case LogType.Debug: - desiredColor = ConsoleColor.Magenta; - prefix = "Debug"; - break; - - case LogType.Network: - desiredColor = ConsoleColor.Green; - prefix = "Network"; - break; - - case LogType.Error: - desiredColor = ConsoleColor.Red; - prefix = "Error"; - break; - - case LogType.Test: - desiredColor = ConsoleColor.DarkGray; - prefix = "Test"; - break; - - case LogType.Initialize: - desiredColor = ConsoleColor.Blue; - prefix = "Init"; - break; - - case LogType.Command: - desiredColor = ConsoleColor.Cyan; - prefix = "Command"; - break; - - case LogType.None: - desiredColor = ConsoleColor.White; - prefix = ""; - break; - - case LogType.File: // Only logs to file, color doesn't matter - prefix = "FileLog"; - desiredColor = ConsoleColor.Black; - break; - - case LogType.Security: - prefix = "Security"; - desiredColor = ConsoleColor.DarkRed; - break; - - case LogType.Communicator: - prefix = "Communicator"; - desiredColor = ConsoleColor.DarkGreen; - break; - - default: - throw new ArgumentOutOfRangeException(nameof(type), type, $"Unhandled log type: {type}"); - } + switch (type) + { + case LogType.AI: + desiredColor = ConsoleColor.Yellow; + prefix = "AI"; + break; + + case LogType.Debug: + desiredColor = ConsoleColor.Magenta; + prefix = "Debug"; + break; + + case LogType.Network: + desiredColor = ConsoleColor.Green; + prefix = "Network"; + break; + + case LogType.Error: + desiredColor = ConsoleColor.Red; + prefix = "Error"; + break; + + case LogType.Test: + desiredColor = ConsoleColor.DarkGray; + prefix = "Test"; + break; + + case LogType.Initialize: + desiredColor = ConsoleColor.Blue; + prefix = "Init"; + break; + + case LogType.Command: + desiredColor = ConsoleColor.Cyan; + prefix = "Command"; + break; + + case LogType.None: + desiredColor = ConsoleColor.White; + prefix = ""; + break; + + case LogType.File: // Only logs to file, color doesn't matter + prefix = "FileLog"; + desiredColor = ConsoleColor.Black; + break; + + case LogType.Security: + prefix = "Security"; + desiredColor = ConsoleColor.DarkRed; + break; + + case LogType.Communicator: + prefix = "Communicator"; + desiredColor = ConsoleColor.DarkGreen; + break; + + default: + throw new ArgumentOutOfRangeException(nameof(type), type, $"Unhandled log type: {type}"); + } - var text = type == LogType.ExportData - ? $"{log}" - : $"[{DateTime.Now:yyyy. MM. dd. HH:mm:ss.fff}] [{prefix}] {log}"; + var text = type == LogType.ExportData + ? $"{log}" + : $"[{DateTime.Now:yyyy. MM. dd. HH:mm:ss.fff}] [{prefix}] {log}"; - _logWriter?.WriteLine(text); + _logWriter?.WriteLine(text); - if (type == LogType.File || (!Config.IsDebugMode && type == LogType.Debug)) - return; + if (type == LogType.File || (!Config?.IsDebugMode ?? true && type == LogType.Debug)) + return; - var color = Console.ForegroundColor; + var color = Console.ForegroundColor; - Console.ForegroundColor = desiredColor; - Console.WriteLine(text); - Console.ForegroundColor = color; - } + Console.ForegroundColor = desiredColor; + Console.WriteLine(text); + Console.ForegroundColor = color; + } - public static void WriteLog(LogType type, string format, params object[] args) - { - WriteLog(type, string.Format(format, args)); - } + public static void WriteLog(LogType type, object log) => WriteLog(type, log?.ToString() ?? "null"); + public static void WriteLog(LogType type, string format, params object[] args) => WriteLog(type, string.Format(format, args)); - public class LoggerConfig - { - public bool IsDebugMode { get; set; } - public string LogFilePath { get; set; } - public bool LogToFile { get; set; } - } + public class LoggerConfig + { + public bool IsDebugMode { get; set; } + public string? LogFilePath { get; set; } + public bool LogToFile { get; set; } } } diff --git a/src/Rasa.Utils/Memory/BufferData.cs b/src/Rasa.Utils/Memory/BufferData.cs deleted file mode 100644 index f47605f8..00000000 --- a/src/Rasa.Utils/Memory/BufferData.cs +++ /dev/null @@ -1,176 +0,0 @@ -using System; -using System.IO; -using System.Text; - -namespace Rasa.Memory -{ - public class BufferData - { - public byte[] Buffer => BufferManager.Buffer; - public int BaseOffset { get; set; } - public int RealBaseOffset { get; } - public int MaxLength => BufferManager.BlockSize - (BaseOffset - RealBaseOffset); - - public int Offset { get; set; } - public int Length { get; set; } - public int ByteCount { get; set; } - public int RemainingLength => Length - Offset; - - public bool Free { get; set; } = true; - - public string StrData => ByteData(); - - public BufferData(int baseOffset) - { - RealBaseOffset = baseOffset; - - Reset(); - } - - public byte this[int off] - { - get { return Buffer[BaseOffset + off]; } - set { Buffer[BaseOffset + off] = value; } - } - - public void Reset() - { - BaseOffset = RealBaseOffset; - Length = MaxLength; - Offset = ByteCount = 0; - - Clear(); - } - - public int Append(BufferData source) - { - var bytesAvailable = MaxLength - Length; - var bytesInSource = source.RemainingLength; - - var bytesToCopy = (bytesInSource > bytesAvailable) ? bytesAvailable : bytesInSource; - - if (bytesToCopy > 0) { - Array.Copy(source.Buffer, source.BaseOffset + source.Offset, this.Buffer, this.BaseOffset + this.Length, bytesToCopy); - source.Offset += bytesToCopy; - Length += bytesToCopy; - } - - return bytesToCopy; - } - - public int ShiftProcessedData() - { - if (Offset > 0) { - var pos = Offset; - var amountToMove = RemainingLength; - - Array.Copy(this.Buffer, this.BaseOffset + pos, this.Buffer, this.BaseOffset + 0, amountToMove); - - ByteCount -= pos; - Length -= pos; - Offset = 0; - - return pos; - } - - return 0; - } - - public void Clear() - { - Clear(0, MaxLength); - } - - public void Clear(int offset, int length) - { - CheckConstraints(offset, length); - - Array.Clear(Buffer, BaseOffset + offset, length); - } - - public static void Copy(BufferData source, int sourceOffset, BufferData dest, int destOffset, int length) - { - source.CheckConstraints(sourceOffset, length); - dest.CheckConstraints(destOffset, length); - - Array.Copy(source.Buffer, source.BaseOffset + sourceOffset, dest.Buffer, dest.BaseOffset + destOffset, length); - } - - public MemoryStream GetStream(bool writable) - { - return GetStream(Offset, RemainingLength, writable); - } - - public MemoryStream GetStream(int offset, int length, bool writable) - { - CheckConstraints(offset, length); - - return new MemoryStream(Buffer, BaseOffset + offset, length, writable); - } - - public BinaryReader GetReader() - { - return GetReader(Offset, RemainingLength, Encoding.UTF8, false); - } - - public BinaryReader GetReader(int offset, int length) - { - return GetReader(offset, length, Encoding.UTF8, false); - } - - public BinaryReader GetReader(int offset, int length, Encoding encoding, bool leaveOpen) - { - return new BinaryReader(GetStream(offset, length, false), encoding, leaveOpen); - } - - public BinaryWriter CreateWriter() - { - return CreateWriter(Offset, RemainingLength, Encoding.UTF8, false); - } - - public BinaryWriter CreateWriter(int offset, int length) - { - return CreateWriter(offset, length, Encoding.UTF8, false); - } - - public BinaryWriter CreateWriter(int offset, int length, Encoding encoding, bool leaveOpen) - { - return new BinaryWriter(GetStream(offset, length, true), encoding, leaveOpen); - } - - private void CheckConstraints(int offset, int length) - { - if (offset < 0) - throw new ArgumentOutOfRangeException(nameof(offset)); - - if (length < 0) - throw new ArgumentOutOfRangeException(nameof(length)); - - if (offset + length > MaxLength) - throw new Exception("BufferData tried to access another BufferData's memory!"); - - if (BaseOffset < RealBaseOffset || BaseOffset > RealBaseOffset + BufferManager.BlockSize) - throw new Exception("The BaseOffset is in another buffer's area!"); - } - - public string ByteData() - { - var sb = new StringBuilder(); - - for (var i = 0; i < RemainingLength; ++i) - { - if (i > 0) - sb.Append(", "); - - sb.Append($"0x{this[Offset + i]:X2}"); - } - - return sb.ToString(); - } - - public override string ToString() - { - return $"BufferData[{BaseOffset} + {Offset}, {Length}]"; - } - } -} diff --git a/src/Rasa.Utils/Memory/BufferManager.cs b/src/Rasa.Utils/Memory/BufferManager.cs deleted file mode 100644 index 1e9fd5d4..00000000 --- a/src/Rasa.Utils/Memory/BufferManager.cs +++ /dev/null @@ -1,60 +0,0 @@ -using System; -using System.Collections.Generic; - -namespace Rasa.Memory -{ - public static class BufferManager - { - private static readonly Stack BufferDatas = new Stack(); - - public static byte[] Buffer { get; private set; } - public static int BlockSize { get; private set; } - - public static void Initialize(int blockSize, int maxClients, int concurrentOperationsByClient) - { - // Already initialized - if (Buffer != null) - return; - - if ((long)blockSize * maxClients * concurrentOperationsByClient > int.MaxValue) - throw new ArgumentOutOfRangeException(nameof(blockSize), blockSize * maxClients * concurrentOperationsByClient, "Can not alloc an array this big!"); - - BlockSize = blockSize; - - // Block Size * Max Client count * concurrentOperationsByClient: - // The block size is the size of the buffer - // The max client count * concurrentOperationsByClient makes sure that there is enough buffers for every client for receive and concurrent send operations - Buffer = new byte[BlockSize * maxClients * concurrentOperationsByClient]; - - // It's a stack, and we should preferable use the buffers at the beginning, so we put it in in reverse order - lock (BufferDatas) - for (var i = Buffer.Length - BlockSize; i >= 0; i -= BlockSize) - BufferDatas.Push(new BufferData(i)); - } - - public static BufferData RequestBuffer() - { - if (BufferDatas.Count == 0) - throw new OutOfMemoryException("BufferManager has ran out of usable buffer space!"); - - BufferData data; - - lock (BufferDatas) - data = BufferDatas.Pop(); - - data.Reset(); - data.Free = false; - - return data; - } - - public static void FreeBuffer(BufferData data) - { - data.Reset(); - data.Free = true; - - lock (BufferDatas) - BufferDatas.Push(data); - } - } -} diff --git a/src/Rasa.Utils/Memory/NonContiguousMemoryStream.cs b/src/Rasa.Utils/Memory/NonContiguousMemoryStream.cs index f6de00d1..ef4ee71b 100644 --- a/src/Rasa.Utils/Memory/NonContiguousMemoryStream.cs +++ b/src/Rasa.Utils/Memory/NonContiguousMemoryStream.cs @@ -1,249 +1,240 @@ -using System; -using System.Buffers; -using System.Collections.Generic; +using System.Buffers; using System.IO; -using System.Linq; -namespace Rasa.Memory +namespace Rasa.Memory; + +public class NonContiguousMemoryStream : Stream { - public class NonContiguousMemoryStream : Stream - { - private const int WriteArrayCapacity = 256; + private const int WriteArrayCapacity = 256; - private record ArrayPoolBuffer(byte[] Buffer, int Length); + private record ArrayPoolBuffer(byte[] Buffer, int Length); - private readonly List _buffers = new(); - private long _origin = 0; + private List Buffers { get; } = new(); + private long Origin { get; set; } - public override bool CanRead => true; - public override bool CanSeek => true; - public override bool CanWrite => true; - public override long Position { get; set; } = 0; + public long WritePosition { get; set; } - public override long Length - { - get - { - return _buffers.Sum(arr => (long)arr.Length) - _origin; - } - } + public override bool CanRead => true; + public override bool CanSeek => true; + public override bool CanWrite => true; + public override long Position { get; set; } + public override long Length => Buffers.Sum(arr => (long)arr.Length) - Origin; - public NonContiguousMemoryStream() - { - } + public int AvailableBytesToRead => (int)(WritePosition - Position); - public void AddSharedPoolArray(byte[] buffer, int length) - { - if (buffer == null) - throw new ArgumentNullException(nameof(buffer)); + public void RemoveBytes(int count) + { + if (count > Length) + throw new ArgumentOutOfRangeException(nameof(count)); - if (length < 0) - throw new ArgumentOutOfRangeException(nameof(length)); + var (index, offset) = GetIndices(count); - _buffers.Add(new ArrayPoolBuffer(buffer, length)); - } - - public void CopyFromArray(byte[] buffer) + if (index > 0) { - if (buffer == null) - throw new ArgumentNullException(nameof(buffer)); + for (var i = 0; i < index; ++i) + ArrayPool.Shared.Return(Buffers[i].Buffer); - CopyFromArray(buffer, 0, buffer.Length); + Buffers.RemoveRange(0, index); } - public void CopyFromArray(byte[] buffer, int offset, int count) - { - if (buffer == null) - throw new ArgumentNullException(nameof(buffer)); - - if (offset < 0) - throw new ArgumentOutOfRangeException(nameof(offset)); + Origin = offset; - if (count > buffer.Length - offset) - throw new ArgumentOutOfRangeException(nameof(count)); - - var newArr = ArrayPool.Shared.Rent(count); + Position = Math.Max(0, Position - count); + WritePosition = Math.Max(0, WritePosition - count); + } - Buffer.BlockCopy(buffer, offset, newArr, 0, count); + private (int, int) GetIndices(long offset) + { + int i = 0; - _buffers.Add(new ArrayPoolBuffer(newArr, count)); - } + offset += Origin; - public void RemoveBytes(int count) + for (; i < Buffers.Count; ++i) { - if (count > Length) - throw new ArgumentOutOfRangeException(nameof(count)); - - var (index, offset) = GetIndices(count); - - if (index > 0) - { - for (var i = 0; i < index; ++i) - { - ArrayPool.Shared.Return(_buffers[i].Buffer); - } + if (offset < Buffers[i].Length) + break; - _buffers.RemoveRange(0, index); - } - - _origin = offset; - - Position = Math.Max(0, Position - count); + offset -= Buffers[i].Length; } - private (int, int) GetIndices(long offset) - { - int i = 0; + if (i == Buffers.Count) + return (i, 0); - offset += _origin; + return (i, (int)offset); + } - for (; i < _buffers.Count; ++i) - { - if (offset < _buffers[i].Length) - { - break; - } + public override void Flush() + { + } - offset -= _buffers[i].Length; - } + public override int Read(byte[] buffer, int offset, int count) + { + ArgumentNullException.ThrowIfNull(buffer); - if (i == _buffers.Count) - return (i, 0); + if (offset < 0) + throw new ArgumentOutOfRangeException(nameof(offset)); - return (i, (int)offset); - } + if (count > buffer.Length - offset) + throw new ArgumentOutOfRangeException(nameof(count)); - public override void Flush() - { - } + if (Position + count > WritePosition) + count = (int)(WritePosition - Position); - public override int Read(byte[] buffer, int offset, int count) - { - if (buffer == null) - throw new ArgumentNullException(nameof(buffer)); + var (indStart, offStart) = GetIndices(Position); + var (indEnd, _) = GetIndices(Position + count); - if (offset < 0) - throw new ArgumentOutOfRangeException(nameof(offset)); + var currentOffset = offStart; + var read = 0; - if (count > buffer.Length - offset) - throw new ArgumentOutOfRangeException(nameof(count)); + for (var i = indStart; i <= indEnd && i < Buffers.Count && count > 0; ++i) + { + int currentCount = count; - var (indStart, offStart) = GetIndices(Position); - var (indEnd, _) = GetIndices(Position + count); + if (Buffers[i].Length - currentOffset < currentCount) + currentCount = Buffers[i].Length - currentOffset; - var currentOffset = offStart; - var read = 0; + Buffer.BlockCopy(Buffers[i].Buffer, currentOffset, buffer, offset, currentCount); - for (var i = indStart; i <= indEnd && i < _buffers.Count && count > 0; ++i) - { - int currentCount = count; + offset += currentCount; + count -= currentCount; - if (_buffers[i].Length - currentOffset < currentCount) - currentCount = _buffers[i].Length - currentOffset; + currentOffset = 0; - Buffer.BlockCopy(_buffers[i].Buffer, currentOffset, buffer, offset, currentCount); + read += currentCount; + } - offset += currentCount; - count -= currentCount; + Position += read; - currentOffset = 0; + return read; + } - read += currentCount; - } + public override long Seek(long offset, SeekOrigin origin) + { + switch (origin) + { + case SeekOrigin.Begin: + Position = offset; + break; - Position += read; + case SeekOrigin.Current: + Position += offset; + break; - return read; + case SeekOrigin.End: + Position = Length + offset; + break; } - public override long Seek(long offset, SeekOrigin origin) - { - switch (origin) - { - case SeekOrigin.Begin: - Position = offset; - break; + return Position; + } - case SeekOrigin.Current: - Position += offset; - break; + public long SeekWrite(long offset, SeekOrigin origin) + { + switch (origin) + { + case SeekOrigin.Begin: + WritePosition = offset; + break; - case SeekOrigin.End: - Position = Length + offset; - break; - } + case SeekOrigin.Current: + WritePosition += offset; + break; - return Position; + case SeekOrigin.End: + WritePosition = Length + offset; + break; } - public override void SetLength(long value) + return WritePosition; + } + + public override void SetLength(long value) + { + if (value > Length) { - if (value > Length) - { - int length = (int)(value - Length); + var newArr = ArrayPool.Shared.Rent((int)(value - Length)); - _buffers.Add(new ArrayPoolBuffer(ArrayPool.Shared.Rent(length), length)); - } + Buffers.Add(new ArrayPoolBuffer(newArr, newArr.Length)); } + } - public override void Write(byte[] buffer, int offset, int count) - { - if (buffer == null) - throw new ArgumentNullException(nameof(buffer)); + public override void Write(byte[] buffer, int offset, int count) + { + ArgumentNullException.ThrowIfNull(buffer); - if (offset < 0) - throw new ArgumentOutOfRangeException(nameof(offset)); + if (offset < 0) + throw new ArgumentOutOfRangeException(nameof(offset)); - if (count > buffer.Length - offset) - throw new ArgumentOutOfRangeException(nameof(count)); + if (count > buffer.Length - offset) + throw new ArgumentOutOfRangeException(nameof(count)); - // Expand the stream with extra space to write to - if (Length < Position + count) - { - SetLength(Length + Math.Max(count, WriteArrayCapacity)); - } + // Expand the stream with extra space to write to + if (WritePosition + count > Length) + SetLength(Length + Math.Max(count, WriteArrayCapacity)); - var (indStart, offStart) = GetIndices(Position); - var (indEnd, _) = GetIndices(Position + count); + var (indStart, offStart) = GetIndices(WritePosition); + var (indEnd, _) = GetIndices(WritePosition + count); - var currentOffset = offStart; - var written = 0; + for (var i = indStart; i <= indEnd && i < Buffers.Count && count > 0; ++i) + { + int currentCount = count; - for (var i = indStart; i <= indEnd && i < _buffers.Count && count > 0; ++i) - { - int currentCount = count; + if (Buffers[i].Length - offStart < currentCount) + currentCount = Buffers[i].Length - offStart; - if (_buffers[i].Length - currentOffset < currentCount) - currentCount = _buffers[i].Length - currentOffset; + Buffer.BlockCopy(buffer, offset, Buffers[i].Buffer, offStart, currentCount); - Buffer.BlockCopy(buffer, offset, _buffers[i].Buffer, currentOffset, currentCount); + offset += currentCount; + count -= currentCount; - offset += currentCount; - count -= currentCount; + offStart = 0; - currentOffset = 0; + WritePosition += currentCount; + } + } - written += currentCount; - } + public void CopyToWithCount(Stream destination, int count) + { + if (count == 0) + return; - Position += written; - } + var buffer = ArrayPool.Shared.Rent(WriteArrayCapacity); - protected override void Dispose(bool disposing) + try { - try + while (count > 0) { - foreach (var buffer in _buffers) - { - ArrayPool.Shared.Return(buffer.Buffer); - } + var toReadSize = Math.Min(count, buffer.Length); - _buffers.Clear(); - } - finally - { - base.Dispose(disposing); + var bytesRead = Read(buffer, 0, toReadSize); + if (bytesRead == 0) + break; + + destination.Write(buffer, 0, bytesRead); + + count -= bytesRead; } } + finally + { + ArrayPool.Shared.Return(buffer); + } + } + + private void Optimize() + { + // TODO: check the buffers and if the buffer.Buffer.Length is greater than buffer.Length + // then grab the next buffer, move the first bytes to the end of + // then return every buffer that + } + + public override void Close() + { + foreach (var buffer in Buffers) + ArrayPool.Shared.Return(buffer.Buffer); + + Buffers.Clear(); + + base.Close(); } -} +} \ No newline at end of file diff --git a/src/Rasa.Utils/Models/Movement.cs b/src/Rasa.Utils/Models/Movement.cs index c985e2c0..00007c23 100644 --- a/src/Rasa.Utils/Models/Movement.cs +++ b/src/Rasa.Utils/Models/Movement.cs @@ -1,23 +1,22 @@ using System.Numerics; -namespace Rasa.Models +namespace Rasa.Models; + +public class Movement { - public class Movement + public Movement(Vector3 position, float velocity, byte flags, Vector2 viewDirection) { - public Movement(Vector3 position, float velocity, byte flags, Vector2 viewDirection) - { - Position = position; - Velocity = velocity; - Flags = flags; - ViewDirection = viewDirection; - } + Position = position; + Velocity = velocity; + Flags = flags; + ViewDirection = viewDirection; + } - public Vector3 Position { get; } + public Vector3 Position { get; } - public float Velocity { get; } + public float Velocity { get; } - public byte Flags { get; } + public byte Flags { get; } - public Vector2 ViewDirection { get; } - } + public Vector2 ViewDirection { get; } } \ No newline at end of file diff --git a/src/Rasa.Utils/Networking/AsyncLengthedSocket.cs b/src/Rasa.Utils/Networking/AsyncLengthedSocket.cs new file mode 100644 index 00000000..6a011825 --- /dev/null +++ b/src/Rasa.Utils/Networking/AsyncLengthedSocket.cs @@ -0,0 +1,351 @@ +using System.Buffers; +using System.Diagnostics; +using System.Net; +using System.Net.Sockets; +using System.Threading.Tasks; +using System.Threading; + +namespace Rasa.Networking; + +using Rasa.Memory; + +public sealed class AsyncLengthedSocket : IDisposable +{ + public enum HeaderSizeType + { + Byte = 1, + Word = 2, + Dword = 4, + } + + public const int MaxDataSize = 0x400; + + private Socket Socket { get; } + private NonContiguousMemoryStream? ReceiveStream { get; set; } + private NonContiguousMemoryStream? SendStream { get; set; } + private Task? ListenTask { get; set; } + private Task? ReceiveTask { get; set; } + private Task? SendTask { get; set; } + private Task? ConnectTask { get; set; } + private SemaphoreSlim? SendDelaySemaphore { get; set; } + private bool Running { get; set; } + private CancellationTokenSource CloseCancellationTokenSource { get; } = new(); + private HeaderSizeType HeaderSize { get; } + private bool CountHeaderSize { get; } + private int HeaderSizeInBytes => (int)HeaderSize; + private int MaxPacketSize => MaxDataSize + (int)HeaderSize; + + public Action? OnError { get; set; } + public Action? OnDisconnect { get; set; } + public Action? OnConnect { get; set; } + public Action? OnAccept { get; set; } + public Action? OnReceive { get; set; } + + public EndPoint? RemoteAddress => Socket?.RemoteEndPoint; + public bool Connected => Socket?.Connected ?? false; + + public AsyncLengthedSocket(HeaderSizeType headerSize, bool countHeaderSize = true) + : this(new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp), headerSize, countHeaderSize) + { + } + + public AsyncLengthedSocket(Socket socket, HeaderSizeType headerSize, bool countHeaderSize = true) + { + Socket = socket; + HeaderSize = headerSize; + CountHeaderSize = countHeaderSize; + } + + public void StartListening(EndPoint endPoint, int backlog = int.MaxValue) + { + ArgumentNullException.ThrowIfNull(endPoint); + + try + { + Socket.Bind(endPoint); + Socket.Listen(backlog); + + ListenTask = DoListen(); + } + catch (Exception ex) + { + OnError?.Invoke(); + + Console.WriteLine($"Unable to start listening on socket {Socket.LocalEndPoint}! Exception: {ex}"); + } + } + + private async Task DoListen() + { + Debug.Assert(OnAccept != null, "No callback is set to handle incoming socket connections!"); + + try + { + while (true) + { + try + { + var socket = await Socket.AcceptAsync(CloseCancellationTokenSource.Token); + + OnAccept(new AsyncLengthedSocket(socket, HeaderSize)); + } + catch (TaskCanceledException) + { + } + } + } + catch (Exception ex) + { + OnError?.Invoke(); + + Console.WriteLine($"Error while listening on socket {Socket.LocalEndPoint}! Exception: {ex}"); + } + } + + public void Start() + { + try + { + Running = true; + ReceiveStream = new(); + SendStream = new(); + SendDelaySemaphore = new(1); + + ReceiveTask = DoReceive(); + SendTask = DoSend(); + } + catch (Exception ex) + { + OnError?.Invoke(); + + Console.WriteLine($"Unable to start communicating on socket {Socket.RemoteEndPoint}! Exception: {ex}"); + } + } + + public void ConnectAsync(EndPoint remote) + { + try + { + ConnectTask = DoConnect(remote); + } + catch (Exception ex) + { + OnError?.Invoke(); + + Console.WriteLine($"Unable to connect to socket at {remote}! Exception: {ex}"); + } + } + + public void Send(byte[] data, int offset, int count) + { + Debug.Assert(SendStream != null, "The socket must be started before sending data to it!"); + Debug.Assert(SendDelaySemaphore != null, "The socket must be started before sending data to it!"); + + var sizeToWrite = count; + if (CountHeaderSize) + sizeToWrite += HeaderSizeInBytes; + + var sizeHolder = ArrayPool.Shared.Rent(HeaderSizeInBytes); + + try + { + BitConverter.TryWriteBytes(sizeHolder, sizeToWrite); + + SendStream.Write(sizeHolder, 0, HeaderSizeInBytes); + SendStream.Write(data, offset, count); + } + finally + { + ArrayPool.Shared.Return(sizeHolder); + } + + SendDelaySemaphore.Release(); + } + + private async Task DoConnect(EndPoint remote) + { + try + { + await Socket.ConnectAsync(remote, CloseCancellationTokenSource.Token); + + OnConnect?.Invoke(); + } + catch (TaskCanceledException) + { + } + catch (Exception ex) + { + OnError?.Invoke(); + + Console.WriteLine($"Error while connecting on address {remote}! Exception: {ex}"); + } + } + + private async Task DoReceive() + { + Debug.Assert(ReceiveStream is not null, "The socket must be started before sending data to it!"); + + var receiveBuffer = ArrayPool.Shared.Rent(MaxPacketSize); + + try + { + while (Running) + { + int received; + + try + { + received = await Socket.ReceiveAsync(receiveBuffer, CloseCancellationTokenSource.Token); + } + catch (TaskCanceledException) + { + break; + } + + if (received == 0) + { + OnDisconnect?.Invoke(); + + Close(); + return; + } + + ReceiveStream.Write(receiveBuffer, 0, received); + + var dataSize = PeekIncomingPacketDataSize(); + if (dataSize == -1) + continue; + + if (ReceiveStream.AvailableBytesToRead >= dataSize + HeaderSizeInBytes) + { + ReceiveStream.RemoveBytes(HeaderSizeInBytes); + + OnReceive?.Invoke(ReceiveStream, dataSize); + + ReceiveStream.RemoveBytes(dataSize); + } + + } + } + catch (Exception ex) + { + OnError?.Invoke(); + + Console.WriteLine($"Error while receiving on socket {Socket.RemoteEndPoint}! Exception: {ex}"); + } + finally + { + ArrayPool.Shared.Return(receiveBuffer); + } + } + + private int PeekIncomingPacketDataSize() + { + Debug.Assert(ReceiveStream is not null, "The socket must be started before sending data to it!"); + + if (ReceiveStream.AvailableBytesToRead < HeaderSizeInBytes) + return -1; + + var readPosition = ReceiveStream!.Position; + var sizeHolder = ArrayPool.Shared.Rent(HeaderSizeInBytes); + + try + { + ReceiveStream.Read(sizeHolder, 0, HeaderSizeInBytes); + + var packetSize = HeaderSize switch + { + HeaderSizeType.Byte => sizeHolder[0], + HeaderSizeType.Word => BitConverter.ToInt16(sizeHolder, 0), + HeaderSizeType.Dword => BitConverter.ToInt32(sizeHolder, 0), + _ => throw new Exception($"Unknown HeaderSizeType: {HeaderSize}!") + }; + + if (CountHeaderSize) + packetSize -= HeaderSizeInBytes; + + return packetSize; + } + finally + { + ReceiveStream.Position = readPosition; + + ArrayPool.Shared.Return(sizeHolder); + } + } + + private async Task DoSend() + { + Debug.Assert(SendStream is not null, "The socket must be started before sending data to it!"); + Debug.Assert(SendDelaySemaphore is not null, "The socket must be started before sending data to it!"); + + var sendBuffer = ArrayPool.Shared.Rent(MaxPacketSize); + + try + { + while (Running) + { + if (SendStream.AvailableBytesToRead > 0) + { + var sizeToSend = Math.Min(MaxPacketSize, SendStream.AvailableBytesToRead); + + SendStream.Read(sendBuffer, 0, sizeToSend); + + int sentBytes; + + try + { + sentBytes = await Socket.SendAsync(new ArraySegment(sendBuffer, 0, sizeToSend), CloseCancellationTokenSource.Token); + } + catch (TaskCanceledException) + { + break; + } + + if (sentBytes == 0) + { + OnError?.Invoke(); + + Close(); + return; + } + + SendStream.RemoveBytes(sentBytes); + } + else + { + try + { + await SendDelaySemaphore.WaitAsync(CloseCancellationTokenSource.Token); + } + catch (TaskCanceledException) + { + } + } + } + } + catch (Exception ex) + { + OnError?.Invoke(); + + Console.WriteLine($"Error while sending on socket {Socket.RemoteEndPoint}! Exception: {ex}"); + } + finally + { + ArrayPool.Shared.Return(sendBuffer); + } + } + + public void Close() + { + Running = false; + CloseCancellationTokenSource.Cancel(); + CloseCancellationTokenSource.Dispose(); + + Socket.Close(); + ReceiveStream?.Dispose(); + SendStream?.Dispose(); + } + + public void Dispose() => Close(); +} \ No newline at end of file diff --git a/src/Rasa.Utils/Networking/LengthedSocket.cs b/src/Rasa.Utils/Networking/LengthedSocket.cs deleted file mode 100644 index d6e756ef..00000000 --- a/src/Rasa.Utils/Networking/LengthedSocket.cs +++ /dev/null @@ -1,352 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Net; -using System.Net.Sockets; - -namespace Rasa.Networking -{ - using Extensions; - using Memory; - using Packets; - - public enum SizeType : byte - { - None = 0, - Char = 1, - Word = 2, - Dword = 4 - } - - public class LengthedSocket - { - public delegate void AcceptHandler(LengthedSocket acceptedSocket); - public delegate void AsyncHandler(SocketAsyncEventArgs args); - public delegate void ReceiveHandler(BufferData data); - public delegate void DisconnectHandler(); - public delegate void EncryptDelegate(BufferData data, ref int length); - public delegate bool DecryptDelegate(BufferData data); - - public SizeType SizeHeaderLength { get; } - public bool CountSize { get; } - public int LengthSize => (int) SizeHeaderLength; - public Socket Socket { get; } - public bool Connected => Socket.Connected; - public IPAddress RemoteAddress => ((IPEndPoint)Socket.RemoteEndPoint).Address; - - public bool AutoReceive { get; set; } = true; - - public AsyncHandler OnConnect; - public DisconnectHandler OnDisconnect; - public AcceptHandler OnAccept; - public AsyncHandler OnSend; - public ReceiveHandler OnReceive; - public AsyncHandler OnError; - public EncryptDelegate OnEncrypt; - public DecryptDelegate OnDecrypt; - - public LengthedSocket(SizeType sizeHeaderLen, bool countSize = true) - : this(new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp), sizeHeaderLen, countSize) - { - } - - public LengthedSocket(Socket s, SizeType sizeHeaderLen, bool countSize) - { - Socket = s; - SizeHeaderLength = sizeHeaderLen; - CountSize = countSize; - } - - #region SocketAsyncEventArgs - private static Stack _socketAsyncEventArgsPool; - - private static readonly object ArgsInitLock = new object(); - - public static void InitializeEventArgsPool(int eventArgsPoolCount) - { - if (_socketAsyncEventArgsPool != null) - return; - - lock (ArgsInitLock) - { - if (_socketAsyncEventArgsPool != null) - return; - - _socketAsyncEventArgsPool = new Stack(eventArgsPoolCount); - - for (var i = 0; i < eventArgsPoolCount; ++i) - _socketAsyncEventArgsPool.Push(new SocketAsyncEventArgs()); - } - } - - private SocketAsyncEventArgs SetupEventArgs(SocketAsyncOperation operation) - { - SocketAsyncEventArgs args; - - lock (_socketAsyncEventArgsPool) - args = _socketAsyncEventArgsPool.Count > 0 ? _socketAsyncEventArgsPool.Pop() : null; - - if (args == null) - throw new OutOfMemoryException("All of the SocketAsyncEventArgs are being used!"); - - switch (operation) - { - case SocketAsyncOperation.Receive: - case SocketAsyncOperation.Send: - var data = BufferManager.RequestBuffer(); - - args.SetBuffer(BufferManager.Buffer, data.BaseOffset, data.MaxLength); - args.UserToken = data; - args.AcceptSocket = Socket; - break; - - case SocketAsyncOperation.Connect: - args.AcceptSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); - break; - } - - args.Completed += OperationCompleted; - - return args; - } - - private void TeardownEventArgs(SocketAsyncEventArgs args) - { - switch (args.LastOperation) - { - case SocketAsyncOperation.Receive: - case SocketAsyncOperation.Send: - BufferManager.FreeBuffer(args.GetUserToken()); - - args.SetBuffer(null, 0, 0); - args.UserToken = null; - break; - - case SocketAsyncOperation.Connect: - args.RemoteEndPoint = null; - break; - } - - args.AcceptSocket = null; - args.Completed -= OperationCompleted; - - lock (_socketAsyncEventArgsPool) - _socketAsyncEventArgsPool.Push(args); - } - - private void OperationCompleted(object o, SocketAsyncEventArgs args) - { - if (args.SocketError != SocketError.Success || (args.LastOperation == SocketAsyncOperation.Receive && args.BytesTransferred == 0)) - OnError?.Invoke(args); - else - { - var data = args.GetUserToken(); - - switch (args.LastOperation) - { - case SocketAsyncOperation.Send: - data.ByteCount += args.BytesTransferred; - - // We've transferred less bytes than we should have - if (data.Length > data.ByteCount) - { - args.SetBuffer(data.BaseOffset + data.ByteCount, data.Length - data.ByteCount); - - // TODO: test if multiple send operations will collide (if the packet was only sent partially, and another packet is getting sent between the two parts) - // TODO: create a queue for sending async, if it collides? - SendAsync(args); - return; - } - - OnSend?.Invoke(args); - break; - - case SocketAsyncOperation.Receive: - // This value may change in the middle of processing, causing odd behavior - var receiveAfter = AutoReceive; - if (ProcessInputBuffer(data, args)) - return; - - if (receiveAfter) - ReceiveAsync(); - - break; - - case SocketAsyncOperation.Connect: - OnConnect?.Invoke(args); - break; - - case SocketAsyncOperation.Accept: - OnAccept?.Invoke(new LengthedSocket(args.AcceptSocket, SizeHeaderLength, CountSize)); - break; - } - } - - TeardownEventArgs(args); - } - - private int ReadSize(BufferData data) - { - var headerSize = !CountSize ? LengthSize : 0; - - switch (SizeHeaderLength) - { - case SizeType.Char: - return headerSize + data[0]; - - case SizeType.Word: - return headerSize + BitConverter.ToInt16(data.Buffer, data.BaseOffset); - - case SizeType.Dword: - return headerSize + BitConverter.ToInt32(data.Buffer, data.BaseOffset); - - default: - throw new NotImplementedException($"Only 1, 2 and 4 byte headers are supported! {SizeHeaderLength} is not!"); - } - } - - private bool ProcessInputBuffer(BufferData data, SocketAsyncEventArgs args) - { - data.ByteCount += args.BytesTransferred; - - while (true) - { - var length = -1; - - if (data.ByteCount >= LengthSize) - length = ReadSize(data); - - if (length != -1) - { - data.Length = length; - - if (data.Length > data.MaxLength) - throw new OutOfMemoryException($"Packet is bigger than the max packet size! Packet size: {length} | Max buffer size: {data.MaxLength}"); - } - - if (length == -1 || data.ByteCount < length) - { - args.SetBuffer(data.BaseOffset + data.ByteCount, data.Length - data.ByteCount); - - ReceiveAsync(args); - return true; - } - - data.Offset = LengthSize; - data.Length = length; - - OnDecrypt?.Invoke(data); - OnReceive?.Invoke(data); - - if (data.ByteCount == length) - break; - - data.ByteCount -= length; - data.BaseOffset += length; - data.Offset = 0; - data.Length = data.MaxLength; - } - - return false; - } - - private void CopyToOtherBuffer(BufferData source, BufferData desti) - { - - } - #endregion - - public void Bind(EndPoint ep) - { - Socket.Bind(ep); - } - - public void Listen(int backlog) - { - Socket.Listen(backlog); - } - - public void AcceptAsync() - { - var args = SetupEventArgs(SocketAsyncOperation.Accept); - - if (!Socket.AcceptAsync(args)) - OperationCompleted(Socket, args); - } - - public void ConnectAsync(EndPoint remote) - { - var args = SetupEventArgs(SocketAsyncOperation.Connect); - - args.RemoteEndPoint = remote; - - if (!Socket.ConnectAsync(args)) - OperationCompleted(Socket, args); - } - - public void ReceiveAsync() - { - ReceiveAsync(SetupEventArgs(SocketAsyncOperation.Receive)); - } - - private void ReceiveAsync(SocketAsyncEventArgs args) - { - if (!Socket.ReceiveAsync(args)) - OperationCompleted(Socket, args); - } - - public void Send(IBasePacket packet) - { - var args = SetupEventArgs(SocketAsyncOperation.Send); - var data = args.GetUserToken(); - - int length; - - // Keep space for the length header - data.Offset = LengthSize; - - // Write the packet data to the buffer - using (var sw = data.CreateWriter()) - { - packet.Write(sw); - - length = (int) sw.BaseStream.Position; - } - - OnEncrypt?.Invoke(data, ref length); - - // Reset the offset to send everything (including the size header) - data.Offset = 0; - data.Length = length + LengthSize; - - var sizeLen = CountSize ? length + LengthSize : length; - - // Copy the size header into the buffer - for (var i = 0; i < LengthSize; ++i) - data[i] = (byte) ((sizeLen >> (i * 8)) & 0xFF); - - args.SetBuffer(data.BaseOffset, data.Length); - - SendAsync(args); - } - - private void SendAsync(SocketAsyncEventArgs args) - { - if (!Socket.SendAsync(args)) - OperationCompleted(Socket, args); - } - - public void Close() - { - try - { - OnDisconnect?.Invoke(); - - Socket.Shutdown(SocketShutdown.Both); - } - catch (Exception) - { - // ignored - } - } - } -} diff --git a/src/Rasa.Utils/Packets/IBasePacket.cs b/src/Rasa.Utils/Packets/IBasePacket.cs index 01920ec2..5ce30a28 100644 --- a/src/Rasa.Utils/Packets/IBasePacket.cs +++ b/src/Rasa.Utils/Packets/IBasePacket.cs @@ -1,11 +1,10 @@ using System.IO; -namespace Rasa.Packets +namespace Rasa.Packets; + +public interface IBasePacket { - public interface IBasePacket - { - void Read(BinaryReader br); + void Read(BinaryReader br); - void Write(BinaryWriter bw); - } + void Write(BinaryWriter bw); } diff --git a/src/Rasa.Utils/Packets/IOpcodedPacket.cs b/src/Rasa.Utils/Packets/IOpcodedPacket.cs index 42817985..b5f8c179 100644 --- a/src/Rasa.Utils/Packets/IOpcodedPacket.cs +++ b/src/Rasa.Utils/Packets/IOpcodedPacket.cs @@ -1,7 +1,6 @@ -namespace Rasa.Packets +namespace Rasa.Packets; + +public interface IOpcodedPacket : IBasePacket { - public interface IOpcodedPacket : IBasePacket - { - T Opcode { get; } - } + T Opcode { get; } } \ No newline at end of file diff --git a/src/Rasa.Utils/Packets/IPacketQueue.cs b/src/Rasa.Utils/Packets/IPacketQueue.cs index ae3dcc32..134086c0 100644 --- a/src/Rasa.Utils/Packets/IPacketQueue.cs +++ b/src/Rasa.Utils/Packets/IPacketQueue.cs @@ -1,10 +1,9 @@ -namespace Rasa.Packets +namespace Rasa.Packets; + +public interface IPacketQueue { - public interface IPacketQueue - { - void EnqueueIncoming(IBasePacket data); - void EnqueueOutgoing(IBasePacket data); - IBasePacket PopIncoming(); - IBasePacket PopOutgoing(); - } + void EnqueueIncoming(IBasePacket data); + void EnqueueOutgoing(IBasePacket data); + IBasePacket? PopIncoming(); + IBasePacket? PopOutgoing(); } diff --git a/src/Rasa.Utils/Packets/PacketHandlerAttribute.cs b/src/Rasa.Utils/Packets/PacketHandlerAttribute.cs index 9fa42368..80850dab 100644 --- a/src/Rasa.Utils/Packets/PacketHandlerAttribute.cs +++ b/src/Rasa.Utils/Packets/PacketHandlerAttribute.cs @@ -1,20 +1,17 @@ -using System; +namespace Rasa.Packets; -namespace Rasa.Packets +[AttributeUsage(AttributeTargets.Method, AllowMultiple = true, Inherited = false)] +public class PacketHandlerAttribute : Attribute { - [AttributeUsage(AttributeTargets.Method, AllowMultiple = true, Inherited = false)] - public class PacketHandlerAttribute : Attribute - { - private object Opcode { get; } + private object Opcode { get; } - public PacketHandlerAttribute(object opcode) - { - Opcode = opcode; - } + public PacketHandlerAttribute(object opcode) + { + Opcode = opcode; + } - public T GetOpcode() where T : struct - { - return (T) Opcode; - } + public T GetOpcode() where T : struct + { + return (T) Opcode; } } diff --git a/src/Rasa.Utils/Packets/PacketQueue.cs b/src/Rasa.Utils/Packets/PacketQueue.cs index 617f9f31..f50c510e 100644 --- a/src/Rasa.Utils/Packets/PacketQueue.cs +++ b/src/Rasa.Utils/Packets/PacketQueue.cs @@ -1,40 +1,37 @@ -using System.Collections.Generic; +namespace Rasa.Packets; -namespace Rasa.Packets +public class PacketQueue : IPacketQueue { - public class PacketQueue : IPacketQueue - { - private readonly Queue _incomingQueue; - private readonly Queue _outgoingQueue; + private readonly Queue _incomingQueue; + private readonly Queue _outgoingQueue; - public PacketQueue() - { - _incomingQueue = new Queue(); - _outgoingQueue = new Queue(); - } + public PacketQueue() + { + _incomingQueue = new Queue(); + _outgoingQueue = new Queue(); + } - public void EnqueueIncoming(IBasePacket data) - { - lock (_incomingQueue) - _incomingQueue.Enqueue(data); - } + public void EnqueueIncoming(IBasePacket data) + { + lock (_incomingQueue) + _incomingQueue.Enqueue(data); + } - public IBasePacket PopIncoming() - { - lock (_incomingQueue) - return _incomingQueue.Count > 0 ?_incomingQueue.Dequeue() : null; - } + public IBasePacket? PopIncoming() + { + lock (_incomingQueue) + return _incomingQueue.Count > 0 ?_incomingQueue.Dequeue() : null; + } - public void EnqueueOutgoing(IBasePacket data) - { - lock (_outgoingQueue) - _outgoingQueue.Enqueue(data); - } + public void EnqueueOutgoing(IBasePacket data) + { + lock (_outgoingQueue) + _outgoingQueue.Enqueue(data); + } - public IBasePacket PopOutgoing() - { - lock (_outgoingQueue) - return _outgoingQueue.Count > 0 ? _outgoingQueue.Dequeue() : null; - } + public IBasePacket? PopOutgoing() + { + lock (_outgoingQueue) + return _outgoingQueue.Count > 0 ? _outgoingQueue.Dequeue() : null; } } diff --git a/src/Rasa.Utils/Packets/PacketRouter.cs b/src/Rasa.Utils/Packets/PacketRouter.cs index 23cc6c35..55a5bcaf 100644 --- a/src/Rasa.Utils/Packets/PacketRouter.cs +++ b/src/Rasa.Utils/Packets/PacketRouter.cs @@ -1,74 +1,67 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Linq.Expressions; +using System.Linq.Expressions; using System.Reflection; -namespace Rasa.Packets +namespace Rasa.Packets; + +public class PacketRouter + where T : class + where O : struct { - public class PacketRouter - where T : class - where O : struct - { - private readonly Dictionary _handlers = new Dictionary(); + private readonly Dictionary _handlers = new Dictionary(); - public PacketRouter() - { - SetupHandlers(); - } + public PacketRouter() + { + SetupHandlers(); + } - public void SetupHandlers() - { - var info = typeof(T).GetTypeInfo(); + public void SetupHandlers() + { + var info = typeof(T).GetTypeInfo(); - foreach (var method in info.DeclaredMethods) - { - foreach (var attr in method.GetCustomAttributes()) - { - var paramType = method.GetParameters().FirstOrDefault()?.ParameterType; - if (paramType == null) - throw new Exception($"Invalid PacketHandler attribute usage! Used on function: {info.FullName}.{method.Name}"); + foreach (var method in info.DeclaredMethods) + { + foreach (var attr in method.GetCustomAttributes()) + { + var paramType = method.GetParameters().FirstOrDefault()?.ParameterType; + if (paramType == null) + throw new Exception($"Invalid PacketHandler attribute usage! Used on function: {info.FullName}.{method.Name}"); - _handlers.Add(attr.GetOpcode(), new PacketData(paramType, method.CreateDelegate(Expression.GetActionType(typeof(T), paramType)))); - } + _handlers.Add(attr.GetOpcode(), new PacketData(paramType, method.CreateDelegate(Expression.GetActionType(typeof(T), paramType)))); } } + } - public void RoutePacket(T target, IOpcodedPacket packet) + public void RoutePacket(T target, IOpcodedPacket packet) + { + if (!_handlers.ContainsKey(packet.Opcode)) { - if (!_handlers.ContainsKey(packet.Opcode)) - { - Logger.WriteLog(LogType.Error, $"PacketRouter can't route to a non-existant opcode: {packet.Opcode}"); - return; - } - - _handlers[packet.Opcode].Handler.DynamicInvoke(target, packet); + Logger.WriteLog(LogType.Error, $"PacketRouter can't route to a non-existant opcode: {packet.Opcode}"); + return; } - public Type GetPacketType(O opcode) - { - if (_handlers.ContainsKey(opcode)) - return _handlers[opcode].Type; + _handlers[packet.Opcode].Handler.DynamicInvoke(target, packet); + } - Logger.WriteLog(LogType.Error, $"Non-existant PacketRouter type definition! Opcode: {opcode}"); - return null; - } + public Type? GetPacketType(O opcode) + { + if (_handlers.TryGetValue(opcode, out var value)) + return value.Type; - public class PacketData - { - public Type Type { get; } - public Delegate Handler { get; } + Logger.WriteLog(LogType.Error, $"Non-existant PacketRouter type definition! Opcode: {opcode}"); + return null; + } - public PacketData(Type type, Delegate handler) - { - Type = type; - Handler = handler; - } + public class PacketData + { + public Type Type { get; } + public Delegate Handler { get; } - public override string ToString() - { - return $"PacketData(Type: {Type} | Handler: {typeof(T).FullName}::{Handler.GetMethodInfo().Name})"; - } + public PacketData(Type type, Delegate handler) + { + Type = type; + Handler = handler; } + + public override string ToString() => $"PacketData(Type: {Type} | Handler: {typeof(T).FullName}::{Handler.GetMethodInfo().Name})"; } } diff --git a/src/Rasa.Utils/Properties/AssemblyInfo.cs b/src/Rasa.Utils/Properties/AssemblyInfo.cs deleted file mode 100644 index 4b2a0d3e..00000000 --- a/src/Rasa.Utils/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System.Reflection; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("Rasa.Utils")] -[assembly: AssemblyTrademark("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("9028a94b-74e3-45aa-8b36-aab753755974")] diff --git a/src/Rasa.Utils/Rasa.Utils.csproj b/src/Rasa.Utils/Rasa.Utils.csproj index 56c98838..eeec94a4 100644 --- a/src/Rasa.Utils/Rasa.Utils.csproj +++ b/src/Rasa.Utils/Rasa.Utils.csproj @@ -2,15 +2,15 @@ Rasa.NET Utils - net5.0 + net7.0 Rasa.Utils Rasa.Utils - 2.1.0 false false false Rasa - 9.0 + 10.0 + enable diff --git a/src/Rasa.Utils/Threading/ILoopable.cs b/src/Rasa.Utils/Threading/ILoopable.cs index 08b094a6..27e92358 100644 --- a/src/Rasa.Utils/Threading/ILoopable.cs +++ b/src/Rasa.Utils/Threading/ILoopable.cs @@ -1,7 +1,6 @@ -namespace Rasa.Threading +namespace Rasa.Threading; + +public interface ILoopable { - public interface ILoopable - { - void MainLoop(long delta); - } + void MainLoop(long delta); } diff --git a/src/Rasa.Utils/Threading/MainLoop.cs b/src/Rasa.Utils/Threading/MainLoop.cs index f19ec55a..63252a6b 100644 --- a/src/Rasa.Utils/Threading/MainLoop.cs +++ b/src/Rasa.Utils/Threading/MainLoop.cs @@ -1,75 +1,70 @@ -using System; -using System.Threading; +using System.Threading; -namespace Rasa.Threading +namespace Rasa.Threading; + +public class MainLoop { - public class MainLoop + public int LoopTime { get; } + public bool Running { get; private set; } + public ILoopable Object { get; } + public Thread? LoopThread { get; private set; } + + private static long CurrentMs() => (DateTime.UtcNow - new DateTime(1970, 1, 1)).Ticks / TimeSpan.TicksPerMillisecond; + + public MainLoop(ILoopable obj, int loopTime) { - public int LoopTime { get; } - public bool Running { get; private set; } - public ILoopable Object { get; } - public Thread LoopThread { get; private set; } + Object = obj; + LoopTime = loopTime; + } - private static long CurrentMs() - { - return (DateTime.UtcNow - new DateTime(1970, 1, 1)).Ticks / TimeSpan.TicksPerMillisecond; - } + public void Start() + { + if (Running) + throw new Exception("Unable to start a running MainLoop!"); - public MainLoop(ILoopable obj, int loopTime) - { - Object = obj; - LoopTime = loopTime; - } + Running = true; - public void Start() + LoopThread = new Thread(Loop) { - if (Running) - throw new Exception("Unable to start a running MainLoop!"); - - Running = true; + Priority = ThreadPriority.Highest + }; + LoopThread.Start(); + } - LoopThread = new Thread(Loop) - { - Priority = ThreadPriority.Highest - }; - LoopThread.Start(); - } + public void Stop() + { + if (!Running) + throw new Exception("Unable to stop a not running MainLoop!"); - public void Stop() - { - if (!Running) - throw new Exception("Unable to stop a not running MainLoop!"); + // No need to join the thread, setting Running to false will eventually stop the thread + Running = false; + } - // No need to join the thread, setting Running to false will eventually stop the thread - Running = false; - } + private void Loop() + { + var prevTime = CurrentMs(); + var prevSleepTime = 0; - private void Loop() + while (Running) { - var prevTime = CurrentMs(); - var prevSleepTime = 0; + var realTime = CurrentMs(); - while (Running) - { - var realTime = CurrentMs(); - - var delta = realTime - prevTime; + var delta = realTime - prevTime; - Object.MainLoop(delta); + Object.MainLoop(delta); - prevTime = realTime; + prevTime = realTime; - if (delta <= LoopTime + prevSleepTime) - { - prevSleepTime = LoopTime + prevSleepTime - (int)delta; - if (prevSleepTime < 10) - prevSleepTime = 10; - } - else + if (delta <= LoopTime + prevSleepTime) + { + prevSleepTime = LoopTime + prevSleepTime - (int)delta; + if (prevSleepTime < 10) prevSleepTime = 10; - - Thread.Sleep(prevSleepTime); } + else + prevSleepTime = 10; + + Thread.Sleep(prevSleepTime); } } } diff --git a/src/Rasa.Utils/Timer/TimedItem.cs b/src/Rasa.Utils/Timer/TimedItem.cs index a352c3de..a9fd0bae 100644 --- a/src/Rasa.Utils/Timer/TimedItem.cs +++ b/src/Rasa.Utils/Timer/TimedItem.cs @@ -1,38 +1,35 @@ -using System; +namespace Rasa.Timer; -namespace Rasa.Timer +public class TimedItem { - public class TimedItem + public string Name { get; } + public bool Repeating { get; } + public long Timer { get; } + public long CurrentTimer { get; private set; } + public Action Action { get; } + + public TimedItem(string name, long timer, bool repeating, Action action) { - public string Name { get; } - public bool Repeating { get; } - public long Timer { get; } - public long CurrentTimer { get; private set; } - public Action Action { get; } + Name = name; + Repeating = repeating; + CurrentTimer = Timer = timer; + Action = action; + } - public TimedItem(string name, long timer, bool repeating, Action action) + public bool Update(long delta) + { + if (CurrentTimer <= delta) { - Name = name; - Repeating = repeating; - CurrentTimer = Timer = timer; - Action = action; + CurrentTimer = Timer - (delta - CurrentTimer); + return true; } - public bool Update(long delta) - { - if (CurrentTimer <= delta) - { - CurrentTimer = Timer - (delta - CurrentTimer); - return true; - } - - CurrentTimer -= delta; - return false; - } + CurrentTimer -= delta; + return false; + } - public void ResetTimer() - { - CurrentTimer = Timer; - } + public void ResetTimer() + { + CurrentTimer = Timer; } } diff --git a/src/Rasa.Utils/Timer/Timer.cs b/src/Rasa.Utils/Timer/Timer.cs index aeb55073..88ec5299 100644 --- a/src/Rasa.Utils/Timer/Timer.cs +++ b/src/Rasa.Utils/Timer/Timer.cs @@ -1,71 +1,60 @@ -using System; -using System.Collections.Generic; +namespace Rasa.Timer; -namespace Rasa.Timer +public class Timer { - public class Timer - { - private readonly Dictionary _timedItems = new(); + private readonly Dictionary _timedItems = new(); - public void Add(string name, long timer, bool repeating, Action action) + public void Add(string name, long timer, bool repeating, Action action) + { + lock (_timedItems) { - lock (_timedItems) - { - if (_timedItems.ContainsKey(name)) - _timedItems.Remove(name); + _timedItems.Remove(name); - _timedItems.Add(name, new TimedItem(name, timer, repeating, action)); - } + _timedItems.Add(name, new TimedItem(name, timer, repeating, action)); } + } - public void Remove(string name) - { - lock (_timedItems) - { - if (_timedItems.ContainsKey(name)) - _timedItems.Remove(name); - } - } + public void Remove(string name) + { + lock (_timedItems) + _timedItems.Remove(name); + } - public void Update(long delta) + public void Update(long delta) + { + lock (_timedItems) { - lock (_timedItems) - { - List toRemove = null; + List? toRemove = null; - foreach (var item in _timedItems) + foreach (var item in _timedItems) + { + if (item.Value.Update(delta)) { - if (item.Value.Update(delta)) - { - item.Value.Action?.Invoke(); + item.Value.Action?.Invoke(); - if (!item.Value.Repeating) - { - if (toRemove == null) - toRemove = new(); + if (!item.Value.Repeating) + { + toRemove ??= new(); - toRemove.Add(item.Key); - } + toRemove.Add(item.Key); } } + } - if (toRemove == null) - return; + if (toRemove == null) + return; - foreach (var key in toRemove) - { - _timedItems.Remove(key); - } - } + foreach (var key in toRemove) + _timedItems.Remove(key); } + } - public void ResetTimer(string name) + public void ResetTimer(string name) + { + lock (_timedItems) { - lock (_timedItems) - { - if (_timedItems.ContainsKey(name)) - _timedItems[name].ResetTimer(); - } + if (_timedItems.TryGetValue(name, out var value)) + value.ResetTimer(); } } }