From c6232f20f933e256fc4d309560abe95521356c56 Mon Sep 17 00:00:00 2001 From: Paul Chote Date: Fri, 31 May 2019 19:03:49 +0000 Subject: [PATCH] Split Protocol version into Handshake vs Orders. Handshake is kept at 7. Orders is incremented to 8 to reflect immediate order changes. --- OpenRA.Game/Network/Connection.cs | 8 ++++---- OpenRA.Game/Network/Handshake.cs | 6 +++++- OpenRA.Game/Network/UnitOrders.cs | 3 ++- OpenRA.Game/Server/ProtocolVersion.cs | 10 ++++++++-- OpenRA.Game/Server/Server.cs | 12 +++++++++++- 5 files changed, 30 insertions(+), 9 deletions(-) diff --git a/OpenRA.Game/Network/Connection.cs b/OpenRA.Game/Network/Connection.cs index abc4707479..2993a103d3 100644 --- a/OpenRA.Game/Network/Connection.cs +++ b/OpenRA.Game/Network/Connection.cs @@ -167,12 +167,12 @@ namespace OpenRA.Network { var networkStream = (NetworkStream)networkStreamObject; var reader = new BinaryReader(networkStream); - var serverProtocol = reader.ReadInt32(); + var handshakeProtocol = reader.ReadInt32(); - if (serverProtocol != ProtocolVersion.Version) + if (handshakeProtocol != ProtocolVersion.Handshake) throw new InvalidOperationException( - "Protocol version mismatch. Server={0} Client={1}" - .F(serverProtocol, ProtocolVersion.Version)); + "Handshake protocol version mismatch. Server={0} Client={1}" + .F(handshakeProtocol, ProtocolVersion.Handshake)); clientId = reader.ReadInt32(); connectionState = ConnectionState.Connected; diff --git a/OpenRA.Game/Network/Handshake.cs b/OpenRA.Game/Network/Handshake.cs index f77eb18f74..b420722a45 100644 --- a/OpenRA.Game/Network/Handshake.cs +++ b/OpenRA.Game/Network/Handshake.cs @@ -41,6 +41,10 @@ namespace OpenRA.Network public string Version; public string Password; + // Default value is hardcoded to 7 so that newer servers + // (which define OrdersProtocol > 7) can detect older clients + public int OrdersProtocol = 7; + // For player authentication public string Fingerprint; public string AuthSignature; @@ -74,7 +78,7 @@ namespace OpenRA.Network { var data = new List(); data.Add(new MiniYamlNode("Handshake", null, - new string[] { "Mod", "Version", "Password", "Fingerprint", "AuthSignature" }.Select(p => FieldSaver.SaveField(this, p)).ToList())); + new[] { "Mod", "Version", "Password", "Fingerprint", "AuthSignature", "OrdersProtocol" }.Select(p => FieldSaver.SaveField(this, p)).ToList())); data.Add(new MiniYamlNode("Client", FieldSaver.Save(Client))); return data.WriteToString(); diff --git a/OpenRA.Game/Network/UnitOrders.cs b/OpenRA.Game/Network/UnitOrders.cs index 9e24a94e69..c3536c357f 100644 --- a/OpenRA.Game/Network/UnitOrders.cs +++ b/OpenRA.Game/Network/UnitOrders.cs @@ -227,7 +227,8 @@ namespace OpenRA.Network Mod = mod.Id, Version = mod.Metadata.Version, Password = orderManager.Password, - Fingerprint = localProfile.Fingerprint + Fingerprint = localProfile.Fingerprint, + OrdersProtocol = ProtocolVersion.Orders }; if (request.AuthToken != null && response.Fingerprint != null) diff --git a/OpenRA.Game/Server/ProtocolVersion.cs b/OpenRA.Game/Server/ProtocolVersion.cs index b8ca4c29b3..755466ec6e 100644 --- a/OpenRA.Game/Server/ProtocolVersion.cs +++ b/OpenRA.Game/Server/ProtocolVersion.cs @@ -13,7 +13,13 @@ namespace OpenRA.Server { public static class ProtocolVersion { - // you *must* increment this whenever you make an incompatible protocol change - public static readonly int Version = 7; + // The protocol for the initial handshake request and response + // Backwards incompatible changes will break runtime mod switching, so only change as a last resort! + public const int Handshake = 7; + + // The protocol for server and world orders + // This applies after the handshake has completed, and is provided to support + // alternative server implementations that wish to support multiple versions in parallel + public const int Orders = 8; } } diff --git a/OpenRA.Game/Server/Server.cs b/OpenRA.Game/Server/Server.cs index ffd1721a41..842fea995d 100644 --- a/OpenRA.Game/Server/Server.cs +++ b/OpenRA.Game/Server/Server.cs @@ -278,7 +278,7 @@ namespace OpenRA.Server // Send handshake and client index. var ms = new MemoryStream(8); - ms.WriteArray(BitConverter.GetBytes(ProtocolVersion.Version)); + ms.WriteArray(BitConverter.GetBytes(ProtocolVersion.Handshake)); ms.WriteArray(BitConverter.GetBytes(newConn.PlayerIndex)); SendData(newConn.Socket, ms.ToArray()); @@ -363,6 +363,16 @@ namespace OpenRA.Server return; } + if (handshake.OrdersProtocol != ProtocolVersion.Orders) + { + Log.Write("server", "Rejected connection from {0}; incompatible Orders protocol version {1}.", + newConn.Socket.RemoteEndPoint, handshake.OrdersProtocol); + + SendOrderTo(newConn, "ServerError", "Server is running an incompatible protocol"); + DropClient(newConn); + return; + } + // Check if IP is banned var bans = Settings.Ban.Union(TempBans); if (bans.Contains(client.IpAddress))