Skip to content

Commit

Permalink
Clean up ClientLoginHandler's implementation of the kicking stuff.
Browse files Browse the repository at this point in the history
  • Loading branch information
RyanYappert committed Dec 20, 2024
1 parent ef4222d commit a874eab
Show file tree
Hide file tree
Showing 7 changed files with 64 additions and 26 deletions.
62 changes: 44 additions & 18 deletions Arrowgene.Ddon.LoginServer/Handler/ClientLoginHandler.cs
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Text.Json;
using System.Threading.Channels;
using Arrowgene.Ddon.Database.Model;
using Arrowgene.Ddon.Server;
using Arrowgene.Ddon.Shared.Entity.PacketStructure;
using Arrowgene.Ddon.Shared.Model;
using Arrowgene.Ddon.Shared.Model.Rpc;
using Arrowgene.Ddon.Shared.Network;
using Arrowgene.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Text.Json;
using System.Threading;

namespace Arrowgene.Ddon.LoginServer.Handler
{
Expand All @@ -20,17 +21,15 @@ public class ClientLoginHandler : LoginStructurePacketHandler<C2LLoginReq>
private readonly LoginServerSetting _setting;
private readonly object _tokensInFLightLock;
private readonly HashSet<string> _tokensInFlight;

private readonly HttpClient _httpClient = new HttpClient();
private bool _httpReady = false;

public ClientLoginHandler(DdonLoginServer server) : base(server)
{
_setting = server.Setting;
_tokensInFLightLock = new object();
_tokensInFlight = new HashSet<string>();

string authToken = server.AssetRepository.ServerList.Find(x => x.Id == server.Id)?.RpcAuthToken ??
throw new Exception($"Server with ID {server.Id} was not found in the ServerList asset.");
_httpClient.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Internal", $"{server.Id}:{authToken}");
}

public override void Handle(LoginClient client, StructurePacket<C2LLoginReq> packet)
Expand Down Expand Up @@ -110,23 +109,32 @@ public override void Handle(LoginClient client, StructurePacket<C2LLoginReq> pac
}

List<Connection> connections = Database.SelectConnectionsByAccountId(account.Id);
if (connections.Count > 0)
{
Logger.Error(client, $"Already logged in");
res.Error = (uint) ErrorCode.ERROR_CODE_AUTH_MULTIPLE_LOGIN;
client.Send(res);

if (_setting.KickOnMultipleLogin)
if (_setting.KickOnMultipleLogin)
{
for (uint tryCount = 0; tryCount < _setting.KickOnMultipleLoginTries; tryCount++)
{
foreach (var conn in connections)
if (connections.Any())
{
connections.ForEach(x => RequestKick(x));
Thread.Sleep(_setting.KickOnMultipleLoginTimer);
connections = Database.SelectConnectionsByAccountId(account.Id);
}
else
{
RequestKick(conn);
break;
}
}
}

if (connections.Any())
{
Logger.Error(client, $"Already logged in.");
res.Error = (uint)ErrorCode.ERROR_CODE_AUTH_MULTIPLE_LOGIN;
client.Send(res);
return;
}

// Order Important,
// account need to be only assigned after
// verification that no connection exists, and before
Expand Down Expand Up @@ -193,6 +201,24 @@ private bool LockToken(string token)

private void RequestKick(Connection connection)
{
// Timing issues with loading files vs server process startup.
if (!_httpReady)
{
lock(_httpClient)
{
ServerInfo serverInfo = Server.AssetRepository.ServerList.Find(x => x.LoginId == Server.Id);
if (serverInfo is null)
{
Logger.Error($"Login server with ID {Server.Id} was not found in the ServerList asset.");
return;
}

// The login server auths as though it was the game server.
_httpClient.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Internal", $"{serverInfo.Id}:{serverInfo.RpcAuthToken}");
_httpReady = true;
}
}

if (connection.Type == ConnectionType.LoginServer)
{
// Can't talk to the login server, but there's usually not a stuck connection here.
Expand Down
3 changes: 2 additions & 1 deletion Arrowgene.Ddon.Rpc.Web/Route/Internal/CommandRoute.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,14 +49,15 @@ public override RpcCommandResult Execute(DdonGameServer gameServer)
}
case RpcInternalCommand.KickInternal:
{
uint target = _entry.GetData<uint>();
int target = _entry.GetData<int>();
foreach (var client in gameServer.ClientLookup.GetAll())
{
if (client.Account.Id == target)
{
client.Close();
}
}
gameServer.Database.DeleteConnection(gameServer.Id, target);
return new RpcCommandResult(this, true);
}
default:
Expand Down
8 changes: 7 additions & 1 deletion Arrowgene.Ddon.Server/LoginServerSetting.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ public class LoginServerSetting
[DataMember(Order = 90)] public bool AccountRequired { get; set; }
[DataMember(Order = 105)] public uint NoOperationTimeOutTime { get; set; }
[DataMember(Order = 110)] public bool KickOnMultipleLogin { get; set; }

[DataMember(Order = 111)] public int KickOnMultipleLoginTries { get; set; }
[DataMember(Order = 112)] public int KickOnMultipleLoginTimer { get; set; }

public LoginServerSetting()
{
ServerSetting = new ServerSetting();
Expand All @@ -21,6 +23,8 @@ public LoginServerSetting()
AccountRequired = false;
NoOperationTimeOutTime = 14400;
KickOnMultipleLogin = false;
KickOnMultipleLoginTries = 3;
KickOnMultipleLoginTimer = 5000;
}

public LoginServerSetting(LoginServerSetting setting)
Expand All @@ -29,6 +33,8 @@ public LoginServerSetting(LoginServerSetting setting)
AccountRequired = setting.AccountRequired;
NoOperationTimeOutTime = setting.NoOperationTimeOutTime;
KickOnMultipleLogin = setting.KickOnMultipleLogin;
KickOnMultipleLoginTries = setting.KickOnMultipleLoginTries;
KickOnMultipleLoginTimer = setting.KickOnMultipleLoginTimer;
}
}
}
4 changes: 3 additions & 1 deletion Arrowgene.Ddon.Shared/Csv/GameServerListInfoCsv.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ namespace Arrowgene.Ddon.Shared.Csv;

