diff --git a/SteamKit2/SteamKit2/Base/ClientMsg.cs b/SteamKit2/SteamKit2/Base/ClientMsg.cs index ceef49be3..689cc556e 100644 --- a/SteamKit2/SteamKit2/Base/ClientMsg.cs +++ b/SteamKit2/SteamKit2/Base/ClientMsg.cs @@ -109,9 +109,12 @@ internal ClientMsgProtobuf( EMsg eMsg, int payloadReserve = 64 ) public ClientMsgProtobuf( IPacketMsg msg ) : this( msg.GetMsgTypeWithNullCheck( nameof(msg) ) ) { - DebugLog.Assert(msg.IsProto, "ClientMsgProtobuf", "ClientMsgProtobuf used for non-proto message!"); + if ( !( msg is PacketClientMsgProtobuf packetMsgProto ) ) + { + throw new InvalidDataException( "ClientMsgProtobuf used for non-proto message!" ); + } - Deserialize( msg.GetData() ); + Header = packetMsgProto.Header; } @@ -123,21 +126,6 @@ public override byte[] Serialize() { throw new NotSupportedException( "ClientMsgProtobuf is for reading only. Use ClientMsgProtobuf for serializing messages." ); } - - /// - /// Initializes this client message by deserializing the specified data. - /// - /// The data representing a client message. - public override void Deserialize( byte[] data ) - { - if ( data == null ) - { - throw new ArgumentNullException( nameof(data) ); - } - - using MemoryStream ms = new MemoryStream( data ); - Header.Deserialize( ms ); - } } /// @@ -147,10 +135,16 @@ public override void Deserialize( byte[] data ) public sealed class ClientMsgProtobuf : ClientMsgProtobuf where TBody : IExtensible, new() { + private TBody _body; + /// /// Gets the body structure of this message. /// - public TBody Body { get; private set; } + public TBody Body + { + get => _body; + set => _body = value ?? throw new ArgumentNullException( nameof( value ) ); + } /// @@ -162,7 +156,7 @@ public sealed class ClientMsgProtobuf : ClientMsgProtobuf public ClientMsgProtobuf( EMsg eMsg, int payloadReserve = 64 ) : base( payloadReserve ) { - Body = new TBody(); + _body = new TBody(); // set our emsg Header.Msg = eMsg; @@ -190,9 +184,27 @@ public ClientMsgProtobuf( EMsg eMsg, MsgBase msg, int payloadRes public ClientMsgProtobuf( IPacketMsg msg ) : this( msg.GetMsgTypeWithNullCheck( nameof(msg) ) ) { - DebugLog.Assert( msg.IsProto, "ClientMsgProtobuf<>", $"ClientMsgProtobuf<{typeof(TBody).FullName}> used for non-proto message!" ); + if ( !( msg is PacketClientMsgProtobuf packetMsg ) ) + { + throw new InvalidDataException( $"ClientMsgProtobuf<{typeof(TBody).FullName}> used for non-proto message!" ); + } + + Header = packetMsg.Header; - Deserialize( msg.GetData() ); + var data = packetMsg.GetData(); + var offset = (int)packetMsg.BodyOffset; + using MemoryStream ms = new MemoryStream( data, offset, data.Length - offset ); + + Body = Serializer.Deserialize( ms ); + + // the rest of the data is the payload + int payloadLen = ( int )( ms.Length - ms.Position ); + + if ( payloadLen > 0 ) + { + ms.CopyTo( Payload, payloadLen ); + Payload.Seek( 0, SeekOrigin.Begin ); + } } /// @@ -210,28 +222,6 @@ public override byte[] Serialize() return ms.ToArray(); } - /// - /// Initializes this client message by deserializing the specified data. - /// - /// The data representing a client message. - public override void Deserialize( byte[] data ) - { - if ( data == null ) - { - throw new ArgumentNullException( nameof(data) ); - } - - using MemoryStream ms = new MemoryStream( data ); - Header.Deserialize( ms ); - Body = Serializer.Deserialize( ms ); - - // the rest of the data is the payload - int payloadOffset = ( int )ms.Position; - int payloadLen = ( int )( ms.Length - ms.Position ); - - Payload.Write( data, payloadOffset, payloadLen ); - Payload.Seek( 0, SeekOrigin.Begin ); - } } /// @@ -357,9 +347,27 @@ public ClientMsg( IPacketMsg msg ) throw new ArgumentNullException( nameof(msg) ); } - DebugLog.Assert( !msg.IsProto, "ClientMsg", $"ClientMsg<{typeof(TBody).FullName}> used for proto message!" ); + if ( !( msg is PacketClientMsg packetMsg ) ) + { + throw new InvalidDataException( $"ClientMsg<{typeof( TBody ).FullName}> used for proto message!" ); + } + + Header = packetMsg.Header; + + var data = packetMsg.GetData(); + var offset = (int)packetMsg.BodyOffset; + using MemoryStream ms = new MemoryStream( data, offset, data.Length - offset ); + + Body.Deserialize( ms ); - Deserialize( msg.GetData() ); + // the rest of the data is the payload + int payloadLen = ( int )( ms.Length - ms.Position ); + + if ( payloadLen > 0 ) + { + ms.CopyTo( Payload, payloadLen ); + Payload.Seek( 0, SeekOrigin.Begin ); + } } /// @@ -377,28 +385,6 @@ public override byte[] Serialize() return ms.ToArray(); } - /// - /// Initializes this client message by deserializing the specified data. - /// - /// The data representing a client message. - public override void Deserialize( byte[] data ) - { - if ( data == null ) - { - throw new ArgumentNullException( nameof(data) ); - } - - using MemoryStream ms = new MemoryStream( data ); - Header.Deserialize( ms ); - Body.Deserialize( ms ); - - // the rest of the data is the payload - int payloadOffset = ( int )ms.Position; - int payloadLen = ( int )( ms.Length - ms.Position ); - - Payload.Write( data, payloadOffset, payloadLen ); - Payload.Seek( 0, SeekOrigin.Begin ); - } } /// @@ -515,7 +501,27 @@ public Msg( IPacketMsg msg ) throw new ArgumentNullException( nameof(msg) ); } - Deserialize( msg.GetData() ); + if ( !( msg is PacketMsg packetMsg ) ) + { + throw new InvalidDataException( $"ClientMsg<{typeof( TBody ).FullName}> used for proto message!" ); + } + + Header = packetMsg.Header; + + var data = packetMsg.GetData(); + var offset = (int)packetMsg.BodyOffset; + using MemoryStream ms = new MemoryStream( data, offset, data.Length - offset ); + + Body.Deserialize( ms ); + + // the rest of the data is the payload + int payloadLen = ( int )( ms.Length - ms.Position ); + + if ( payloadLen > 0 ) + { + ms.CopyTo( Payload, payloadLen ); + Payload.Seek( 0, SeekOrigin.Begin ); + } } @@ -534,28 +540,5 @@ public override byte[] Serialize() return ms.ToArray(); } - /// - /// Initializes this client message by deserializing the specified data. - /// - /// The data representing a client message. - public override void Deserialize( byte[] data ) - { - if ( data == null ) - { - throw new ArgumentNullException( nameof(data) ); - } - - using MemoryStream ms = new MemoryStream( data ); - Header.Deserialize( ms ); - Body.Deserialize( ms ); - - // the rest of the data is the payload - int payloadOffset = ( int )ms.Position; - int payloadLen = ( int )( ms.Length - ms.Position ); - - Payload.Write( data, payloadOffset, payloadLen ); - Payload.Seek( 0, SeekOrigin.Begin ); - } - } } diff --git a/SteamKit2/SteamKit2/Base/MsgBase.cs b/SteamKit2/SteamKit2/Base/MsgBase.cs index 880812d4e..a3b66c012 100644 --- a/SteamKit2/SteamKit2/Base/MsgBase.cs +++ b/SteamKit2/SteamKit2/Base/MsgBase.cs @@ -65,11 +65,6 @@ public interface IClientMsg /// /// Data representing a client message. byte[] Serialize(); - /// - /// Initializes this client message by deserializing the specified data. - /// - /// The data representing a client message. - void Deserialize( byte[] data ); } /// @@ -492,7 +487,7 @@ public abstract class MsgBase : MsgBase, IClientMsg /// /// Gets the header for this message type. /// - public THeader Header { get; } + public THeader Header { get; internal set; } /// @@ -513,11 +508,5 @@ public MsgBase( int payloadReserve = 0 ) /// Data representing a client message. /// public abstract byte[] Serialize(); - /// - /// Initializes this client message by deserializing the specified data. - /// - /// The data representing a client message. - public abstract void Deserialize( byte[] data ); - } } diff --git a/SteamKit2/SteamKit2/Base/PacketBase.cs b/SteamKit2/SteamKit2/Base/PacketBase.cs index c98030569..a4648d292 100644 --- a/SteamKit2/SteamKit2/Base/PacketBase.cs +++ b/SteamKit2/SteamKit2/Base/PacketBase.cs @@ -80,7 +80,7 @@ public sealed class PacketClientMsgProtobuf : IPacketMsg /// /// true if this instance is protobuf backed; otherwise, false. /// - public bool IsProto { get { return true; } } + public bool IsProto => true; /// /// Gets the network message type of this packet message. /// @@ -95,15 +95,28 @@ public sealed class PacketClientMsgProtobuf : IPacketMsg /// /// The target job id. /// - public ulong TargetJobID { get; } + public ulong TargetJobID => Header.Proto.jobid_target; /// /// Gets the source job id for this packet message. /// /// /// The source job id. /// - public ulong SourceJobID { get; } - + public ulong SourceJobID => Header.Proto.jobid_source; + /// + /// Gets the header for this packet message. + /// + /// + /// The header. + /// + internal MsgHdrProtoBuf Header; + /// + /// Gets the offset in payload to the body after the header. + /// + /// + /// The offset in payload after the header. + /// + internal long BodyOffset; byte[] payload; @@ -123,16 +136,12 @@ public PacketClientMsgProtobuf( EMsg eMsg, byte[] data ) MsgType = eMsg; payload = data; - MsgHdrProtoBuf protobufHeader = new MsgHdrProtoBuf(); + Header = new MsgHdrProtoBuf(); // we need to pull out the job ids, so we deserialize the protobuf header - using ( MemoryStream ms = new MemoryStream( data ) ) - { - protobufHeader.Deserialize( ms ); - } - - TargetJobID = protobufHeader.Proto.jobid_target; - SourceJobID = protobufHeader.Proto.jobid_source; + using MemoryStream ms = new MemoryStream( data ); + Header.Deserialize( ms ); + BodyOffset = ms.Position; } @@ -173,14 +182,28 @@ public sealed class PacketClientMsg : IPacketMsg /// /// The target job id. /// - public ulong TargetJobID { get; } + public ulong TargetJobID => Header.TargetJobID; /// /// Gets the source job id for this packet message. /// /// /// The source job id. /// - public ulong SourceJobID { get; } + public ulong SourceJobID => Header.SourceJobID; + /// + /// Gets the header for this packet message. + /// + /// + /// The header. + /// + internal ExtendedClientMsgHdr Header; + /// + /// Gets the offset in payload to the body after the header. + /// + /// + /// The offset in payload after the header. + /// + internal long BodyOffset; byte[] payload; @@ -200,16 +223,12 @@ public PacketClientMsg( EMsg eMsg, byte[] data ) MsgType = eMsg; payload = data; - ExtendedClientMsgHdr extendedHdr = new ExtendedClientMsgHdr(); + Header = new ExtendedClientMsgHdr(); // deserialize the extended header to get our hands on the job ids - using ( MemoryStream ms = new MemoryStream( data ) ) - { - extendedHdr.Deserialize( ms ); - } - - TargetJobID = extendedHdr.TargetJobID; - SourceJobID = extendedHdr.SourceJobID; + using MemoryStream ms = new MemoryStream( data ); + Header.Deserialize( ms ); + BodyOffset = ms.Position; } @@ -250,14 +269,28 @@ public sealed class PacketMsg : IPacketMsg /// /// The target job id. /// - public ulong TargetJobID { get; } + public ulong TargetJobID => Header.TargetJobID; /// /// Gets the source job id for this packet message. /// /// /// The source job id. /// - public ulong SourceJobID { get; } + public ulong SourceJobID => Header.SourceJobID; + /// + /// Gets the header for this packet message. + /// + /// + /// The header. + /// + internal MsgHdr Header; + /// + /// Gets the offset in payload to the body after the header. + /// + /// + /// The offset in payload after the header. + /// + internal long BodyOffset; byte[] payload; @@ -277,16 +310,12 @@ public PacketMsg( EMsg eMsg, byte[] data ) MsgType = eMsg; payload = data; - MsgHdr msgHdr = new MsgHdr(); + Header = new MsgHdr(); // deserialize the header to get our hands on the job ids - using ( MemoryStream ms = new MemoryStream( data ) ) - { - msgHdr.Deserialize( ms ); - } - - TargetJobID = msgHdr.TargetJobID; - SourceJobID = msgHdr.SourceJobID; + using MemoryStream ms = new MemoryStream( data ); + Header.Deserialize( ms ); + BodyOffset = ms.Position; } diff --git a/SteamKit2/SteamKit2/Steam/Handlers/SteamUnifiedMessages/Callbacks.cs b/SteamKit2/SteamKit2/Steam/Handlers/SteamUnifiedMessages/Callbacks.cs index a979a1deb..a7884f911 100644 --- a/SteamKit2/SteamKit2/Steam/Handlers/SteamUnifiedMessages/Callbacks.cs +++ b/SteamKit2/SteamKit2/Steam/Handlers/SteamUnifiedMessages/Callbacks.cs @@ -4,10 +4,8 @@ */ using System; -using System.IO; using System.Reflection; using ProtoBuf; -using SteamKit2.Internal; namespace SteamKit2 { @@ -23,17 +21,12 @@ public class ServiceMethodResponse : CallbackMsg /// public EResult Result { get; private set; } - /// - /// Gets the raw binary response. - /// - public byte[] ResponseRaw { get; private set; } - /// /// Gets the name of the Service. /// public string ServiceName { - get { return MethodName.Split( '.' )[0]; } + get { return MethodName.Split( '.' )[ 0 ]; } } /// @@ -41,7 +34,7 @@ public string ServiceName /// public string RpcName { - get { return MethodName.Substring( ServiceName.Length + 1 ).Split( '#' )[0]; } + get { return MethodName.Substring( ServiceName.Length + 1 ).Split( '#' )[ 0 ]; } } /// @@ -49,14 +42,15 @@ public string RpcName /// public string MethodName { get; private set; } + private PacketClientMsgProtobuf PacketMsg; - internal ServiceMethodResponse( JobID jobID, EResult result, CMsgClientServiceMethodLegacyResponse resp ) + internal ServiceMethodResponse( PacketClientMsgProtobuf packetMsg ) { - JobID = jobID; - - Result = result; - ResponseRaw = resp.serialized_method_response; - MethodName = resp.method_name ?? string.Empty; + var protoHeader = packetMsg.Header.Proto; + JobID = protoHeader.jobid_target; + Result = ( EResult )protoHeader.eresult; + MethodName = protoHeader.target_job_name; + PacketMsg = packetMsg; } @@ -66,10 +60,10 @@ internal ServiceMethodResponse( JobID jobID, EResult result, CMsgClientServiceMe /// Protobuf type of the response message. /// The response to the message sent through . public T GetDeserializedResponse() - where T : IExtensible + where T : IExtensible, new() { - using var ms = new MemoryStream( ResponseRaw ); - return Serializer.Deserialize( ms ); + var msg = new ClientMsgProtobuf( PacketMsg ); + return msg.Body; } } @@ -83,7 +77,7 @@ public class ServiceMethodNotification : CallbackMsg /// public string ServiceName { - get { return MethodName.Split( '.' )[0]; } + get { return MethodName.Split( '.' )[ 0 ]; } } /// @@ -91,7 +85,7 @@ public string ServiceName /// public string RpcName { - get { return MethodName.Substring( ServiceName.Length + 1 ).Split( '#' )[0]; } + get { return MethodName.Substring( ServiceName.Length + 1 ).Split( '#' )[ 0 ]; } } /// diff --git a/SteamKit2/SteamKit2/Steam/Handlers/SteamUnifiedMessages/SteamUnifiedMessages.cs b/SteamKit2/SteamKit2/Steam/Handlers/SteamUnifiedMessages/SteamUnifiedMessages.cs index 505df00d3..d2c9b5515 100644 --- a/SteamKit2/SteamKit2/Steam/Handlers/SteamUnifiedMessages/SteamUnifiedMessages.cs +++ b/SteamKit2/SteamKit2/Steam/Handlers/SteamUnifiedMessages/SteamUnifiedMessages.cs @@ -10,7 +10,6 @@ using System.Linq; using System.Linq.Expressions; using ProtoBuf; -using SteamKit2.Internal; namespace SteamKit2 { @@ -105,7 +104,7 @@ internal SteamUnifiedMessages() { dispatchMap = new Dictionary> { - { EMsg.ClientServiceMethodLegacyResponse, HandleClientServiceMethodResponse }, + { EMsg.ServiceMethodResponse, HandleServiceMethodResponse }, { EMsg.ServiceMethod, HandleServiceMethod }, }; } @@ -121,25 +120,17 @@ internal SteamUnifiedMessages() /// Whether this message is a notification or not. /// The JobID of the request. This can be used to find the appropriate . public AsyncJob SendMessage( string name, TRequest message, bool isNotification = false ) - where TRequest : IExtensible + where TRequest : IExtensible, new() { if ( message == null ) { throw new ArgumentNullException( nameof(message) ); } - var msg = new ClientMsgProtobuf( EMsg.ClientServiceMethodLegacy ); + var msg = new ClientMsgProtobuf( isNotification ? EMsg.ServiceMethodSendToClient : EMsg.ServiceMethodCallFromClient ); msg.SourceJobID = Client.GetNextJobID(); - - using ( var ms = new MemoryStream() ) - { - Serializer.Serialize( ms, message ); - msg.Body.serialized_method = ms.ToArray(); - } - - msg.Body.method_name = name; - msg.Body.is_notification = isNotification; - + msg.Header.Proto.target_job_name = name; + msg.Body = message; Client.Send( msg ); return new AsyncJob( this.Client, msg.SourceJobID ); @@ -178,18 +169,25 @@ public override void HandleMsg( IPacketMsg packetMsg ) #region ClientMsg Handlers - void HandleClientServiceMethodResponse( IPacketMsg packetMsg ) + void HandleServiceMethodResponse( IPacketMsg packetMsg ) { - var response = new ClientMsgProtobuf( packetMsg ); - var callback = new ServiceMethodResponse(response.TargetJobID, (EResult)response.ProtoHeader.eresult, response.Body); + if ( !( packetMsg is PacketClientMsgProtobuf packetMsgProto ) ) + { + throw new InvalidDataException( "Packet message is expected to be protobuf." ); + } + + var callback = new ServiceMethodResponse( packetMsgProto ); Client.PostCallback( callback ); } void HandleServiceMethod( IPacketMsg packetMsg ) { - var notification = new ClientMsgProtobuf( packetMsg ); + if ( !( packetMsg is PacketClientMsgProtobuf packetMsgProto ) ) + { + throw new InvalidDataException( "Packet message is expected to be protobuf." ); + } - var jobName = notification.Header.Proto.target_job_name; + var jobName = packetMsgProto.Header.Proto.target_job_name; if ( !string.IsNullOrEmpty( jobName ) ) { var splitByDot = jobName.Split( '.' );