Refactoring RPC.Packets namespace to RPC.Messages and adding support for friends messages.

feature-npv2
Icedream 2014-05-08 10:25:43 +02:00
parent bc1e9ef662
commit 7724c5b221
33 changed files with 373 additions and 94 deletions

View File

@ -1,4 +1,5 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=ID/@EntryIndexedValue">ID</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=NP/@EntryIndexedValue">NP</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=NPID/@EntryIndexedValue">NPID</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=RPC/@EntryIndexedValue">RPC</s:String></wpf:ResourceDictionary>

View File

@ -6,7 +6,7 @@ using System.Threading;
using System.Threading.Tasks;
using log4net;
using NPSharp.RPC;
using NPSharp.RPC.Packets;
using NPSharp.RPC.Messages;
namespace NPSharp
{
@ -88,7 +88,7 @@ namespace NPSharp
_log.Debug("Disconnect() start");
_cancellationTokenSource.Cancel(true); // TODO: Find a cleaner way to cancel _processingTask (focus: _rpc.Read)
_procTask.Wait(_cancellationToken);
//_procTask.Wait(_cancellationToken);
_rpc.Close();
LoginId = 0;

View File

@ -1,10 +1,10 @@
using ProtoBuf;
namespace NPSharp.RPC.Packets
namespace NPSharp.RPC.Messages
{
[Packet(1006)]
[ProtoContract]
class AuthenticateExternalStatusMessage : RPCServerMessage
public sealed class AuthenticateExternalStatusMessage : RPCServerMessage
{
[ProtoMember(1)]
public int Status { get; set; }

View File

@ -1,10 +1,10 @@
using ProtoBuf;
namespace NPSharp.RPC.Packets
namespace NPSharp.RPC.Messages
{
[Packet(1010)]
[ProtoContract]
class AuthenticateResultMessage : RPCServerMessage
public sealed class AuthenticateResultMessage : RPCServerMessage
{
[ProtoMember(1)]
public int Result { get; set; }

View File

@ -1,10 +1,10 @@
using ProtoBuf;
namespace NPSharp.RPC.Packets
namespace NPSharp.RPC.Messages
{
[Packet(1003)]
[ProtoContract]
class AuthenticateWithTokenMessage : RPCClientMessage
public sealed class AuthenticateWithTokenMessage : RPCClientMessage
{
[ProtoMember(1)]
public string Token { get; set; }

View File

@ -1,10 +1,10 @@
using ProtoBuf;
namespace NPSharp.RPC.Packets
namespace NPSharp.RPC.Messages
{
[Packet(2001)]
[ProtoContract]
class CloseAppMessage : RPCServerMessage
public sealed class CloseAppMessage : RPCServerMessage
{
[ProtoMember(1)]
public string Reason { get; set; }

View File

@ -0,0 +1,17 @@
using System;
using ProtoBuf;
namespace NPSharp.RPC.Messages
{
[ProtoContract]
public sealed class FriendDetails
{
internal FriendDetails() { }
[ProtoMember(1)]
public UInt64 NPID { get; set; }
[ProtoMember(2)]
public string Name { get; set; }
}
}

View File

@ -0,0 +1,16 @@
using System;
using ProtoBuf;
namespace NPSharp.RPC.Messages
{
[ProtoContract]
[Packet(1202)]
public sealed class FriendsGetProfileDataMessage : RPCClientMessage
{
[ProtoMember(1)]
public UInt64[] IDs { get; set; }
[ProtoMember(2)]
public string ProfileType { get; set; }
}
}

View File

@ -0,0 +1,12 @@
using ProtoBuf;
namespace NPSharp.RPC.Messages
{
[ProtoContract]
[Packet(1203)]
public sealed class FriendsGetProfileDataResultMessage : RPCServerMessage
{
[ProtoMember(1)]
public ProfileDataResult[] Results { get; set; }
}
}

View File

@ -0,0 +1,13 @@
using System;
using ProtoBuf;
namespace NPSharp.RPC.Messages
{
[ProtoContract]
[Packet(1214)]
public sealed class FriendsGetUserAvatarMessage : RPCClientMessage
{
[ProtoMember(1)]
public Int32 Guid { get; set; }
}
}

View File

@ -0,0 +1,20 @@
using ProtoBuf;
namespace NPSharp.RPC.Messages
{
[ProtoContract]
[Packet(1215)]
public sealed class FriendsGetUserAvatarResultMessage : RPCServerMessage
{
internal FriendsGetUserAvatarResultMessage() { }
[ProtoMember(1)]
public int Result { get; internal set; }
[ProtoMember(2)]
public int Guid { get; internal set; }
[ProtoMember(3)]
public byte[] FileData { get; internal set; }
}
}

View File

@ -0,0 +1,18 @@
using ProtoBuf;
namespace NPSharp.RPC.Messages
{
[ProtoContract]
public sealed class FriendsPresence
{
internal FriendsPresence()
{
}
[ProtoMember(1)]
public string Key { get; set; }
[ProtoMember(2)]
public string Value { get; set; }
}
}

View File

@ -0,0 +1,26 @@
using System;
using ProtoBuf;
namespace NPSharp.RPC.Messages
{
[ProtoContract]
[Packet(1212)]
public sealed class FriendsPresenceMessage
{
internal FriendsPresenceMessage()
{
}
[ProtoMember(1)]
public UInt64 Friend { get; internal set; }
[ProtoMember(2)]
public Int32 PresenceState { get; internal set; }
[ProtoMember(3)]
public UInt64 CurrentServer { get; internal set; }
[ProtoMember(4)]
public FriendsPresence[] Presence { get; internal set; }
}
}

View File

@ -0,0 +1,14 @@
using ProtoBuf;
namespace NPSharp.RPC.Messages
{
[ProtoContract]
[Packet(1211)]
public sealed class FriendsRosterMessage : RPCServerMessage
{
internal FriendsRosterMessage() { }
[ProtoMember(1)]
public FriendDetails[] Friends { get; set; }
}
}

View File

@ -0,0 +1,12 @@
using ProtoBuf;
namespace NPSharp.RPC.Messages
{
[ProtoContract]
[Packet(1213)]
public sealed class FriendsSetPresenceMessage : RPCClientMessage
{
[ProtoMember(1)]
public FriendsPresence[] Presence { get; set; }
}
}

View File

@ -0,0 +1,13 @@
using System;
using ProtoBuf;
namespace NPSharp.RPC.Messages
{
[ProtoContract]
[Packet(1201)]
public sealed class FriendsSetSteamIDMessage : RPCClientMessage
{
[ProtoMember(1)]
public UInt64 SteamID { get; set; }
}
}

View File

@ -1,10 +1,10 @@
using ProtoBuf;
namespace NPSharp.RPC.Packets
namespace NPSharp.RPC.Messages
{
[Packet(1000)]
[ProtoContract]
class HelloMessage : RPCServerMessage
public sealed class HelloMessage : RPCServerMessage
{
// I seriously have no idea where in the code this is used but whatever
[ProtoMember(1)]

View File

@ -1,10 +1,10 @@
using ProtoBuf;
namespace NPSharp.RPC.Packets
namespace NPSharp.RPC.Messages
{
[Packet(2002)]
[ProtoContract]
class MessagingSendDataMessage : RPCClientMessage
public sealed class MessagingSendDataMessage : RPCClientMessage
{
[ProtoMember(1)]
public ulong NPID { get; set; }

View File

@ -1,8 +1,8 @@
using System;
namespace NPSharp.RPC.Packets
namespace NPSharp.RPC.Messages
{
class PacketAttribute : Attribute
internal sealed class PacketAttribute : Attribute
{
public PacketAttribute(uint type)
{

View File

@ -0,0 +1,17 @@
using System;
using ProtoBuf;
namespace NPSharp.RPC.Messages
{
[ProtoContract]
public sealed class ProfileDataResult
{
internal ProfileDataResult() { }
[ProtoMember(1)]
public UInt64 NPID { get; set; }
[ProtoMember(2)]
public byte[] Profile { get; set; }
}
}

View File

@ -0,0 +1,82 @@
using System;
using System.IO;
using log4net;
namespace NPSharp.RPC.Messages
{
public abstract class RPCClientMessage : RPCMessage
{
private static readonly ILog _log;
static RPCClientMessage()
{
_log = LogManager.GetLogger("RPCClientMessage");
}
public byte[] Serialize(uint id)
{
#if DEBUG
foreach (var prop in GetType().GetProperties())
{
Console.WriteLine("\t{0} = {1}", prop.Name, prop.GetValue(this));
}
#endif
byte[] content;
using (var bufferStream = new MemoryStream())
{
ProtoBuf.Serializer.Serialize(bufferStream, this);
bufferStream.Seek(0, SeekOrigin.Begin);
content = bufferStream.ToArray();
}
_log.DebugFormat("Serialized packet to {0} bytes", content.Length);
byte[] buffArray;
using (var ms = new MemoryStream())
{
using (var bw = new BinaryWriter(ms))
{
bw.Write(Signature);
bw.Write((uint)content.Length);
bw.Write(GetTypeId());
bw.Write(id);
bw.Write(content);
bw.Flush();
ms.Seek(0, SeekOrigin.Begin);
buffArray = ms.ToArray();
}
}
#if DEBUG
Console.Write("\t");
Console.ForegroundColor = ConsoleColor.Gray;
Console.Write(BitConverter.ToString(buffArray, 0, sizeof(uint)).Replace("-", ""));
Console.ResetColor();
Console.ForegroundColor = ConsoleColor.DarkRed;
Console.Write(BitConverter.ToString(buffArray, 1 * sizeof(uint), sizeof(uint)).Replace("-", ""));
Console.ResetColor();
Console.ForegroundColor = ConsoleColor.Green;
Console.Write(BitConverter.ToString(buffArray, 2 * sizeof(uint), sizeof(uint)).Replace("-", ""));
Console.ResetColor();
Console.ForegroundColor = ConsoleColor.Yellow;
Console.Write(BitConverter.ToString(buffArray, 3 * sizeof(uint), sizeof(uint)).Replace("-", ""));
Console.ResetColor();
Console.ForegroundColor = ConsoleColor.Magenta;
Console.Write(BitConverter.ToString(buffArray, 4 * sizeof(uint)).Replace("-", ""));
Console.ResetColor();
Console.WriteLine();
#endif
return buffArray;
}
}
}

View File

@ -1,8 +1,8 @@
using System.Linq;
namespace NPSharp.RPC.Packets
namespace NPSharp.RPC.Messages
{
public class RPCMessage
public abstract class RPCMessage
{
internal const uint Signature = 0xDEADC0DE; // I wonder if aiw3 changed this since kernal noted it in his source code.

View File

@ -1,34 +1,64 @@
using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Reflection;
using log4net;
namespace NPSharp.RPC.Packets
namespace NPSharp.RPC.Messages
{
public class RPCServerMessage : RPCMessage
public abstract class RPCServerMessage : RPCMessage
{
private static readonly ILog Log;
static RPCServerMessage()
{
Log = LogManager.GetLogger("RPCServerMessage");
}
// Internal constructor to make classes unconstructible from outside
internal RPCServerMessage() { }
public uint MessageId { get; private set; }
public static RPCServerMessage Deserialize(NetworkStream ns)
{
var header = new byte[16];
var header = new byte[4 * sizeof(uint)];
Log.Debug("Reading...");
var l = ns.Read(header, 0, header.Length);
if (l == 0)
{
Log.Debug("Received 0 bytes");
return null;
}
if (l < 16)
{
Log.ErrorFormat("Received incomplete header ({0} bytes of 16 wanted bytes)", l);
throw new ProtocolViolationException("Received incomplete header");
}
uint signature, length, type, pid;
using (var ms = new MemoryStream(header))
{
using (var br = new BinaryReader(ms))
{
signature = br.ReadUInt32();
length = br.ReadUInt32();
type = br.ReadUInt32();
pid = br.ReadUInt32();
}
}
var signature = (uint)IPAddress.NetworkToHostOrder(BitConverter.ToUInt32(header, 0));
var length = (uint)IPAddress.NetworkToHostOrder(BitConverter.ToUInt32(header, 4));
var type = (uint)IPAddress.NetworkToHostOrder(BitConverter.ToUInt32(header, 8));
var buffer = new byte[length];
ns.Read(buffer, 0, buffer.Length);
if (signature != Signature)
{
Log.Error("Received invalid signature");
throw new ProtocolViolationException("Received packet with invalid signature");
}
RPCServerMessage packet;
@ -42,14 +72,13 @@ namespace NPSharp.RPC.Packets
).ToArray();
if (!types.Any())
{
throw new ProtocolViolationException("Received packet of unknown type");
throw new ProtocolViolationException(string.Format("Received packet of unknown type ({0})", type));
}
if (types.Count() > 1)
{
#if DEBUG
Debug.Fail(string.Format("Bug in program code: Found more than 1 type for packet ID {0}", type));
#else
// TODO: log4net
return null;
#endif
}
@ -59,7 +88,7 @@ namespace NPSharp.RPC.Packets
);
}
packet.MessageId = (uint)IPAddress.NetworkToHostOrder(BitConverter.ToUInt32(header, 12));
packet.MessageId = pid;
return packet;
}

View File

@ -1,10 +1,10 @@
using ProtoBuf;
namespace NPSharp.RPC.Packets
namespace NPSharp.RPC.Messages
{
[ProtoContract]
[Packet(1101)]
class StorageGetPublisherFileMessage : RPCClientMessage
public sealed class StorageGetPublisherFileMessage : RPCClientMessage
{
[ProtoMember(1)]
public string FileName { get; set; }

View File

@ -1,10 +1,10 @@
using ProtoBuf;
namespace NPSharp.RPC.Packets
namespace NPSharp.RPC.Messages
{
[Packet(1102)]
[ProtoContract]
class StorageGetUserFileMessage : RPCClientMessage
public sealed class StorageGetUserFileMessage : RPCClientMessage
{
[ProtoMember(1)]
public string FileName { get; set; }

View File

@ -1,10 +1,10 @@
using ProtoBuf;
namespace NPSharp.RPC.Packets
namespace NPSharp.RPC.Messages
{
[Packet(1111)]
[ProtoContract]
class StoragePublisherFileMessage : RPCServerMessage
public sealed class StoragePublisherFileMessage : RPCServerMessage
{
[ProtoMember(1)]
public int Result { get; set; }

View File

@ -1,10 +1,10 @@
using ProtoBuf;
namespace NPSharp.RPC.Packets
namespace NPSharp.RPC.Messages
{
[Packet(1104)]
[ProtoContract]
class StorageSendRandomStringMessage : RPCClientMessage
public sealed class StorageSendRandomStringMessage : RPCClientMessage
{
[ProtoMember(1)]
public string RandomString { get; set; }

View File

@ -1,10 +1,10 @@
using ProtoBuf;
namespace NPSharp.RPC.Packets
namespace NPSharp.RPC.Messages
{
[Packet(1112)]
[ProtoContract]
class StorageUserFileMessage : RPCServerMessage
public sealed class StorageUserFileMessage : RPCServerMessage
{
[ProtoMember(1)]
public int Result { get; set; }

View File

@ -1,10 +1,10 @@
using ProtoBuf;
namespace NPSharp.RPC.Packets
namespace NPSharp.RPC.Messages
{
[Packet(1103)]
[ProtoContract]
class StorageWriteUserFileMessage : RPCClientMessage
public sealed class StorageWriteUserFileMessage : RPCClientMessage
{
[ProtoMember(1)]
public string FileName { get; set; }

View File

@ -1,10 +1,10 @@
using ProtoBuf;
namespace NPSharp.RPC.Packets
namespace NPSharp.RPC.Messages
{
[Packet(1113)]
[ProtoContract]
class StorageWriteUserFileResultMessage : RPCServerMessage
public sealed class StorageWriteUserFileResultMessage : RPCServerMessage
{
[ProtoMember(1)]
public int Result { get; set; }

View File

@ -1,30 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
namespace NPSharp.RPC.Packets
{
public class RPCClientMessage : RPCMessage
{
public byte[] Serialize(uint id)
{
byte[] content;
using (var bufferStream = new MemoryStream())
{
ProtoBuf.Serializer.Serialize(bufferStream, this);
bufferStream.Seek(0, SeekOrigin.Begin);
content = bufferStream.ToArray();
}
var buffer = new List<byte>();
buffer.AddRange(BitConverter.GetBytes((uint)IPAddress.HostToNetworkOrder(Signature)));
buffer.AddRange(BitConverter.GetBytes((uint)IPAddress.HostToNetworkOrder(content.Length)));
buffer.AddRange(BitConverter.GetBytes((uint)IPAddress.HostToNetworkOrder(GetTypeId())));
buffer.AddRange(BitConverter.GetBytes((uint)IPAddress.HostToNetworkOrder(id)));
buffer.AddRange(content);
return buffer.ToArray();
}
}
}

View File

@ -2,7 +2,7 @@
using System.Collections.Generic;
using System.Net.Sockets;
using log4net;
using NPSharp.RPC.Packets;
using NPSharp.RPC.Messages;
namespace NPSharp.RPC
{
@ -13,7 +13,7 @@ namespace NPSharp.RPC
{
private NetworkStream _ns;
private uint _id;
private ILog _log;
private readonly ILog _log;
private readonly string _host;
private readonly ushort _port;
@ -38,6 +38,8 @@ namespace NPSharp.RPC
/// <returns>True if the connection succeeded, otherwise false.</returns>
public bool Open()
{
_log.Debug("Open() start");
// Connection already established?
if (_ns != null)
throw new InvalidOperationException("Connection already opened");
@ -52,6 +54,8 @@ namespace NPSharp.RPC
return false;
}
_ns = tcp.GetStream();
_log.Debug("Open() end");
return true;
}
@ -82,6 +86,7 @@ namespace NPSharp.RPC
/// <param name="callback">The method to call when we receive a response to the next message</param>
public void AttachCallback(Action<RPCServerMessage> callback)
{
_log.DebugFormat("AttachCallback for packet id {0}", _id);
if (_callbacks.ContainsKey(_id))
throw new Exception("There is already a callback for the current message. You can only add max. one callback.");
_callbacks.Add(_id, callback);
@ -120,7 +125,12 @@ namespace NPSharp.RPC
var message = RPCServerMessage.Deserialize(_ns);
if (message == null)
{
_log.Debug("Recv NULL message");
return null;
}
_log.DebugFormat("Received packet ID {1} (type {0})", message.GetType().Name, message.MessageId);
if (!_callbacks.ContainsKey(message.MessageId))
return message;
@ -128,8 +138,6 @@ namespace NPSharp.RPC
_callbacks[message.MessageId].Invoke(message);
_callbacks.Remove(message.MessageId);
_log.DebugFormat("Received packet ID {1} (type {0})", message.GetType().Name, message.MessageId);
return message;
}
}

View File

@ -56,24 +56,35 @@
<ItemGroup>
<Compile Include="NPClient.cs" />
<Compile Include="NPFileException.cs" />
<Compile Include="RPC\Messages\FriendDetails.cs" />
<Compile Include="RPC\Messages\FriendsSetSteamIDMessage.cs" />
<Compile Include="RPC\Messages\FriendsGetProfileDataMessage.cs" />
<Compile Include="RPC\Messages\FriendsGetProfileDataResultMessage.cs" />
<Compile Include="RPC\Messages\FriendsGetUserAvatarMessage.cs" />
<Compile Include="RPC\Messages\FriendsGetUserAvatarResultMessage.cs" />
<Compile Include="RPC\Messages\FriendsPresence.cs" />
<Compile Include="RPC\Messages\FriendsPresenceMessage.cs" />
<Compile Include="RPC\Messages\FriendsRosterMessage.cs" />
<Compile Include="RPC\Messages\FriendsSetPresenceMessage.cs" />
<Compile Include="RPC\Messages\ProfileDataResult.cs" />
<Compile Include="RPC\RPCClientStream.cs" />
<Compile Include="RPC\Packets\AuthenticateExternalStatusMessage.cs" />
<Compile Include="RPC\Packets\AuthenticateResultMessage.cs" />
<Compile Include="RPC\Packets\AuthenticateWithTokenMessage.cs" />
<Compile Include="RPC\Packets\CloseAppMessage.cs" />
<Compile Include="RPC\Packets\HelloMessage.cs" />
<Compile Include="RPC\Packets\MessagingSendDataMessage.cs" />
<Compile Include="RPC\Packets\RPCMessage.cs" />
<Compile Include="RPC\Packets\PacketAttribute.cs" />
<Compile Include="RPC\Packets\RPCClientMessage.cs" />
<Compile Include="RPC\Packets\RPCServerMessage.cs" />
<Compile Include="RPC\Packets\StorageGetUserFileMessage.cs" />
<Compile Include="RPC\Packets\StorageGetPublisherFileMessage.cs" />
<Compile Include="RPC\Packets\StoragePublisherFileMessage.cs" />
<Compile Include="RPC\Packets\StorageSendRandomStringMessage.cs" />
<Compile Include="RPC\Packets\StorageUserFileMessage.cs" />
<Compile Include="RPC\Packets\StorageWriteUserFileMessage.cs" />
<Compile Include="RPC\Packets\StorageWriteUserFileResultMessage.cs" />
<Compile Include="RPC\Messages\AuthenticateExternalStatusMessage.cs" />
<Compile Include="RPC\Messages\AuthenticateResultMessage.cs" />
<Compile Include="RPC\Messages\AuthenticateWithTokenMessage.cs" />
<Compile Include="RPC\Messages\CloseAppMessage.cs" />
<Compile Include="RPC\Messages\HelloMessage.cs" />
<Compile Include="RPC\Messages\MessagingSendDataMessage.cs" />
<Compile Include="RPC\Messages\RPCMessage.cs" />
<Compile Include="RPC\Messages\PacketAttribute.cs" />
<Compile Include="RPC\Messages\RPCClientMessage.cs" />
<Compile Include="RPC\Messages\RPCServerMessage.cs" />
<Compile Include="RPC\Messages\StorageGetUserFileMessage.cs" />
<Compile Include="RPC\Messages\StorageGetPublisherFileMessage.cs" />
<Compile Include="RPC\Messages\StoragePublisherFileMessage.cs" />
<Compile Include="RPC\Messages\StorageSendRandomStringMessage.cs" />
<Compile Include="RPC\Messages\StorageUserFileMessage.cs" />
<Compile Include="RPC\Messages\StorageWriteUserFileMessage.cs" />
<Compile Include="RPC\Messages\StorageWriteUserFileResultMessage.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Authentication\AuthenticationHelper.cs" />
</ItemGroup>