Unstable v0.19.3.0
This commit is contained in:
+124
-132
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
#nullable enable
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using System.Linq;
|
||||
@@ -7,10 +8,10 @@ using Lidgren.Network;
|
||||
|
||||
namespace Barotrauma.Networking
|
||||
{
|
||||
class LidgrenServerPeer : ServerPeer
|
||||
internal sealed class LidgrenServerPeer : ServerPeer
|
||||
{
|
||||
private NetPeerConfiguration netPeerConfiguration;
|
||||
private NetServer netServer;
|
||||
private readonly NetPeerConfiguration netPeerConfiguration;
|
||||
private NetServer? netServer;
|
||||
|
||||
private readonly List<NetIncomingMessage> incomingLidgrenMessages;
|
||||
|
||||
@@ -20,6 +21,25 @@ namespace Barotrauma.Networking
|
||||
|
||||
netServer = null;
|
||||
|
||||
netPeerConfiguration = new NetPeerConfiguration("barotrauma")
|
||||
{
|
||||
AcceptIncomingConnections = true,
|
||||
AutoExpandMTU = false,
|
||||
MaximumConnections = NetConfig.MaxPlayers * 2,
|
||||
EnableUPnP = serverSettings.EnableUPnP,
|
||||
Port = serverSettings.Port
|
||||
};
|
||||
|
||||
netPeerConfiguration.DisableMessageType(
|
||||
NetIncomingMessageType.DebugMessage
|
||||
| NetIncomingMessageType.WarningMessage
|
||||
| NetIncomingMessageType.Receipt
|
||||
| NetIncomingMessageType.ErrorMessage
|
||||
| NetIncomingMessageType.Error
|
||||
| NetIncomingMessageType.UnconnectedData);
|
||||
|
||||
netPeerConfiguration.EnableMessageType(NetIncomingMessageType.ConnectionApproval);
|
||||
|
||||
connectedClients = new List<NetworkConnection>();
|
||||
pendingClients = new List<PendingClient>();
|
||||
|
||||
@@ -32,21 +52,7 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
if (netServer != null) { return; }
|
||||
|
||||
netPeerConfiguration = new NetPeerConfiguration("barotrauma")
|
||||
{
|
||||
AcceptIncomingConnections = true,
|
||||
AutoExpandMTU = false,
|
||||
MaximumConnections = NetConfig.MaxPlayers * 2,
|
||||
EnableUPnP = serverSettings.EnableUPnP,
|
||||
Port = serverSettings.Port
|
||||
};
|
||||
|
||||
netPeerConfiguration.DisableMessageType(NetIncomingMessageType.DebugMessage |
|
||||
NetIncomingMessageType.WarningMessage | NetIncomingMessageType.Receipt |
|
||||
NetIncomingMessageType.ErrorMessage | NetIncomingMessageType.Error |
|
||||
NetIncomingMessageType.UnconnectedData);
|
||||
|
||||
netPeerConfiguration.EnableMessageType(NetIncomingMessageType.ConnectionApproval);
|
||||
incomingLidgrenMessages.Clear();
|
||||
|
||||
netServer = new NetServer(netPeerConfiguration);
|
||||
|
||||
@@ -62,7 +68,7 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
}
|
||||
|
||||
public override void Close(string msg = null)
|
||||
public override void Close(string? msg = null)
|
||||
{
|
||||
if (netServer == null) { return; }
|
||||
|
||||
@@ -90,7 +96,9 @@ namespace Barotrauma.Networking
|
||||
|
||||
public override void Update(float deltaTime)
|
||||
{
|
||||
if (netServer == null) { return; }
|
||||
if (netServer is null) { return; }
|
||||
|
||||
ToolBox.ThrowIfNull(incomingLidgrenMessages);
|
||||
|
||||
if (OnOwnerDetermined != null && OwnerConnection != null)
|
||||
{
|
||||
@@ -99,7 +107,7 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
|
||||
netServer.ReadMessages(incomingLidgrenMessages);
|
||||
|
||||
|
||||
//process incoming connections first
|
||||
foreach (NetIncomingMessage inc in incomingLidgrenMessages.Where(m => m.MessageType == NetIncomingMessageType.ConnectionApproval))
|
||||
{
|
||||
@@ -126,7 +134,7 @@ namespace Barotrauma.Networking
|
||||
catch (Exception e)
|
||||
{
|
||||
string errorMsg = "Server failed to read an incoming message. {" + e + "}\n" + e.StackTrace.CleanupStackTrace();
|
||||
GameAnalyticsManager.AddErrorEventOnce("LidgrenServerPeer.Update:ClientReadException" + e.TargetSite.ToString(), GameAnalyticsManager.ErrorSeverity.Error, errorMsg);
|
||||
GameAnalyticsManager.AddErrorEventOnce($"LidgrenServerPeer.Update:ClientReadException{e.TargetSite}", GameAnalyticsManager.ErrorSeverity.Error, errorMsg);
|
||||
#if DEBUG
|
||||
DebugConsole.ThrowError(errorMsg);
|
||||
#else
|
||||
@@ -138,7 +146,8 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
PendingClient pendingClient = pendingClients[i];
|
||||
|
||||
var connection = pendingClient.Connection as LidgrenConnection;
|
||||
LidgrenConnection connection = (LidgrenConnection)pendingClient.Connection;
|
||||
|
||||
if (connection.NetConnection.Status == NetConnectionStatus.InitiatedConnect ||
|
||||
connection.NetConnection.Status == NetConnectionStatus.ReceivedInitiation ||
|
||||
connection.NetConnection.Status == NetConnectionStatus.RespondedAwaitingApproval ||
|
||||
@@ -146,6 +155,7 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
UpdatePendingClient(pendingClient);
|
||||
if (i >= pendingClients.Count || pendingClients[i] != pendingClient) { i--; }
|
||||
}
|
||||
@@ -155,7 +165,9 @@ namespace Barotrauma.Networking
|
||||
|
||||
private void InitUPnP()
|
||||
{
|
||||
if (netServer == null) { return; }
|
||||
if (netServer is null) { return; }
|
||||
|
||||
ToolBox.ThrowIfNull(netPeerConfiguration);
|
||||
|
||||
netServer.UPnP.ForwardPort(netPeerConfiguration.Port, "barotrauma");
|
||||
#if USE_STEAM
|
||||
@@ -178,7 +190,7 @@ namespace Barotrauma.Networking
|
||||
private void HandleConnection(NetIncomingMessage inc)
|
||||
{
|
||||
if (netServer == null) { return; }
|
||||
|
||||
|
||||
if (connectedClients.Count >= serverSettings.MaxPlayers)
|
||||
{
|
||||
inc.SenderConnection.Deny(DisconnectReason.ServerFull.ToString());
|
||||
@@ -188,13 +200,13 @@ namespace Barotrauma.Networking
|
||||
if (serverSettings.BanList.IsBanned(new LidgrenEndpoint(inc.SenderConnection.RemoteEndPoint), out string banReason))
|
||||
{
|
||||
//IP banned: deny immediately
|
||||
inc.SenderConnection.Deny(DisconnectReason.Banned.ToString() + "/ " + banReason);
|
||||
inc.SenderConnection.Deny($"{DisconnectReason.Banned}/ {banReason}");
|
||||
return;
|
||||
}
|
||||
|
||||
PendingClient pendingClient = pendingClients.Find(c => c.Connection is LidgrenConnection l && l.NetConnection == inc.SenderConnection);
|
||||
PendingClient? pendingClient = pendingClients.Find(c => c.Connection is LidgrenConnection l && l.NetConnection == inc.SenderConnection);
|
||||
|
||||
if (pendingClient == null)
|
||||
if (pendingClient is null)
|
||||
{
|
||||
pendingClient = new PendingClient(new LidgrenConnection(inc.SenderConnection));
|
||||
pendingClients.Add(pendingClient);
|
||||
@@ -203,51 +215,52 @@ namespace Barotrauma.Networking
|
||||
inc.SenderConnection.Approve();
|
||||
}
|
||||
|
||||
private void HandleDataMessage(NetIncomingMessage inc)
|
||||
private void HandleDataMessage(NetIncomingMessage lidgrenMsg)
|
||||
{
|
||||
if (netServer == null) { return; }
|
||||
|
||||
PendingClient pendingClient = pendingClients.Find(c => c.Connection is LidgrenConnection l && l.NetConnection == inc.SenderConnection);
|
||||
PendingClient? pendingClient = pendingClients.Find(c => c.Connection is LidgrenConnection l && l.NetConnection == lidgrenMsg.SenderConnection);
|
||||
|
||||
PacketHeader packetHeader = (PacketHeader)inc.ReadByte();
|
||||
IReadMessage inc = lidgrenMsg.ToReadMessage();
|
||||
|
||||
if (packetHeader.IsConnectionInitializationStep() && pendingClient != null)
|
||||
var (_, packetHeader, initialization) = INetSerializableStruct.Read<PeerPacketHeaders>(inc);
|
||||
|
||||
if (packetHeader.IsConnectionInitializationStep() && pendingClient != null && initialization.HasValue)
|
||||
{
|
||||
ReadConnectionInitializationStep(pendingClient, new ReadWriteMessage(inc.Data, (int)inc.Position, inc.LengthBits, false));
|
||||
ReadConnectionInitializationStep(pendingClient, inc, initialization.Value);
|
||||
}
|
||||
else if (!packetHeader.IsConnectionInitializationStep())
|
||||
{
|
||||
LidgrenConnection conn = connectedClients.Find(c => (c is LidgrenConnection l) && l.NetConnection == inc.SenderConnection) as LidgrenConnection;
|
||||
if (conn == null)
|
||||
if (!(connectedClients.Find(c => c is LidgrenConnection l && l.NetConnection == lidgrenMsg.SenderConnection) is LidgrenConnection conn))
|
||||
{
|
||||
if (pendingClient != null)
|
||||
{
|
||||
RemovePendingClient(pendingClient, DisconnectReason.AuthenticationRequired, "Received data message from unauthenticated client");
|
||||
}
|
||||
else if (inc.SenderConnection.Status != NetConnectionStatus.Disconnected &&
|
||||
inc.SenderConnection.Status != NetConnectionStatus.Disconnecting)
|
||||
else if (lidgrenMsg.SenderConnection.Status != NetConnectionStatus.Disconnected &&
|
||||
lidgrenMsg.SenderConnection.Status != NetConnectionStatus.Disconnecting)
|
||||
{
|
||||
inc.SenderConnection.Disconnect(DisconnectReason.AuthenticationRequired.ToString() + "/ Received data message from unauthenticated client");
|
||||
lidgrenMsg.SenderConnection.Disconnect($"{DisconnectReason.AuthenticationRequired}/ Received data message from unauthenticated client");
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (pendingClient != null) { pendingClients.Remove(pendingClient); }
|
||||
|
||||
if (serverSettings.BanList.IsBanned(conn.Endpoint, out string banReason)
|
||||
|| (conn.AccountInfo.AccountId.TryUnwrap(out var accountId) && serverSettings.BanList.IsBanned(accountId, out banReason))
|
||||
|| conn.AccountInfo.OtherMatchingIds.Any(id => serverSettings.BanList.IsBanned(id, out banReason)))
|
||||
{
|
||||
Disconnect(conn, DisconnectReason.Banned.ToString() + "/ " + banReason);
|
||||
Disconnect(conn, $"{DisconnectReason.Banned}/ {banReason}");
|
||||
return;
|
||||
}
|
||||
UInt16 length = inc.ReadUInt16();
|
||||
|
||||
//DebugConsole.NewMessage(isCompressed + " " + isConnectionInitializationStep + " " + (int)incByte + " " + length);
|
||||
|
||||
IReadMessage msg = new ReadOnlyMessage(inc.Data, packetHeader.IsCompressed(), inc.PositionInBytes, length, conn);
|
||||
OnMessageReceived?.Invoke(conn, msg);
|
||||
var packet = INetSerializableStruct.Read<PeerPacketMessage>(inc);
|
||||
OnMessageReceived?.Invoke(conn, packet.GetReadMessage(packetHeader.IsCompressed(), conn));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void HandleStatusChanged(NetIncomingMessage inc)
|
||||
{
|
||||
if (netServer == null) { return; }
|
||||
@@ -255,30 +268,30 @@ namespace Barotrauma.Networking
|
||||
switch (inc.SenderConnection.Status)
|
||||
{
|
||||
case NetConnectionStatus.Disconnected:
|
||||
string disconnectMsg;
|
||||
LidgrenConnection conn = connectedClients.Select(c => c as LidgrenConnection).FirstOrDefault(c => c.NetConnection == inc.SenderConnection);
|
||||
LidgrenConnection? conn = connectedClients.Cast<LidgrenConnection>().FirstOrDefault(c => c.NetConnection == inc.SenderConnection);
|
||||
if (conn != null)
|
||||
{
|
||||
if (conn == OwnerConnection)
|
||||
{
|
||||
DebugConsole.NewMessage("Owner disconnected: closing the server...");
|
||||
GameServer.Log("Owner disconnected: closing the server...", ServerLog.MessageType.ServerMessage);
|
||||
Close(DisconnectReason.ServerShutdown.ToString() + "/ Owner disconnected");
|
||||
Close($"{DisconnectReason.ServerShutdown}/ Owner disconnected");
|
||||
}
|
||||
else
|
||||
{
|
||||
disconnectMsg = $"ServerMessage.HasDisconnected~[client]={GameMain.Server.ConnectedClients.First(c => c.Connection == conn).Name}";
|
||||
Disconnect(conn, disconnectMsg);
|
||||
#warning TODO: kill off disconnect in layer 1
|
||||
Disconnect(conn, $"ServerMessage.HasDisconnected~[client]={GameMain.Server.ConnectedClients.First(c => c.Connection == conn).Name}");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
PendingClient pendingClient = pendingClients.Find(c => (c.Connection is LidgrenConnection l) && l.NetConnection == inc.SenderConnection);
|
||||
PendingClient? pendingClient = pendingClients.Find(c => c.Connection is LidgrenConnection l && l.NetConnection == inc.SenderConnection);
|
||||
if (pendingClient != null)
|
||||
{
|
||||
RemovePendingClient(pendingClient, DisconnectReason.Unknown, $"ServerMessage.HasDisconnected~[client]={pendingClient.Name}");
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -292,25 +305,23 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
if (netServer == null) { return; }
|
||||
|
||||
PendingClient pendingClient = pendingClients.Find(c => c.AccountInfo.AccountId is Some<AccountId> { Value: SteamId id } && id.Value == steamId);
|
||||
DebugConsole.Log(steamId + " validation: " + status+", "+(pendingClient!=null));
|
||||
|
||||
if (pendingClient == null)
|
||||
PendingClient? pendingClient = pendingClients.Find(c => c.AccountInfo.AccountId is Some<AccountId> { Value: SteamId id } && id.Value == steamId);
|
||||
DebugConsole.Log($"{steamId} validation: {status}, {(pendingClient != null)}");
|
||||
|
||||
if (pendingClient is null)
|
||||
{
|
||||
if (status != Steamworks.AuthResponse.OK)
|
||||
if (status == Steamworks.AuthResponse.OK) { return; }
|
||||
|
||||
if (connectedClients.Find(c => c.AccountInfo.AccountId is Some<AccountId> { Value: SteamId id } && id.Value == steamId) is LidgrenConnection connection)
|
||||
{
|
||||
LidgrenConnection connection = connectedClients.Find(c => c.AccountInfo.AccountId is Some<AccountId> { Value: SteamId id } && id.Value == steamId) as LidgrenConnection;
|
||||
if (connection != null)
|
||||
{
|
||||
Disconnect(connection, DisconnectReason.SteamAuthenticationFailed.ToString() + "/ Steam authentication status changed: " + status.ToString());
|
||||
}
|
||||
Disconnect(connection, $"{DisconnectReason.SteamAuthenticationFailed}/ Steam authentication status changed: {status}");
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
LidgrenConnection pendingConnection = pendingClient.Connection as LidgrenConnection;
|
||||
string banReason;
|
||||
if (serverSettings.BanList.IsBanned(pendingConnection.Endpoint, out banReason)
|
||||
LidgrenConnection pendingConnection = (LidgrenConnection)pendingClient.Connection;
|
||||
if (serverSettings.BanList.IsBanned(pendingConnection.Endpoint, out string banReason)
|
||||
|| serverSettings.BanList.IsBanned(new SteamId(steamId), out banReason)
|
||||
|| serverSettings.BanList.IsBanned(new SteamId(ownerId), out banReason))
|
||||
{
|
||||
@@ -326,8 +337,7 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
else
|
||||
{
|
||||
RemovePendingClient(pendingClient, DisconnectReason.SteamAuthenticationFailed, "Steam authentication failed: " + status.ToString());
|
||||
return;
|
||||
RemovePendingClient(pendingClient, DisconnectReason.SteamAuthenticationFailed, $"Steam authentication failed: {status}");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -335,86 +345,62 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
if (netServer == null) { return; }
|
||||
|
||||
if (!(conn is LidgrenConnection lidgrenConn)) return;
|
||||
if (!connectedClients.Contains(lidgrenConn))
|
||||
if (!connectedClients.Contains(conn))
|
||||
{
|
||||
DebugConsole.ThrowError("Tried to send message to unauthenticated connection: " + lidgrenConn.Endpoint.StringRepresentation);
|
||||
DebugConsole.ThrowError($"Tried to send message to unauthenticated connection: {conn.Endpoint.StringRepresentation}");
|
||||
return;
|
||||
}
|
||||
|
||||
NetDeliveryMethod lidgrenDeliveryMethod = NetDeliveryMethod.Unreliable;
|
||||
switch (deliveryMethod)
|
||||
{
|
||||
case DeliveryMethod.Unreliable:
|
||||
lidgrenDeliveryMethod = NetDeliveryMethod.Unreliable;
|
||||
break;
|
||||
case DeliveryMethod.Reliable:
|
||||
lidgrenDeliveryMethod = NetDeliveryMethod.ReliableUnordered;
|
||||
break;
|
||||
case DeliveryMethod.ReliableOrdered:
|
||||
lidgrenDeliveryMethod = NetDeliveryMethod.ReliableOrdered;
|
||||
break;
|
||||
}
|
||||
byte[] bufAux = msg.PrepareForSending(compressPastThreshold, out bool isCompressed, out _);
|
||||
|
||||
#if DEBUG
|
||||
ToolBox.ThrowIfNull(netPeerConfiguration);
|
||||
netPeerConfiguration.SimulatedDuplicatesChance = GameMain.Server.SimulatedDuplicatesChance;
|
||||
netPeerConfiguration.SimulatedMinimumLatency = GameMain.Server.SimulatedMinimumLatency;
|
||||
netPeerConfiguration.SimulatedRandomLatency = GameMain.Server.SimulatedRandomLatency;
|
||||
netPeerConfiguration.SimulatedLoss = GameMain.Server.SimulatedLoss;
|
||||
#endif
|
||||
|
||||
NetOutgoingMessage lidgrenMsg = netServer.CreateMessage();
|
||||
byte[] msgData = new byte[msg.LengthBytes];
|
||||
msg.PrepareForSending(ref msgData, compressPastThreshold, out bool isCompressed, out int length);
|
||||
lidgrenMsg.Write((byte)(isCompressed ? PacketHeader.IsCompressed : PacketHeader.None));
|
||||
lidgrenMsg.Write((UInt16)length);
|
||||
lidgrenMsg.Write(msgData, 0, length);
|
||||
|
||||
NetSendResult result = netServer.SendMessage(lidgrenMsg, lidgrenConn.NetConnection, lidgrenDeliveryMethod);
|
||||
if (result != NetSendResult.Sent && result != NetSendResult.Queued)
|
||||
var headers = new PeerPacketHeaders
|
||||
{
|
||||
DebugConsole.NewMessage("Failed to send message to "+conn.Endpoint.StringRepresentation+": " + result.ToString(), Microsoft.Xna.Framework.Color.Yellow);
|
||||
}
|
||||
DeliveryMethod = deliveryMethod,
|
||||
PacketHeader = isCompressed ? PacketHeader.IsCompressed : PacketHeader.None,
|
||||
Initialization = null
|
||||
};
|
||||
var body = new PeerPacketMessage
|
||||
{
|
||||
Buffer = bufAux
|
||||
};
|
||||
SendMsgInternal(conn, headers, body);
|
||||
}
|
||||
|
||||
public override void Disconnect(NetworkConnection conn,string msg=null)
|
||||
|
||||
public override void Disconnect(NetworkConnection conn, string? msg = null)
|
||||
{
|
||||
if (netServer == null) { return; }
|
||||
|
||||
if (!(conn is LidgrenConnection lidgrenConn)) { return; }
|
||||
|
||||
if (connectedClients.Contains(lidgrenConn))
|
||||
{
|
||||
lidgrenConn.Status = NetworkConnectionStatus.Disconnected;
|
||||
connectedClients.Remove(lidgrenConn);
|
||||
OnDisconnect?.Invoke(conn, msg);
|
||||
if (conn.AccountInfo.AccountId is Some<AccountId> { Value: SteamId steamId }) { Steam.SteamManager.StopAuthSession(steamId); }
|
||||
if (conn.AccountInfo.AccountId is Some<AccountId> { Value: SteamId steamId }) { SteamManager.StopAuthSession(steamId); }
|
||||
}
|
||||
|
||||
lidgrenConn.NetConnection.Disconnect(msg ?? "Disconnected");
|
||||
}
|
||||
|
||||
protected override void SendMsgInternal(NetworkConnection conn, DeliveryMethod deliveryMethod, IWriteMessage msg)
|
||||
protected override void SendMsgInternal(NetworkConnection conn, PeerPacketHeaders headers, INetSerializableStruct? body)
|
||||
{
|
||||
LidgrenConnection lidgrenConn = conn as LidgrenConnection;
|
||||
NetDeliveryMethod lidgrenDeliveryMethod = NetDeliveryMethod.Unreliable;
|
||||
switch (deliveryMethod)
|
||||
{
|
||||
case DeliveryMethod.Unreliable:
|
||||
lidgrenDeliveryMethod = NetDeliveryMethod.Unreliable;
|
||||
break;
|
||||
case DeliveryMethod.Reliable:
|
||||
lidgrenDeliveryMethod = NetDeliveryMethod.ReliableUnordered;
|
||||
break;
|
||||
case DeliveryMethod.ReliableOrdered:
|
||||
lidgrenDeliveryMethod = NetDeliveryMethod.ReliableOrdered;
|
||||
break;
|
||||
}
|
||||
IWriteMessage msgToSend = new WriteOnlyMessage();
|
||||
msgToSend.WriteNetSerializableStruct(headers);
|
||||
body?.Write(msgToSend);
|
||||
|
||||
NetOutgoingMessage lidgrenMsg = netServer.CreateMessage();
|
||||
lidgrenMsg.Write(msg.Buffer, 0, msg.LengthBytes);
|
||||
NetSendResult result = netServer.SendMessage(lidgrenMsg, lidgrenConn.NetConnection, lidgrenDeliveryMethod);
|
||||
NetSendResult result = ForwardToLidgren(msgToSend, conn, headers.DeliveryMethod);
|
||||
if (result != NetSendResult.Sent && result != NetSendResult.Queued)
|
||||
{
|
||||
DebugConsole.NewMessage("Failed to send message to " + conn.Endpoint.StringRepresentation + ": " + result.ToString(), Microsoft.Xna.Framework.Color.Yellow);
|
||||
DebugConsole.NewMessage($"Failed to send message to {conn.Endpoint}: {result}", Microsoft.Xna.Framework.Color.Yellow);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -430,7 +416,7 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
}
|
||||
|
||||
protected override void ProcessAuthTicket(string name, Option<int> ownKey, Option<SteamId> steamId, PendingClient pendingClient, byte[] ticket)
|
||||
protected override void ProcessAuthTicket(ClientSteamTicketAndVersionPacket packet, PendingClient pendingClient)
|
||||
{
|
||||
if (pendingClient.AccountInfo.AccountId.IsNone())
|
||||
{
|
||||
@@ -438,19 +424,19 @@ namespace Barotrauma.Networking
|
||||
#if DEBUG
|
||||
requireSteamAuth = false;
|
||||
#endif
|
||||
bool hasSteamAuth = packet.SteamAuthTicket.TryUnwrap(out var ticket);
|
||||
|
||||
//steam auth cannot be done (SteamManager not initialized or no ticket given),
|
||||
//but it's not required either -> let the client join without auth
|
||||
if ((!SteamManager.IsInitialized || (ticket?.Length ?? 0) == 0)
|
||||
&& !requireSteamAuth)
|
||||
if ((!SteamManager.IsInitialized || !hasSteamAuth) && !requireSteamAuth)
|
||||
{
|
||||
pendingClient.Name = name;
|
||||
pendingClient.OwnerKey = ownKey;
|
||||
pendingClient.Name = packet.Name;
|
||||
pendingClient.OwnerKey = packet.OwnerKey;
|
||||
pendingClient.InitializationStep = serverSettings.HasPassword ? ConnectionInitialization.Password : ConnectionInitialization.ContentPackageOrder;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!steamId.TryUnwrap(out var id))
|
||||
if (!packet.SteamId.TryUnwrap(out var id) || !(id is SteamId steamId))
|
||||
{
|
||||
if (requireSteamAuth)
|
||||
{
|
||||
@@ -460,36 +446,42 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
else
|
||||
{
|
||||
Steamworks.BeginAuthResult authSessionStartState = Steam.SteamManager.StartAuthSession(ticket, id);
|
||||
Steamworks.BeginAuthResult authSessionStartState = SteamManager.StartAuthSession(ticket, steamId);
|
||||
if (authSessionStartState != Steamworks.BeginAuthResult.OK)
|
||||
{
|
||||
if (requireSteamAuth)
|
||||
{
|
||||
RemovePendingClient(pendingClient, DisconnectReason.SteamAuthenticationFailed, "Steam auth session failed to start: " + authSessionStartState.ToString());
|
||||
return;
|
||||
RemovePendingClient(pendingClient, DisconnectReason.SteamAuthenticationFailed, $"Steam auth session failed to start: {authSessionStartState}");
|
||||
}
|
||||
else
|
||||
{
|
||||
steamId = Option<SteamId>.None();
|
||||
packet.SteamId = Option<AccountId>.None();
|
||||
pendingClient.InitializationStep = serverSettings.HasPassword ? ConnectionInitialization.Password : ConnectionInitialization.ContentPackageOrder;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pendingClient.Connection.SetAccountInfo(new AccountInfo(steamId.Select(uid => (AccountId)uid)));
|
||||
pendingClient.Name = name;
|
||||
pendingClient.OwnerKey = ownKey;
|
||||
pendingClient.Connection.SetAccountInfo(new AccountInfo(packet.SteamId.Select(uid => (AccountId)uid)));
|
||||
pendingClient.Name = packet.Name;
|
||||
pendingClient.OwnerKey = packet.OwnerKey;
|
||||
pendingClient.AuthSessionStarted = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (pendingClient.AccountInfo.AccountId != steamId.Select(uid => (AccountId)uid))
|
||||
if (pendingClient.AccountInfo.AccountId != packet.SteamId.Select(uid => (AccountId)uid))
|
||||
{
|
||||
RemovePendingClient(pendingClient, DisconnectReason.SteamAuthenticationFailed, "SteamID mismatch");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private NetSendResult ForwardToLidgren(IWriteMessage msg, NetworkConnection connection, DeliveryMethod deliveryMethod)
|
||||
{
|
||||
ToolBox.ThrowIfNull(netServer);
|
||||
|
||||
LidgrenConnection conn = (LidgrenConnection)connection;
|
||||
return netServer.SendMessage(msg.ToLidgren(netServer), conn.NetConnection, deliveryMethod.ToLidgren());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+92
-86
@@ -1,39 +1,41 @@
|
||||
using System;
|
||||
#nullable enable
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
using Barotrauma.Extensions;
|
||||
|
||||
namespace Barotrauma.Networking
|
||||
{
|
||||
abstract class ServerPeer
|
||||
internal abstract class ServerPeer
|
||||
{
|
||||
public delegate void MessageCallback(NetworkConnection connection, IReadMessage message);
|
||||
public delegate void DisconnectCallback(NetworkConnection connection, string reason);
|
||||
public delegate void InitializationCompleteCallback(NetworkConnection connection, string clientName);
|
||||
|
||||
public delegate void DisconnectCallback(NetworkConnection connection, string? reason);
|
||||
|
||||
public delegate void InitializationCompleteCallback(NetworkConnection connection, string? clientName);
|
||||
|
||||
public delegate void ShutdownCallback();
|
||||
|
||||
public delegate void OwnerDeterminedCallback(NetworkConnection connection);
|
||||
|
||||
public MessageCallback OnMessageReceived;
|
||||
public DisconnectCallback OnDisconnect;
|
||||
public InitializationCompleteCallback OnInitializationComplete;
|
||||
public ShutdownCallback OnShutdown;
|
||||
public OwnerDeterminedCallback OnOwnerDetermined;
|
||||
|
||||
protected Option<int> ownerKey;
|
||||
|
||||
public NetworkConnection OwnerConnection { get; protected set; }
|
||||
public MessageCallback? OnMessageReceived;
|
||||
public DisconnectCallback? OnDisconnect;
|
||||
public InitializationCompleteCallback? OnInitializationComplete;
|
||||
public ShutdownCallback? OnShutdown;
|
||||
public OwnerDeterminedCallback? OnOwnerDetermined;
|
||||
|
||||
public abstract void InitializeSteamServerCallbacks();
|
||||
|
||||
public abstract void Start();
|
||||
public abstract void Close(string msg = null);
|
||||
public abstract void Close(string? msg = null);
|
||||
public abstract void Update(float deltaTime);
|
||||
|
||||
protected class PendingClient
|
||||
protected sealed class PendingClient
|
||||
{
|
||||
public string Name;
|
||||
public string? Name;
|
||||
public Option<int> OwnerKey;
|
||||
public NetworkConnection Connection;
|
||||
public readonly NetworkConnection Connection;
|
||||
public ConnectionInitialization InitializationStep;
|
||||
public double UpdateTime;
|
||||
public double TimeOut;
|
||||
@@ -60,76 +62,69 @@ namespace Barotrauma.Networking
|
||||
TimeOut = NetworkConnection.TimeoutThreshold;
|
||||
}
|
||||
}
|
||||
protected List<NetworkConnection> connectedClients;
|
||||
protected List<PendingClient> pendingClients;
|
||||
|
||||
protected ServerSettings serverSettings;
|
||||
protected List<NetworkConnection> connectedClients = null!;
|
||||
protected List<PendingClient> pendingClients = null!;
|
||||
protected ServerSettings serverSettings = null!;
|
||||
protected Option<int> ownerKey = null!;
|
||||
protected NetworkConnection? OwnerConnection;
|
||||
|
||||
protected void ReadConnectionInitializationStep(PendingClient pendingClient, IReadMessage inc)
|
||||
protected void ReadConnectionInitializationStep(PendingClient pendingClient, IReadMessage inc, ConnectionInitialization initializationStep)
|
||||
{
|
||||
pendingClient.TimeOut = NetworkConnection.TimeoutThreshold;
|
||||
|
||||
ConnectionInitialization initializationStep = (ConnectionInitialization)inc.ReadByte();
|
||||
|
||||
if (pendingClient.InitializationStep != initializationStep) return;
|
||||
if (pendingClient.InitializationStep != initializationStep) { return; }
|
||||
|
||||
pendingClient.UpdateTime = Timing.TotalTime + Timing.Step;
|
||||
|
||||
switch (initializationStep)
|
||||
{
|
||||
case ConnectionInitialization.SteamTicketAndVersion:
|
||||
string name = Client.SanitizeName(inc.ReadString());
|
||||
int ownerKey = inc.ReadInt32();
|
||||
UInt64 steamIdVal = inc.ReadUInt64();
|
||||
Option<SteamId> steamId = steamIdVal != 0
|
||||
? Option<SteamId>.Some(new SteamId(steamIdVal))
|
||||
: Option<SteamId>.None();
|
||||
UInt16 ticketLength = inc.ReadUInt16();
|
||||
byte[] ticketBytes = inc.ReadBytes(ticketLength);
|
||||
var authPacket = INetSerializableStruct.Read<ClientSteamTicketAndVersionPacket>(inc);
|
||||
|
||||
if (!Client.IsValidName(name, serverSettings))
|
||||
if (!Client.IsValidName(authPacket.Name, serverSettings))
|
||||
{
|
||||
RemovePendingClient(pendingClient, DisconnectReason.InvalidName, "");
|
||||
return;
|
||||
}
|
||||
|
||||
string version = inc.ReadString();
|
||||
bool isCompatibleVersion = NetworkMember.IsCompatible(version, GameMain.Version.ToString()) ?? false;
|
||||
bool isCompatibleVersion = NetworkMember.IsCompatible(authPacket.GameVersion, GameMain.Version.ToString()) ?? false;
|
||||
if (!isCompatibleVersion)
|
||||
{
|
||||
RemovePendingClient(pendingClient, DisconnectReason.InvalidVersion,
|
||||
$"DisconnectMessage.InvalidVersion~[version]={GameMain.Version}~[clientversion]={version}");
|
||||
$"DisconnectMessage.InvalidVersion~[version]={GameMain.Version}~[clientversion]={authPacket.GameVersion}");
|
||||
|
||||
GameServer.Log($"{name} ({steamId}) couldn't join the server (incompatible game version)", ServerLog.MessageType.Error);
|
||||
DebugConsole.NewMessage($"{name} ({steamId}) couldn't join the server (incompatible game version)", Microsoft.Xna.Framework.Color.Red);
|
||||
GameServer.Log($"{authPacket.Name} ({authPacket.SteamId}) couldn't join the server (incompatible game version)", ServerLog.MessageType.Error);
|
||||
DebugConsole.NewMessage($"{authPacket.Name} ({authPacket.SteamId}) couldn't join the server (incompatible game version)", Microsoft.Xna.Framework.Color.Red);
|
||||
return;
|
||||
}
|
||||
|
||||
LanguageIdentifier language = inc.ReadIdentifier().ToLanguageIdentifier();
|
||||
pendingClient.Connection.Language = language;
|
||||
pendingClient.Connection.Language = authPacket.Language.ToLanguageIdentifier();
|
||||
|
||||
Client nameTaken = GameMain.Server.ConnectedClients.Find(c => Homoglyphs.Compare(c.Name.ToLower(), name.ToLower()));
|
||||
Client nameTaken = GameMain.Server.ConnectedClients.Find(c => Homoglyphs.Compare(c.Name.ToLower(), authPacket.Name.ToLower()));
|
||||
if (nameTaken != null)
|
||||
{
|
||||
RemovePendingClient(pendingClient, DisconnectReason.NameTaken, "");
|
||||
GameServer.Log($"{name} ({steamId}) couldn't join the server (name too similar to the name of the client \"" + nameTaken.Name + "\").", ServerLog.MessageType.Error);
|
||||
GameServer.Log($"{authPacket.Name} ({authPacket.SteamId}) couldn't join the server (name too similar to the name of the client \"" + nameTaken.Name + "\").", ServerLog.MessageType.Error);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!pendingClient.AuthSessionStarted)
|
||||
{
|
||||
ProcessAuthTicket(name, ownerKey != 0 ? Option<int>.Some(ownerKey) : Option<int>.None(), steamId, pendingClient, ticketBytes);
|
||||
ProcessAuthTicket(authPacket, pendingClient);
|
||||
}
|
||||
|
||||
break;
|
||||
case ConnectionInitialization.Password:
|
||||
int pwLength = inc.ReadByte();
|
||||
byte[] incPassword = inc.ReadBytes(pwLength);
|
||||
if (pendingClient.PasswordSalt == null)
|
||||
var passwordPacket = INetSerializableStruct.Read<ClientPeerPasswordPacket>(inc);
|
||||
|
||||
if (pendingClient.PasswordSalt is null)
|
||||
{
|
||||
DebugConsole.ThrowError("Received password message from client without salt");
|
||||
return;
|
||||
}
|
||||
if (serverSettings.IsPasswordCorrect(incPassword, pendingClient.PasswordSalt.Value))
|
||||
|
||||
if (serverSettings.IsPasswordCorrect(passwordPacket.Password, pendingClient.PasswordSalt.Value))
|
||||
{
|
||||
pendingClient.InitializationStep = ConnectionInitialization.ContentPackageOrder;
|
||||
}
|
||||
@@ -138,13 +133,13 @@ namespace Barotrauma.Networking
|
||||
pendingClient.Retries++;
|
||||
if (serverSettings.BanAfterWrongPassword && pendingClient.Retries > serverSettings.MaxPasswordRetriesBeforeBan)
|
||||
{
|
||||
string banMsg = "Failed to enter correct password too many times";
|
||||
const string banMsg = "Failed to enter correct password too many times";
|
||||
BanPendingClient(pendingClient, banMsg, null);
|
||||
|
||||
RemovePendingClient(pendingClient, DisconnectReason.Banned, banMsg);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
pendingClient.UpdateTime = Timing.TotalTime;
|
||||
break;
|
||||
case ConnectionInitialization.ContentPackageOrder:
|
||||
@@ -154,25 +149,25 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract void ProcessAuthTicket(string name, Option<int> ownKey, Option<SteamId> steamId, PendingClient pendingClient, byte[] ticket);
|
||||
protected abstract void ProcessAuthTicket(ClientSteamTicketAndVersionPacket packet, PendingClient pendingClient);
|
||||
|
||||
protected void BanPendingClient(PendingClient pendingClient, string banReason, TimeSpan? duration)
|
||||
{
|
||||
void banAccountId(AccountId accountId)
|
||||
{
|
||||
serverSettings.BanList.BanPlayer(pendingClient.Name, accountId, banReason, duration);
|
||||
serverSettings.BanList.BanPlayer(pendingClient.Name ?? "Player", accountId, banReason, duration);
|
||||
}
|
||||
|
||||
|
||||
if (pendingClient.AccountInfo.AccountId.TryUnwrap(out var id)) { banAccountId(id); }
|
||||
|
||||
pendingClient.AccountInfo.OtherMatchingIds.ForEach(banAccountId);
|
||||
serverSettings.BanList.BanPlayer(pendingClient.Name, pendingClient.Connection.Endpoint, banReason, duration);
|
||||
serverSettings.BanList.BanPlayer(pendingClient.Name ?? "Player", pendingClient.Connection.Endpoint, banReason, duration);
|
||||
}
|
||||
|
||||
protected bool IsPendingClientBanned(PendingClient pendingClient, out string banReason)
|
||||
|
||||
protected bool IsPendingClientBanned(PendingClient pendingClient, out string? banReason)
|
||||
{
|
||||
bool isAccountIdBanned(AccountId accountId, out string banReason)
|
||||
bool isAccountIdBanned(AccountId accountId, out string? banReason)
|
||||
{
|
||||
banReason = default;
|
||||
return serverSettings.BanList.IsBanned(accountId, out banReason);
|
||||
}
|
||||
|
||||
@@ -182,16 +177,18 @@ namespace Barotrauma.Networking
|
||||
foreach (var otherId in pendingClient.AccountInfo.OtherMatchingIds)
|
||||
{
|
||||
if (isBanned) { break; }
|
||||
|
||||
isBanned |= isAccountIdBanned(otherId, out banReason);
|
||||
}
|
||||
|
||||
return isBanned;
|
||||
}
|
||||
|
||||
protected abstract void SendMsgInternal(NetworkConnection conn, DeliveryMethod deliveryMethod, IWriteMessage msg);
|
||||
protected abstract void SendMsgInternal(NetworkConnection conn, PeerPacketHeaders headers, INetSerializableStruct? body);
|
||||
|
||||
protected void UpdatePendingClient(PendingClient pendingClient)
|
||||
{
|
||||
if (IsPendingClientBanned(pendingClient, out string banReason))
|
||||
if (IsPendingClientBanned(pendingClient, out string? banReason))
|
||||
{
|
||||
RemovePendingClient(pendingClient, DisconnectReason.Banned, banReason);
|
||||
return;
|
||||
@@ -220,52 +217,61 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
|
||||
if (Timing.TotalTime < pendingClient.UpdateTime) { return; }
|
||||
|
||||
pendingClient.UpdateTime = Timing.TotalTime + 1.0;
|
||||
|
||||
IWriteMessage outMsg = new WriteOnlyMessage();
|
||||
outMsg.Write((byte)(PacketHeader.IsConnectionInitializationStep |
|
||||
PacketHeader.IsServerMessage));
|
||||
outMsg.Write((byte)pendingClient.InitializationStep);
|
||||
PeerPacketHeaders headers = new PeerPacketHeaders
|
||||
{
|
||||
DeliveryMethod = DeliveryMethod.Reliable,
|
||||
PacketHeader = PacketHeader.IsConnectionInitializationStep | PacketHeader.IsServerMessage,
|
||||
Initialization = pendingClient.InitializationStep
|
||||
};
|
||||
|
||||
INetSerializableStruct? structToSend = null;
|
||||
|
||||
switch (pendingClient.InitializationStep)
|
||||
{
|
||||
case ConnectionInitialization.ContentPackageOrder:
|
||||
var mpContentPackages = ContentPackageManager.EnabledPackages.All.Where(cp => cp.HasMultiplayerSyncedContent).ToList();
|
||||
outMsg.WriteVariableUInt32((UInt32)mpContentPackages.Count);
|
||||
for (int i = 0; i < mpContentPackages.Count; i++)
|
||||
|
||||
DateTime timeNow = DateTime.UtcNow;
|
||||
structToSend = new ServerPeerContentPackageOrderPacket
|
||||
{
|
||||
outMsg.Write(mpContentPackages[i].Name);
|
||||
byte[] hashBytes = mpContentPackages[i].Hash.ByteRepresentation;
|
||||
outMsg.WriteVariableUInt32((UInt32)hashBytes.Length);
|
||||
outMsg.Write(hashBytes, 0, hashBytes.Length);
|
||||
outMsg.Write(mpContentPackages[i].SteamWorkshopId);
|
||||
UInt32 installTimeDiffSeconds = (UInt32)((mpContentPackages[i].InstallTime ?? DateTime.UtcNow) - DateTime.UtcNow).TotalSeconds;
|
||||
outMsg.Write(installTimeDiffSeconds);
|
||||
}
|
||||
ServerName = GameMain.Server.ServerName,
|
||||
ContentPackages = ContentPackageManager.EnabledPackages.All.Where(cp => cp.HasMultiplayerSyncedContent)
|
||||
.Select(contentPackage => new ServerContentPackage(contentPackage, timeNow))
|
||||
.ToImmutableArray()
|
||||
};
|
||||
|
||||
break;
|
||||
case ConnectionInitialization.Password:
|
||||
outMsg.Write(pendingClient.PasswordSalt == null); outMsg.WritePadBits();
|
||||
if (pendingClient.PasswordSalt == null)
|
||||
structToSend = new ServerPeerPasswordPacket
|
||||
{
|
||||
pendingClient.PasswordSalt = Lidgren.Network.CryptoRandom.Instance.Next();
|
||||
outMsg.Write(pendingClient.PasswordSalt.Value);
|
||||
}
|
||||
else
|
||||
Salt = GetSalt(pendingClient),
|
||||
RetriesLeft = Option<int>.Some(pendingClient.Retries)
|
||||
};
|
||||
|
||||
static Option<int> GetSalt(PendingClient client)
|
||||
{
|
||||
outMsg.Write(pendingClient.Retries);
|
||||
if (client.PasswordSalt is { } salt) { return Option<int>.Some(salt); }
|
||||
|
||||
salt = Lidgren.Network.CryptoRandom.Instance.Next();
|
||||
client.PasswordSalt = salt;
|
||||
return Option<int>.Some(salt);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
SendMsgInternal(pendingClient.Connection, DeliveryMethod.Reliable, outMsg);
|
||||
SendMsgInternal(pendingClient.Connection, headers, structToSend);
|
||||
}
|
||||
|
||||
protected virtual void CheckOwnership(PendingClient pendingClient) { }
|
||||
|
||||
protected void RemovePendingClient(PendingClient pendingClient, DisconnectReason reason, string msg)
|
||||
protected void RemovePendingClient(PendingClient pendingClient, DisconnectReason reason, string? msg)
|
||||
{
|
||||
if (pendingClients.Contains(pendingClient))
|
||||
{
|
||||
Disconnect(pendingClient.Connection, reason + "/" + msg);
|
||||
Disconnect(pendingClient.Connection, $"{reason}/{msg}");
|
||||
|
||||
pendingClients.Remove(pendingClient);
|
||||
|
||||
@@ -279,6 +285,6 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
|
||||
public abstract void Send(IWriteMessage msg, NetworkConnection conn, DeliveryMethod deliveryMethod, bool compressPastThreshold = true);
|
||||
public abstract void Disconnect(NetworkConnection conn, string msg = null);
|
||||
public abstract void Disconnect(NetworkConnection conn, string? msg = null);
|
||||
}
|
||||
}
|
||||
}
|
||||
+111
-93
@@ -1,21 +1,20 @@
|
||||
using System;
|
||||
#nullable enable
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Barotrauma.Networking
|
||||
{
|
||||
class SteamP2PServerPeer : ServerPeer
|
||||
internal sealed class SteamP2PServerPeer : ServerPeer
|
||||
{
|
||||
private bool started;
|
||||
|
||||
private readonly SteamId ownerSteamId;
|
||||
|
||||
private UInt64 ownerKey64 => unchecked((UInt64)ownerKey.Fallback(0));
|
||||
|
||||
private SteamId ReadSteamId(IReadMessage inc)
|
||||
=> new SteamId(inc.ReadUInt64() ^ ownerKey64);
|
||||
private void WriteSteamId(IWriteMessage msg, SteamId val)
|
||||
=> msg.Write(val.Value ^ ownerKey64);
|
||||
|
||||
private SteamId ReadSteamId(IReadMessage inc) => new SteamId(inc.ReadUInt64() ^ ownerKey64);
|
||||
private void WriteSteamId(IWriteMessage msg, SteamId val) => msg.WriteUInt64(val.Value ^ ownerKey64);
|
||||
|
||||
public SteamP2PServerPeer(SteamId steamId, int ownerKey, ServerSettings settings)
|
||||
{
|
||||
@@ -33,23 +32,22 @@ namespace Barotrauma.Networking
|
||||
|
||||
public override void Start()
|
||||
{
|
||||
IWriteMessage outMsg = new WriteOnlyMessage();
|
||||
WriteSteamId(outMsg, ownerSteamId);
|
||||
outMsg.Write((byte)DeliveryMethod.Reliable);
|
||||
outMsg.Write((byte)(PacketHeader.IsConnectionInitializationStep | PacketHeader.IsServerMessage));
|
||||
|
||||
byte[] msgToSend = (byte[])outMsg.Buffer.Clone();
|
||||
Array.Resize(ref msgToSend, outMsg.LengthBytes);
|
||||
ChildServerRelay.Write(msgToSend);
|
||||
var headers = new PeerPacketHeaders
|
||||
{
|
||||
DeliveryMethod = DeliveryMethod.Reliable,
|
||||
PacketHeader = PacketHeader.IsConnectionInitializationStep | PacketHeader.IsServerMessage,
|
||||
Initialization = null
|
||||
};
|
||||
SendMsgInternal(ownerSteamId, headers, null);
|
||||
|
||||
started = true;
|
||||
}
|
||||
|
||||
public override void Close(string msg = null)
|
||||
public override void Close(string? msg = null)
|
||||
{
|
||||
if (!started) { return; }
|
||||
|
||||
if (OwnerConnection != null) OwnerConnection.Status = NetworkConnectionStatus.Disconnected;
|
||||
if (OwnerConnection != null) { OwnerConnection.Status = NetworkConnectionStatus.Disconnected; }
|
||||
|
||||
for (int i = pendingClients.Count - 1; i >= 0; i--)
|
||||
{
|
||||
@@ -82,7 +80,7 @@ namespace Barotrauma.Networking
|
||||
//backwards for loop so we can remove elements while iterating
|
||||
for (int i = connectedClients.Count - 1; i >= 0; i--)
|
||||
{
|
||||
SteamP2PConnection conn = connectedClients[i] as SteamP2PConnection;
|
||||
SteamP2PConnection conn = (SteamP2PConnection)connectedClients[i];
|
||||
conn.Decay(deltaTime);
|
||||
if (conn.Timeout < 0.0)
|
||||
{
|
||||
@@ -103,7 +101,7 @@ namespace Barotrauma.Networking
|
||||
catch (Exception e)
|
||||
{
|
||||
string errorMsg = "Server failed to read an incoming message. {" + e + "}\n" + e.StackTrace.CleanupStackTrace();
|
||||
GameAnalyticsManager.AddErrorEventOnce("SteamP2PServerPeer.Update:ClientReadException" + e.TargetSite.ToString(), GameAnalyticsManager.ErrorSeverity.Error, errorMsg);
|
||||
GameAnalyticsManager.AddErrorEventOnce($"SteamP2PServerPeer.Update:ClientReadException{e.TargetSite}", GameAnalyticsManager.ErrorSeverity.Error, errorMsg);
|
||||
#if DEBUG
|
||||
DebugConsole.ThrowError(errorMsg);
|
||||
#else
|
||||
@@ -118,36 +116,36 @@ namespace Barotrauma.Networking
|
||||
if (i >= pendingClients.Count || pendingClients[i] != pendingClient) { i--; }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void HandleDataMessage(IReadMessage inc)
|
||||
{
|
||||
if (!started) { return; }
|
||||
|
||||
SteamId senderSteamId = ReadSteamId(inc);
|
||||
SteamId ownerSteamId = ReadSteamId(inc);
|
||||
|
||||
PacketHeader packetHeader = (PacketHeader)inc.ReadByte();
|
||||
|
||||
SteamId sentOwnerSteamId = ReadSteamId(inc);
|
||||
|
||||
var (deliveryMethod, packetHeader, initialization) = INetSerializableStruct.Read<PeerPacketHeaders>(inc);
|
||||
|
||||
if (packetHeader.IsServerMessage())
|
||||
{
|
||||
DebugConsole.ThrowError("Got server message from" + senderSteamId.ToString());
|
||||
DebugConsole.ThrowError($"Got server message from {senderSteamId}");
|
||||
return;
|
||||
}
|
||||
|
||||
if (senderSteamId != this.ownerSteamId) //sender is remote, handle disconnects and heartbeats
|
||||
if (senderSteamId != ownerSteamId) //sender is remote, handle disconnects and heartbeats
|
||||
{
|
||||
bool connectionMatches(NetworkConnection conn)
|
||||
=> conn is SteamP2PConnection { Endpoint: SteamP2PEndpoint { SteamId: var steamId } }
|
||||
&& steamId == senderSteamId;
|
||||
PendingClient pendingClient = pendingClients.Find(c => connectionMatches(c.Connection));
|
||||
SteamP2PConnection connectedClient = connectedClients.Find(connectionMatches) as SteamP2PConnection;
|
||||
bool connectionMatches(NetworkConnection conn) =>
|
||||
conn is SteamP2PConnection { Endpoint: SteamP2PEndpoint { SteamId: var steamId } }
|
||||
&& steamId == senderSteamId;
|
||||
|
||||
PendingClient? pendingClient = pendingClients.Find(c => connectionMatches(c.Connection));
|
||||
SteamP2PConnection? connectedClient = connectedClients.Find(connectionMatches) as SteamP2PConnection;
|
||||
|
||||
pendingClient?.Heartbeat();
|
||||
connectedClient?.Heartbeat();
|
||||
|
||||
string banReason;
|
||||
if (serverSettings.BanList.IsBanned(senderSteamId, out banReason) ||
|
||||
serverSettings.BanList.IsBanned(ownerSteamId, out banReason))
|
||||
if (serverSettings.BanList.IsBanned(senderSteamId, out string banReason) ||
|
||||
serverSettings.BanList.IsBanned(sentOwnerSteamId, out banReason))
|
||||
{
|
||||
if (pendingClient != null)
|
||||
{
|
||||
@@ -155,9 +153,8 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
else if (connectedClient != null)
|
||||
{
|
||||
Disconnect(connectedClient, DisconnectReason.Banned.ToString() + "/ "+ banReason);
|
||||
Disconnect(connectedClient, $"{DisconnectReason.Banned}/ {banReason}");
|
||||
}
|
||||
return;
|
||||
}
|
||||
else if (packetHeader.IsDisconnectMessage())
|
||||
{
|
||||
@@ -171,7 +168,6 @@ namespace Barotrauma.Networking
|
||||
string disconnectMsg = $"ServerMessage.HasDisconnected~[client]={GameMain.Server.ConnectedClients.First(c => c.Connection == connectedClient).Name}";
|
||||
Disconnect(connectedClient, disconnectMsg, false);
|
||||
}
|
||||
return;
|
||||
}
|
||||
else if (packetHeader.IsHeartbeatMessage())
|
||||
{
|
||||
@@ -182,12 +178,15 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
if (pendingClient != null)
|
||||
{
|
||||
pendingClient.Connection.SetAccountInfo(new AccountInfo(senderSteamId, ownerSteamId));
|
||||
ReadConnectionInitializationStep(pendingClient, new ReadOnlyMessage(inc.Buffer, false, inc.BytePosition, inc.LengthBytes - inc.BytePosition, null));
|
||||
pendingClient.Connection.SetAccountInfo(new AccountInfo(senderSteamId, sentOwnerSteamId));
|
||||
ReadConnectionInitializationStep(
|
||||
pendingClient,
|
||||
new ReadWriteMessage(inc.Buffer, inc.BitPosition, inc.LengthBits, false),
|
||||
initialization ?? throw new Exception("Initialization step missing"));
|
||||
}
|
||||
else
|
||||
else if (initialization.HasValue)
|
||||
{
|
||||
ConnectionInitialization initializationStep = (ConnectionInitialization)inc.ReadByte();
|
||||
ConnectionInitialization initializationStep = initialization.Value;
|
||||
if (initializationStep == ConnectionInitialization.ConnectionStarted)
|
||||
{
|
||||
pendingClients.Add(new PendingClient(new SteamP2PConnection(senderSteamId)));
|
||||
@@ -196,51 +195,53 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
else if (connectedClient != null)
|
||||
{
|
||||
UInt16 length = inc.ReadUInt16();
|
||||
|
||||
IReadMessage msg = new ReadOnlyMessage(inc.Buffer, packetHeader.IsCompressed(), inc.BytePosition, length, connectedClient);
|
||||
var packet = INetSerializableStruct.Read<PeerPacketMessage>(inc);
|
||||
IReadMessage msg = new ReadOnlyMessage(packet.Buffer, packetHeader.IsCompressed(), 0, packet.Length, connectedClient);
|
||||
OnMessageReceived?.Invoke(connectedClient, msg);
|
||||
}
|
||||
}
|
||||
else //sender is owner
|
||||
{
|
||||
if (OwnerConnection != null) { (OwnerConnection as SteamP2PConnection).Heartbeat(); }
|
||||
(OwnerConnection as SteamP2PConnection)?.Heartbeat();
|
||||
|
||||
if (packetHeader.IsDisconnectMessage())
|
||||
{
|
||||
DebugConsole.ThrowError("Received disconnect message from owner");
|
||||
return;
|
||||
}
|
||||
|
||||
if (packetHeader.IsServerMessage())
|
||||
{
|
||||
DebugConsole.ThrowError("Received server message from owner");
|
||||
return;
|
||||
}
|
||||
|
||||
if (packetHeader.IsConnectionInitializationStep())
|
||||
{
|
||||
if (OwnerConnection == null)
|
||||
if (OwnerConnection is null)
|
||||
{
|
||||
string ownerName = inc.ReadString();
|
||||
OwnerConnection = new SteamP2PConnection(this.ownerSteamId)
|
||||
var packet = INetSerializableStruct.Read<SteamP2PInitializationOwnerPacket>(inc);
|
||||
OwnerConnection = new SteamP2PConnection(ownerSteamId)
|
||||
{
|
||||
Language = GameSettings.CurrentConfig.Language
|
||||
};
|
||||
OwnerConnection.SetAccountInfo(new AccountInfo(this.ownerSteamId, this.ownerSteamId));
|
||||
OwnerConnection.SetAccountInfo(new AccountInfo(ownerSteamId, ownerSteamId));
|
||||
|
||||
OnInitializationComplete?.Invoke(OwnerConnection, ownerName);
|
||||
OnInitializationComplete?.Invoke(OwnerConnection, packet.OwnerName);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (packetHeader.IsHeartbeatMessage())
|
||||
{
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
UInt16 length = inc.ReadUInt16();
|
||||
|
||||
IReadMessage msg = new ReadOnlyMessage(inc.Buffer, packetHeader.IsCompressed(), inc.BytePosition, length, OwnerConnection);
|
||||
OnMessageReceived?.Invoke(OwnerConnection, msg);
|
||||
var packet = INetSerializableStruct.Read<PeerPacketMessage>(inc);
|
||||
IReadMessage msg = new ReadOnlyMessage(packet.Buffer, packetHeader.IsCompressed(), 0, packet.Length, OwnerConnection);
|
||||
OnMessageReceived?.Invoke(OwnerConnection!, msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -249,59 +250,67 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
throw new InvalidOperationException("Called InitializeSteamServerCallbacks on SteamP2PServerPeer!");
|
||||
}
|
||||
|
||||
|
||||
public override void Send(IWriteMessage msg, NetworkConnection conn, DeliveryMethod deliveryMethod, bool compressPastThreshold = true)
|
||||
{
|
||||
if (!started) { return; }
|
||||
|
||||
if (!(conn is SteamP2PConnection steamp2pConn)) { return; }
|
||||
if (!connectedClients.Contains(steamp2pConn) && conn != OwnerConnection)
|
||||
if (!(conn is SteamP2PConnection steamP2PConn)) { return; }
|
||||
|
||||
if (!connectedClients.Contains(steamP2PConn) && conn != OwnerConnection)
|
||||
{
|
||||
DebugConsole.ThrowError("Tried to send message to unauthenticated connection: " + steamp2pConn.AccountInfo.AccountId.ToString());
|
||||
DebugConsole.ThrowError($"Tried to send message to unauthenticated connection: {steamP2PConn.AccountInfo.AccountId}");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!conn.AccountInfo.AccountId.TryUnwrap(out var connAccountId) || !(connAccountId is SteamId connSteamId)) { return; }
|
||||
|
||||
IWriteMessage msgToSend = new WriteOnlyMessage();
|
||||
byte[] msgData = new byte[16];
|
||||
msg.PrepareForSending(ref msgData, compressPastThreshold, out bool isCompressed, out int length);
|
||||
WriteSteamId(msgToSend, connSteamId);
|
||||
msgToSend.Write((byte)deliveryMethod);
|
||||
msgToSend.Write((byte)((isCompressed ? PacketHeader.IsCompressed : PacketHeader.None) | PacketHeader.IsServerMessage));
|
||||
msgToSend.Write((UInt16)length);
|
||||
msgToSend.Write(msgData, 0, length);
|
||||
byte[] bufAux = msg.PrepareForSending(compressPastThreshold, out bool isCompressed, out _);
|
||||
|
||||
byte[] bufToSend = (byte[])msgToSend.Buffer.Clone();
|
||||
Array.Resize(ref bufToSend, msgToSend.LengthBytes);
|
||||
ChildServerRelay.Write(bufToSend);
|
||||
var headers = new PeerPacketHeaders
|
||||
{
|
||||
DeliveryMethod = deliveryMethod,
|
||||
PacketHeader = (isCompressed ? PacketHeader.IsCompressed : PacketHeader.None)
|
||||
| PacketHeader.IsServerMessage,
|
||||
Initialization = null
|
||||
};
|
||||
var body = new PeerPacketMessage
|
||||
{
|
||||
Buffer = bufAux
|
||||
};
|
||||
SendMsgInternal(steamP2PConn, headers, body);
|
||||
}
|
||||
|
||||
private void SendDisconnectMessage(SteamId steamId, string msg)
|
||||
private void SendDisconnectMessage(SteamId steamId, string? msg)
|
||||
{
|
||||
if (!started) { return; }
|
||||
|
||||
if (string.IsNullOrWhiteSpace(msg)) { return; }
|
||||
|
||||
IWriteMessage msgToSend = new WriteOnlyMessage();
|
||||
WriteSteamId(msgToSend, steamId);
|
||||
msgToSend.Write((byte)DeliveryMethod.Reliable);
|
||||
msgToSend.Write((byte)(PacketHeader.IsDisconnectMessage | PacketHeader.IsServerMessage));
|
||||
msgToSend.Write(msg);
|
||||
var headers = new PeerPacketHeaders
|
||||
{
|
||||
DeliveryMethod = DeliveryMethod.Reliable,
|
||||
PacketHeader = PacketHeader.IsDisconnectMessage | PacketHeader.IsServerMessage,
|
||||
Initialization = null
|
||||
};
|
||||
var packet = new PeerDisconnectPacket
|
||||
{
|
||||
Message = msg
|
||||
};
|
||||
|
||||
byte[] bufToSend = (byte[])msgToSend.Buffer.Clone();
|
||||
Array.Resize(ref bufToSend, msgToSend.LengthBytes);
|
||||
ChildServerRelay.Write(bufToSend);
|
||||
SendMsgInternal(steamId, headers, packet);
|
||||
}
|
||||
|
||||
private void Disconnect(NetworkConnection conn, string msg, bool sendDisconnectMessage)
|
||||
private void Disconnect(NetworkConnection conn, string? msg, bool sendDisconnectMessage)
|
||||
{
|
||||
if (!started) { return; }
|
||||
|
||||
if (!(conn is SteamP2PConnection steamp2pConn)) { return; }
|
||||
|
||||
if (!conn.AccountInfo.AccountId.TryUnwrap(out var connAccountId) || !(connAccountId is SteamId connSteamId)) { return; }
|
||||
|
||||
|
||||
if (sendDisconnectMessage) { SendDisconnectMessage(connSteamId, msg); }
|
||||
|
||||
if (connectedClients.Contains(steamp2pConn))
|
||||
{
|
||||
steamp2pConn.Status = NetworkConnectionStatus.Disconnected;
|
||||
@@ -315,32 +324,41 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
}
|
||||
|
||||
public override void Disconnect(NetworkConnection conn, string msg = null)
|
||||
public override void Disconnect(NetworkConnection conn, string? msg = null)
|
||||
{
|
||||
Disconnect(conn, msg, true);
|
||||
}
|
||||
|
||||
protected override void SendMsgInternal(NetworkConnection conn, DeliveryMethod deliveryMethod, IWriteMessage msg)
|
||||
protected override void SendMsgInternal(NetworkConnection conn, PeerPacketHeaders headers, INetSerializableStruct? body)
|
||||
{
|
||||
var connSteamId = conn is SteamP2PConnection { Endpoint: SteamP2PEndpoint { SteamId: var id } }
|
||||
? id : null;
|
||||
var connSteamId = conn is SteamP2PConnection { Endpoint: SteamP2PEndpoint { SteamId: var id } } ? id : null;
|
||||
if (connSteamId is null) { return; }
|
||||
|
||||
|
||||
SendMsgInternal(connSteamId, headers, body);
|
||||
}
|
||||
|
||||
private void SendMsgInternal(SteamId connSteamId, PeerPacketHeaders headers, INetSerializableStruct? body)
|
||||
{
|
||||
IWriteMessage msgToSend = new WriteOnlyMessage();
|
||||
WriteSteamId(msgToSend, connSteamId);
|
||||
msgToSend.Write((byte)deliveryMethod);
|
||||
msgToSend.Write(msg.Buffer, 0, msg.LengthBytes);
|
||||
byte[] bufToSend = (byte[])msgToSend.Buffer.Clone();
|
||||
Array.Resize(ref bufToSend, msgToSend.LengthBytes);
|
||||
msgToSend.WriteNetSerializableStruct(headers);
|
||||
body?.Write(msgToSend);
|
||||
|
||||
ForwardToOwnerProcess(msgToSend);
|
||||
}
|
||||
|
||||
private static void ForwardToOwnerProcess(IWriteMessage msg)
|
||||
{
|
||||
byte[] bufToSend = (byte[])msg.Buffer.Clone();
|
||||
Array.Resize(ref bufToSend, msg.LengthBytes);
|
||||
ChildServerRelay.Write(bufToSend);
|
||||
}
|
||||
|
||||
protected override void ProcessAuthTicket(string name, Option<int> ownKey, Option<SteamId> steamId, PendingClient pendingClient, byte[] ticket)
|
||||
protected override void ProcessAuthTicket(ClientSteamTicketAndVersionPacket packet, PendingClient pendingClient)
|
||||
{
|
||||
pendingClient.InitializationStep = serverSettings.HasPassword ? ConnectionInitialization.Password : ConnectionInitialization.ContentPackageOrder;
|
||||
|
||||
pendingClient.Name = name;
|
||||
pendingClient.Name = packet.Name;
|
||||
pendingClient.AuthSessionStarted = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user