public class GameServerListInfoCsv : CsvReaderWriter<ServerInfo>
{
protected override int NumExpectedItems => 9;
protected override int NumExpectedItems => 10;
protected override ServerInfo CreateInstance(string[] properties)
{
if (!ushort.TryParse(properties[0], out ushort id)) return null;
Expand All @@ -17,6 +17,7 @@ protected override ServerInfo CreateInstance(string[] properties)
if (!bool.TryParse(properties[6], out bool isHide)) return null;
if (!ushort.TryParse(properties[7], out ushort rpcPort)) return null;
string authToken = properties[8];
if (!ushort.TryParse(properties[9], out ushort loginId)) return null;

return new ServerInfo()
{
Expand All @@ -30,6 +31,7 @@ protected override ServerInfo CreateInstance(string[] properties)
IsHide = isHide,
RpcPort = rpcPort,
RpcAuthToken = authToken,
LoginId = loginId,
};
}
}
4 changes: 2 additions & 2 deletions Arrowgene.Ddon.Shared/Files/Assets/GameServerList.csv
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
#Id,Name,Brief,MaxLoginNum,IpAddress,Port,IsHide,RpcPort,RpcAuth
10,Local Host,Brief,1000,127.0.0.1,52000,false,52099,AuthToken
#Id,Name,Brief,MaxLoginNum,IpAddress,Port,IsHide,RpcPort,RpcAuth,LoginId
10,Local Host,Brief,1000,127.0.0.1,52000,false,52099,AuthToken,1
8 changes: 5 additions & 3 deletions Arrowgene.Ddon.Shared/Model/Rpc/RpcInternalCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,18 @@ namespace Arrowgene.Ddon.Shared.Model.Rpc
{
public enum RpcInternalCommand
{
//CommandRoute
NotifyPlayerList, // List<RpcCharacterData>
NotifyClanQuestCompletion, //RpcQuestCompletionData
EpitaphRoadWeeklyReset, // null
KickInternal, // int

//InternalChatRoute
SendTellMessage, // RpcChatData
SendClanMessage, // RpcChatData

//PacketRoute
AnnouncePacketAll, // RpcPacketData
AnnouncePacketClan, // RpcPacketData

EpitaphRoadWeeklyReset, // null
KickInternal, // uint
}
}
1 change: 1 addition & 0 deletions Arrowgene.Ddon.Shared/Model/ServerInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ public ServerInfo()
public bool IsHide { get; set; }
public ushort RpcPort { get; set; }
public string RpcAuthToken { get; set; }
public ushort LoginId { get; set; }

public CDataGameServerListInfo ToCDataGameServerListInfo()
{
Expand Down

0 comments on commit a874eab

Please sign in to comment.