Merge ServerOrder into Order and 0xFE order type into 0xFF.

This commit is contained in:
Paul Chote
2019-05-11 15:58:17 +00:00
committed by abcdefg30
parent 90ebffc6c0
commit 862a274357
7 changed files with 73 additions and 185 deletions

View File

@@ -230,7 +230,7 @@ namespace OpenRA.Network
foreach (var kv in TraitData) foreach (var kv in TraitData)
{ {
var data = new List<MiniYamlNode>() { new MiniYamlNode(kv.Key.ToString(), kv.Value) }.WriteToString(); var data = new List<MiniYamlNode>() { new MiniYamlNode(kv.Key.ToString(), kv.Value) }.WriteToString();
packetFn(0, 0, new ServerOrder("SaveTraitData", data).Serialize()); packetFn(0, 0, Order.FromTargetString("SaveTraitData", data, true).Serialize());
} }
ordersStream.Seek(0, SeekOrigin.Begin); ordersStream.Seek(0, SeekOrigin.Begin);

View File

@@ -19,12 +19,14 @@ namespace OpenRA
[Flags] [Flags]
enum OrderFields : byte enum OrderFields : byte
{ {
None = 0x0,
Target = 0x01, Target = 0x01,
TargetString = 0x04, TargetString = 0x04,
Queued = 0x08, Queued = 0x08,
ExtraLocation = 0x10, ExtraLocation = 0x10,
ExtraData = 0x20, ExtraData = 0x20,
TargetIsCell = 0x40 TargetIsCell = 0x40,
Subject = 0x80
} }
static class OrderFieldsExts static class OrderFieldsExts
@@ -72,12 +74,15 @@ namespace OpenRA
case 0xFF: case 0xFF:
{ {
var order = r.ReadString(); var order = r.ReadString();
var subjectId = r.ReadUInt32();
var flags = (OrderFields)r.ReadByte(); var flags = (OrderFields)r.ReadByte();
Actor subject = null; Actor subject = null;
if (world != null) if (flags.HasField(OrderFields.Subject))
TryGetActorFromUInt(world, subjectId, out subject); {
var subjectId = r.ReadUInt32();
if (world != null)
TryGetActorFromUInt(world, subjectId, out subject);
}
var target = Target.Invalid; var target = Target.Invalid;
if (flags.HasField(OrderFields.Target)) if (flags.HasField(OrderFields.Target))
@@ -139,22 +144,12 @@ namespace OpenRA
if (world == null) if (world == null)
return new Order(order, null, target, targetString, queued, extraLocation, extraData); return new Order(order, null, target, targetString, queued, extraLocation, extraData);
if (subject == null && subjectId != uint.MaxValue) if (subject == null && flags.HasField(OrderFields.Subject))
return null; return null;
return new Order(order, subject, target, targetString, queued, extraLocation, extraData); return new Order(order, subject, target, targetString, queued, extraLocation, extraData);
} }
case 0xfe:
{
var name = r.ReadString();
var flags = (OrderFields)r.ReadByte();
var targetString = flags.HasField(OrderFields.TargetString) ? r.ReadString() : null;
var extraData = flags.HasField(OrderFields.ExtraData) ? r.ReadUInt32() : 0;
return new Order(name, null, false) { IsImmediate = true, TargetString = targetString, ExtraData = extraData };
}
default: default:
{ {
Log.Write("debug", "Received unknown order with magic {0}", magic); Log.Write("debug", "Received unknown order with magic {0}", magic);
@@ -200,19 +195,9 @@ namespace OpenRA
return new Order("Chat", null, false) { IsImmediate = true, TargetString = text, ExtraData = teamNumber }; return new Order("Chat", null, false) { IsImmediate = true, TargetString = text, ExtraData = teamNumber };
} }
public static Order HandshakeResponse(string text) public static Order FromTargetString(string order, string targetString, bool isImmediate)
{ {
return new Order("HandshakeResponse", null, false) { IsImmediate = true, TargetString = text }; return new Order(order, null, false) { IsImmediate = isImmediate, TargetString = targetString };
}
public static Order Pong(string pingTime)
{
return new Order("Pong", null, false) { IsImmediate = true, TargetString = pingTime };
}
public static Order PauseGame(bool paused)
{
return new Order("PauseGame", null, false) { TargetString = paused ? "Pause" : "UnPause" };
} }
public static Order Command(string text) public static Order Command(string text)
@@ -247,36 +232,23 @@ namespace OpenRA
public byte[] Serialize() public byte[] Serialize()
{ {
var minLength = OrderString.Length + 1 + (IsImmediate ? 1 + 1 + TargetString.Length + 1 + 4 : 6); var minLength = 1 + OrderString.Length + 1 + 4 + 1 + 13 + (TargetString != null ? TargetString.Length + 1 : 0) + 4 + 4;
var ret = new MemoryStream(minLength); var ret = new MemoryStream(minLength);
var w = new BinaryWriter(ret); var w = new BinaryWriter(ret);
OrderFields fields = 0; w.Write((byte)0xFF);
w.Write(OrderString);
var fields = OrderFields.None;
if (Subject != null)
fields |= OrderFields.Subject;
if (TargetString != null) if (TargetString != null)
fields |= OrderFields.TargetString; fields |= OrderFields.TargetString;
if (ExtraData != 0) if (ExtraData != 0)
fields |= OrderFields.ExtraData; fields |= OrderFields.ExtraData;
if (IsImmediate)
{
w.Write((byte)0xFE);
w.Write(OrderString);
w.Write((byte)fields);
if (fields.HasField(OrderFields.TargetString))
w.Write(TargetString);
if (fields.HasField(OrderFields.ExtraData))
w.Write(ExtraData);
return ret.ToArray();
}
w.Write((byte)0xFF);
w.Write(OrderString);
w.Write(UIntFromActor(Subject));
if (Target.SerializableType != TargetType.Invalid) if (Target.SerializableType != TargetType.Invalid)
fields |= OrderFields.Target; fields |= OrderFields.Target;
@@ -291,6 +263,9 @@ namespace OpenRA
w.Write((byte)fields); w.Write((byte)fields);
if (fields.HasField(OrderFields.Subject))
w.Write(UIntFromActor(Subject));
if (fields.HasField(OrderFields.Target)) if (fields.HasField(OrderFields.Target))
{ {
w.Write((byte)Target.SerializableType); w.Write((byte)Target.SerializableType);

View File

@@ -13,6 +13,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using OpenRA.Primitives; using OpenRA.Primitives;
using OpenRA.Server;
using OpenRA.Traits; using OpenRA.Traits;
namespace OpenRA.Network namespace OpenRA.Network
@@ -232,7 +233,12 @@ namespace OpenRA.Network
if (request.AuthToken != null && response.Fingerprint != null) if (request.AuthToken != null && response.Fingerprint != null)
response.AuthSignature = localProfile.Sign(request.AuthToken); response.AuthSignature = localProfile.Sign(request.AuthToken);
orderManager.IssueOrder(Order.HandshakeResponse(response.Serialize())); orderManager.IssueOrder(new Order("HandshakeResponse", null, false)
{
IsImmediate = true,
TargetString = response.Serialize()
});
break; break;
} }
@@ -326,19 +332,15 @@ namespace OpenRA.Network
case "Ping": case "Ping":
{ {
orderManager.IssueOrder(Order.Pong(order.TargetString)); orderManager.IssueOrder(Order.FromTargetString("Pong", order.TargetString, true));
break; break;
} }
default: default:
{ {
if (!order.IsImmediate) if (order.Subject != null && !order.Subject.IsDead)
{ foreach (var t in order.Subject.TraitsImplementing<IResolveOrder>())
var self = order.Subject; t.ResolveOrder(order.Subject, order);
if (!self.IsDead)
foreach (var t in self.TraitsImplementing<IResolveOrder>())
t.ResolveOrder(self, order);
}
break; break;
} }

View File

@@ -292,7 +292,11 @@ namespace OpenRA.Server
AuthToken = token AuthToken = token
}; };
DispatchOrdersToClient(newConn, 0, 0, new ServerOrder("HandshakeRequest", request.Serialize()).Serialize()); DispatchOrdersToClient(newConn, 0, 0, new Order("HandshakeRequest", null, false)
{
IsImmediate = true,
TargetString = request.Serialize()
}.Serialize());
} }
catch (Exception e) catch (Exception e)
{ {
@@ -579,9 +583,9 @@ namespace OpenRA.Server
{ {
while (ms.Position < ms.Length) while (ms.Position < ms.Length)
{ {
var so = ServerOrder.Deserialize(br); var o = Order.Deserialize(null, br);
if (so == null) return; if (o != null)
InterpretServerOrder(conn, so); InterpretServerOrder(conn, o);
} }
} }
catch (EndOfStreamException) { } catch (EndOfStreamException) { }
@@ -590,29 +594,29 @@ namespace OpenRA.Server
public void SendOrderTo(Connection conn, string order, string data) public void SendOrderTo(Connection conn, string order, string data)
{ {
DispatchOrdersToClient(conn, 0, 0, new ServerOrder(order, data).Serialize()); DispatchOrdersToClient(conn, 0, 0, Order.FromTargetString(order, data, true).Serialize());
} }
public void SendMessage(string text, Connection conn = null) public void SendMessage(string text, Connection conn = null)
{ {
DispatchOrdersToClients(conn, 0, new ServerOrder("Message", text).Serialize()); DispatchOrdersToClients(conn, 0, Order.FromTargetString("Message", text, true).Serialize());
if (Dedicated) if (Dedicated)
Console.WriteLine("[{0}] {1}".F(DateTime.Now.ToString(Settings.TimestampFormat), text)); Console.WriteLine("[{0}] {1}".F(DateTime.Now.ToString(Settings.TimestampFormat), text));
} }
void InterpretServerOrder(Connection conn, ServerOrder so) void InterpretServerOrder(Connection conn, Order o)
{ {
// Only accept handshake responses from unvalidated clients // Only accept handshake responses from unvalidated clients
// Anything else may be an attempt to exploit the server // Anything else may be an attempt to exploit the server
if (!conn.Validated) if (!conn.Validated)
{ {
if (so.Name == "HandshakeResponse") if (o.OrderString == "HandshakeResponse")
ValidateClient(conn, so.Data); ValidateClient(conn, o.TargetString);
else else
{ {
Log.Write("server", "Rejected connection from {0}; Order `{1}` is not a `HandshakeResponse`.", Log.Write("server", "Rejected connection from {0}; Order `{1}` is not a `HandshakeResponse`.",
conn.Socket.RemoteEndPoint, so.Name); conn.Socket.RemoteEndPoint, o.OrderString);
DropClient(conn); DropClient(conn);
} }
@@ -620,31 +624,31 @@ namespace OpenRA.Server
return; return;
} }
switch (so.Name) switch (o.OrderString)
{ {
case "Command": case "Command":
{ {
var handledBy = serverTraits.WithInterface<IInterpretCommand>() var handledBy = serverTraits.WithInterface<IInterpretCommand>()
.FirstOrDefault(t => t.InterpretCommand(this, conn, GetClient(conn), so.Data)); .FirstOrDefault(t => t.InterpretCommand(this, conn, GetClient(conn), o.TargetString));
if (handledBy == null) if (handledBy == null)
{ {
Log.Write("server", "Unknown server command: {0}", so.Data); Log.Write("server", "Unknown server command: {0}", o.TargetString);
SendOrderTo(conn, "Message", "Unknown server command: {0}".F(so.Data)); SendOrderTo(conn, "Message", "Unknown server command: {0}".F(o.TargetString));
} }
break; break;
} }
case "Chat": case "Chat":
DispatchOrdersToClients(conn, 0, so.Serialize()); DispatchOrdersToClients(conn, 0, o.Serialize());
break; break;
case "Pong": case "Pong":
{ {
long pingSent; long pingSent;
if (!OpenRA.Exts.TryParseInt64Invariant(so.Data, out pingSent)) if (!OpenRA.Exts.TryParseInt64Invariant(o.TargetString, out pingSent))
{ {
Log.Write("server", "Invalid order pong payload: {0}", so.Data); Log.Write("server", "Invalid order pong payload: {0}", o.TargetString);
break; break;
} }
@@ -676,7 +680,7 @@ namespace OpenRA.Server
{ {
if (GameSave != null) if (GameSave != null)
{ {
var data = MiniYaml.FromString(so.Data)[0]; var data = MiniYaml.FromString(o.TargetString)[0];
GameSave.AddTraitData(int.Parse(data.Key), data.Value); GameSave.AddTraitData(int.Parse(data.Key), data.Value);
} }
@@ -688,7 +692,7 @@ namespace OpenRA.Server
if (GameSave != null) if (GameSave != null)
{ {
// Sanitize potentially malicious input // Sanitize potentially malicious input
var filename = so.Data; var filename = o.TargetString;
var invalidIndex = -1; var invalidIndex = -1;
var invalidChars = Path.GetInvalidFileNameChars(); var invalidChars = Path.GetInvalidFileNameChars();
while ((invalidIndex = filename.IndexOfAny(invalidChars)) != -1) while ((invalidIndex = filename.IndexOfAny(invalidChars)) != -1)
@@ -704,7 +708,7 @@ namespace OpenRA.Server
Directory.CreateDirectory(baseSavePath); Directory.CreateDirectory(baseSavePath);
GameSave.Save(Path.Combine(baseSavePath, filename)); GameSave.Save(Path.Combine(baseSavePath, filename));
DispatchOrdersToClients(null, 0, new ServerOrder("GameSaved", filename).Serialize()); DispatchOrdersToClients(null, 0, Order.FromTargetString("GameSaved", filename, true).Serialize());
} }
break; break;
@@ -716,7 +720,7 @@ namespace OpenRA.Server
break; break;
// Sanitize potentially malicious input // Sanitize potentially malicious input
var filename = so.Data; var filename = o.TargetString;
var invalidIndex = -1; var invalidIndex = -1;
var invalidChars = Path.GetInvalidFileNameChars(); var invalidChars = Path.GetInvalidFileNameChars();
while ((invalidIndex = filename.IndexOfAny(invalidChars)) != -1) while ((invalidIndex = filename.IndexOfAny(invalidChars)) != -1)
@@ -808,7 +812,7 @@ namespace OpenRA.Server
SendMessage("{0}{1} has disconnected.".F(dropClient.Name, suffix)); SendMessage("{0}{1} has disconnected.".F(dropClient.Name, suffix));
// Send disconnected order, even if still in the lobby // Send disconnected order, even if still in the lobby
DispatchOrdersToClients(toDrop, 0, new ServerOrder("Disconnected", "").Serialize()); DispatchOrdersToClients(toDrop, 0, Order.FromTargetString("Disconnected", "", true).Serialize());
LobbyInfo.Clients.RemoveAll(c => c.Index == toDrop.PlayerIndex); LobbyInfo.Clients.RemoveAll(c => c.Index == toDrop.PlayerIndex);
LobbyInfo.ClientPings.RemoveAll(p => p.Index == toDrop.PlayerIndex); LobbyInfo.ClientPings.RemoveAll(p => p.Index == toDrop.PlayerIndex);
@@ -854,7 +858,7 @@ namespace OpenRA.Server
public void SyncLobbyInfo() public void SyncLobbyInfo()
{ {
if (State == ServerState.WaitingPlayers) // Don't do this while the game is running, it breaks things! if (State == ServerState.WaitingPlayers) // Don't do this while the game is running, it breaks things!
DispatchOrders(null, 0, new ServerOrder("SyncInfo", LobbyInfo.Serialize()).Serialize()); DispatchOrders(null, 0, Order.FromTargetString("SyncInfo", LobbyInfo.Serialize(), true).Serialize());
foreach (var t in serverTraits.WithInterface<INotifySyncLobbyInfo>()) foreach (var t in serverTraits.WithInterface<INotifySyncLobbyInfo>())
t.LobbyInfoSynced(this); t.LobbyInfoSynced(this);
@@ -868,7 +872,7 @@ namespace OpenRA.Server
// TODO: Only need to sync the specific client that has changed to avoid conflicts! // TODO: Only need to sync the specific client that has changed to avoid conflicts!
var clientData = LobbyInfo.Clients.Select(client => client.Serialize()).ToList(); var clientData = LobbyInfo.Clients.Select(client => client.Serialize()).ToList();
DispatchOrders(null, 0, new ServerOrder("SyncLobbyClients", clientData.WriteToString()).Serialize()); DispatchOrders(null, 0, Order.FromTargetString("SyncLobbyClients", clientData.WriteToString(), true).Serialize());
foreach (var t in serverTraits.WithInterface<INotifySyncLobbyInfo>()) foreach (var t in serverTraits.WithInterface<INotifySyncLobbyInfo>())
t.LobbyInfoSynced(this); t.LobbyInfoSynced(this);
@@ -882,7 +886,7 @@ namespace OpenRA.Server
// TODO: Don't sync all the slots if just one changed! // TODO: Don't sync all the slots if just one changed!
var slotData = LobbyInfo.Slots.Select(slot => slot.Value.Serialize()).ToList(); var slotData = LobbyInfo.Slots.Select(slot => slot.Value.Serialize()).ToList();
DispatchOrders(null, 0, new ServerOrder("SyncLobbySlots", slotData.WriteToString()).Serialize()); DispatchOrders(null, 0, Order.FromTargetString("SyncLobbySlots", slotData.WriteToString(), true).Serialize());
foreach (var t in serverTraits.WithInterface<INotifySyncLobbyInfo>()) foreach (var t in serverTraits.WithInterface<INotifySyncLobbyInfo>())
t.LobbyInfoSynced(this); t.LobbyInfoSynced(this);
@@ -895,7 +899,7 @@ namespace OpenRA.Server
var sessionData = new List<MiniYamlNode> { LobbyInfo.GlobalSettings.Serialize() }; var sessionData = new List<MiniYamlNode> { LobbyInfo.GlobalSettings.Serialize() };
DispatchOrders(null, 0, new ServerOrder("SyncLobbyGlobalSettings", sessionData.WriteToString()).Serialize()); DispatchOrders(null, 0, Order.FromTargetString("SyncLobbyGlobalSettings", sessionData.WriteToString(), true).Serialize());
foreach (var t in serverTraits.WithInterface<INotifySyncLobbyInfo>()) foreach (var t in serverTraits.WithInterface<INotifySyncLobbyInfo>())
t.LobbyInfoSynced(this); t.LobbyInfoSynced(this);
@@ -907,7 +911,7 @@ namespace OpenRA.Server
var clientPings = LobbyInfo.ClientPings.Select(ping => ping.Serialize()).ToList(); var clientPings = LobbyInfo.ClientPings.Select(ping => ping.Serialize()).ToList();
// Note that syncing pings doesn't trigger INotifySyncLobbyInfo // Note that syncing pings doesn't trigger INotifySyncLobbyInfo
DispatchOrders(null, 0, new ServerOrder("SyncClientPings", clientPings.WriteToString()).Serialize()); DispatchOrders(null, 0, Order.FromTargetString("SyncClientPings", clientPings.WriteToString(), true).Serialize());
} }
public void StartGame() public void StartGame()
@@ -960,7 +964,7 @@ namespace OpenRA.Server
} }
DispatchOrders(null, 0, DispatchOrders(null, 0,
new ServerOrder("StartGame", startGameData).Serialize()); Order.FromTargetString("StartGame", startGameData, true).Serialize());
foreach (var t in serverTraits.WithInterface<IStartGame>()) foreach (var t in serverTraits.WithInterface<IStartGame>())
t.GameStarted(this); t.GameStarted(this);

View File

@@ -1,82 +0,0 @@
#region Copyright & License Information
/*
* Copyright 2007-2019 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version. For more
* information, see COPYING.
*/
#endregion
using System;
using System.IO;
namespace OpenRA.Server
{
class ServerOrder
{
public readonly string Name;
public readonly string Data;
public readonly uint ExtraData;
public ServerOrder(string name, string data, uint extraData = 0)
{
Name = name;
Data = data;
ExtraData = extraData;
}
public static ServerOrder Deserialize(BinaryReader r)
{
byte b;
switch (b = r.ReadByte())
{
case 0xbf:
// Silently ignore disconnect notifications
return null;
case 0xff:
Console.WriteLine("This isn't a server order.");
return null;
case 0xfe:
{
var name = r.ReadString();
var flags = (OrderFields)r.ReadByte();
var data = flags.HasField(OrderFields.TargetString) ? r.ReadString() : null;
var extraData = flags.HasField(OrderFields.ExtraData) ? r.ReadUInt32() : 0;
return new ServerOrder(name, data, extraData);
}
default:
throw new NotImplementedException(b.ToString("x2"));
}
}
public byte[] Serialize()
{
var ms = new MemoryStream(1 + Name.Length + 1 + 1 + Data.Length + 1 + 4);
var bw = new BinaryWriter(ms);
OrderFields fields = 0;
if (Data != null)
fields |= OrderFields.TargetString;
if (ExtraData != 0)
fields |= OrderFields.ExtraData;
bw.Write((byte)0xfe);
bw.Write(Name);
bw.Write((byte)fields);
if (fields.HasField(OrderFields.TargetString))
bw.Write(Data);
if (fields.HasField(OrderFields.ExtraData))
bw.Write(ExtraData);
return ms.ToArray();
}
}
}

View File

@@ -135,7 +135,8 @@ namespace OpenRA
readonly GameInformation gameInfo; readonly GameInformation gameInfo;
public void IssueOrder(Order o) { OrderManager.IssueOrder(o); } /* avoid exposing the OM to mod code */ // Hide the OrderManager from mod code
public void IssueOrder(Order o) { OrderManager.IssueOrder(o); }
IOrderGenerator orderGenerator; IOrderGenerator orderGenerator;
public IOrderGenerator OrderGenerator public IOrderGenerator OrderGenerator
@@ -377,7 +378,7 @@ namespace OpenRA
if (PauseStateLocked) if (PauseStateLocked)
return; return;
IssueOrder(Order.PauseGame(paused)); IssueOrder(Order.FromTargetString("PauseGame", paused ? "Pause" : "UnPause", false));
PredictedPaused = paused; PredictedPaused = paused;
} }
@@ -523,21 +524,13 @@ namespace OpenRA
if (data != null) if (data != null)
{ {
var yaml = new List<MiniYamlNode>() { new MiniYamlNode(i.ToString(), new MiniYaml("", data)) }; var yaml = new List<MiniYamlNode>() { new MiniYamlNode(i.ToString(), new MiniYaml("", data)) };
IssueOrder(new Order("GameSaveTraitData", null, false) IssueOrder(Order.FromTargetString("GameSaveTraitData", yaml.WriteToString(), true));
{
IsImmediate = true,
TargetString = yaml.WriteToString()
});
} }
i++; i++;
} }
IssueOrder(new Order("CreateGameSave", null, false) IssueOrder(Order.FromTargetString("CreateGameSave", filename, true));
{
IsImmediate = true,
TargetString = filename
});
} }
public bool Disposing; public bool Disposing;

View File

@@ -290,11 +290,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
var orders = new List<Order>() var orders = new List<Order>()
{ {
new Order("LoadGameSave", null, false) Order.FromTargetString("LoadGameSave", Path.GetFileName(selectedSave), true),
{
IsImmediate = true,
TargetString = Path.GetFileName(selectedSave)
},
Order.Command("state {0}".F(Session.ClientState.Ready)) Order.Command("state {0}".F(Session.ClientState.Ready))
}; };