From f996f727dc0bbd0e78efd8770e0791329f08334b Mon Sep 17 00:00:00 2001 From: Filip Maj Date: Thu, 27 Aug 2015 10:19:00 -0400 Subject: [PATCH] Server now processes session ids and stores the correct logged in user in the clientconnection object. Reserve character now creates a entry in the db. --- FFXIVClassic_Lobby_Server/ClientConnection.cs | 9 +-- FFXIVClassic_Lobby_Server/Database.cs | 67 ++++++++++++++++--- .../FFXIVClassic_Lobby_Server.csproj | 8 ++- FFXIVClassic_Lobby_Server/PacketProcessor.cs | 42 +++++++----- FFXIVClassic_Lobby_Server/Server.cs | 4 +- .../packets/CharacterRequestPacket.cs | 36 ---------- .../packets/PacketStructs.cs | 57 ++++++++++++++++ 7 files changed, 152 insertions(+), 71 deletions(-) delete mode 100644 FFXIVClassic_Lobby_Server/packets/CharacterRequestPacket.cs create mode 100644 FFXIVClassic_Lobby_Server/packets/PacketStructs.cs diff --git a/FFXIVClassic_Lobby_Server/ClientConnection.cs b/FFXIVClassic_Lobby_Server/ClientConnection.cs index 0f6fb3af..27d0773a 100644 --- a/FFXIVClassic_Lobby_Server/ClientConnection.cs +++ b/FFXIVClassic_Lobby_Server/ClientConnection.cs @@ -24,7 +24,7 @@ namespace FFXIVClassic_Lobby_Server public BlockingCollection sendPacketQueue = new BlockingCollection(100); //Instance Stuff - public uint currentSession; + public uint currentUserId = 0; public uint currentAccount; @@ -43,6 +43,9 @@ namespace FFXIVClassic_Lobby_Server public void flushQueuedSendPackets() { + if (!socket.Connected) + return; + while (sendPacketQueue.Count > 0) { BasePacket packet = sendPacketQueue.Take(); @@ -55,14 +58,12 @@ namespace FFXIVClassic_Lobby_Server catch(Exception e) { Debug.WriteLine("Weird case, socket was d/ced: {0}", e); } } - - } public String getAddress() { return String.Format("{0}:{1}", (socket.RemoteEndPoint as IPEndPoint).Address, (socket.RemoteEndPoint as IPEndPoint).Port); - } + } public void disconnect() { diff --git a/FFXIVClassic_Lobby_Server/Database.cs b/FFXIVClassic_Lobby_Server/Database.cs index 3b247a06..5d73fa9f 100644 --- a/FFXIVClassic_Lobby_Server/Database.cs +++ b/FFXIVClassic_Lobby_Server/Database.cs @@ -13,22 +13,66 @@ namespace FFXIVClassic_Lobby_Server class Database { - public static void reserveCharacter(int accountId, int slot, int serverId, String name) + public static uint getUserIdFromSession(String sessionId) { + uint id = 0; using (MySqlConnection conn = new MySqlConnection(String.Format("Server={0}; Port={1}; Database={2}; UID={3}; Password={4}", ConfigConstants.DATABASE_HOST, ConfigConstants.DATABASE_PORT, ConfigConstants.DATABASE_NAME, ConfigConstants.DATABASE_USERNAME, ConfigConstants.DATABASE_PASSWORD))) { try { conn.Open(); - MySqlCommand cmd = new MySqlCommand(); - cmd.Connection = conn; - cmd.CommandText = "INSERT INTO ffxiv_characters2(accountId, slot, serverId, name, charState) VALUES(@accountId, @slot, @serverId, @name, 0)"; - cmd.Prepare(); - cmd.Parameters.AddWithValue("@accountId", accountId); - cmd.Parameters.AddWithValue("@slot", slot); + MySqlCommand cmd = new MySqlCommand("SELECT * FROM ffxiv_sessions WHERE id = @sessionId AND expiration > NOW()", conn); + cmd.Parameters.AddWithValue("@sessionId", sessionId); + using (MySqlDataReader Reader = cmd.ExecuteReader()) + { + while (Reader.Read()) + { + id = Reader.GetUInt32("userId"); + } + } + } + catch (MySqlException e) + { Console.WriteLine(e); } + finally + { + conn.Close(); + } + } + return id; + } + + public static bool reserveCharacter(uint userId, uint slot, uint serverId, String name) + { + bool alreadyExists = false; + using (MySqlConnection conn = new MySqlConnection(String.Format("Server={0}; Port={1}; Database={2}; UID={3}; Password={4}", ConfigConstants.DATABASE_HOST, ConfigConstants.DATABASE_PORT, ConfigConstants.DATABASE_NAME, ConfigConstants.DATABASE_USERNAME, ConfigConstants.DATABASE_PASSWORD))) + { + try + { + conn.Open(); + + //Check if exists + MySqlCommand cmd = new MySqlCommand("SELECT * FROM ffxiv_characters2 WHERE name=@name AND serverId=@serverId", conn); cmd.Parameters.AddWithValue("@serverId", serverId); cmd.Parameters.AddWithValue("@name", name); - cmd.ExecuteNonQuery(); + using (MySqlDataReader Reader = cmd.ExecuteReader()) + { + if (Reader.HasRows) + alreadyExists = true; + } + + //Reserve + if (!alreadyExists) + { + MySqlCommand cmd2 = new MySqlCommand(); + cmd2.Connection = conn; + cmd2.CommandText = "INSERT INTO ffxiv_characters2(userId, slot, serverId, name, state) VALUES(@userId, @slot, @serverId, @name, 0)"; + cmd2.Prepare(); + cmd2.Parameters.AddWithValue("@userId", userId); + cmd2.Parameters.AddWithValue("@slot", slot); + cmd2.Parameters.AddWithValue("@serverId", serverId); + cmd2.Parameters.AddWithValue("@name", name); + cmd2.ExecuteNonQuery(); + } } catch (MySqlException e) @@ -40,9 +84,11 @@ namespace FFXIVClassic_Lobby_Server conn.Close(); } } - } - public static void makeCharacter(int accountId, String name, Character charaInfo) + return alreadyExists; + } + + public static void makeCharacter(uint accountId, String name, Character charaInfo) { using (MySqlConnection conn = new MySqlConnection(String.Format("Server={0}; Port={1}; Database={2}; UID={3}; Password={4}", ConfigConstants.DATABASE_HOST, ConfigConstants.DATABASE_PORT, ConfigConstants.DATABASE_NAME, ConfigConstants.DATABASE_USERNAME, ConfigConstants.DATABASE_PASSWORD))) { @@ -234,5 +280,6 @@ namespace FFXIVClassic_Lobby_Server return world; } } + } } diff --git a/FFXIVClassic_Lobby_Server/FFXIVClassic_Lobby_Server.csproj b/FFXIVClassic_Lobby_Server/FFXIVClassic_Lobby_Server.csproj index bade925c..573a078e 100644 --- a/FFXIVClassic_Lobby_Server/FFXIVClassic_Lobby_Server.csproj +++ b/FFXIVClassic_Lobby_Server/FFXIVClassic_Lobby_Server.csproj @@ -40,6 +40,9 @@ ..\packages\MySql.Data.6.9.7\lib\net45\MySql.Data.dll + + ..\packages\Newtonsoft.Json.7.0.1\lib\net45\Newtonsoft.Json.dll + @@ -49,17 +52,18 @@ - + + - + diff --git a/FFXIVClassic_Lobby_Server/PacketProcessor.cs b/FFXIVClassic_Lobby_Server/PacketProcessor.cs index f9b9949b..107f6842 100644 --- a/FFXIVClassic_Lobby_Server/PacketProcessor.cs +++ b/FFXIVClassic_Lobby_Server/PacketProcessor.cs @@ -117,19 +117,24 @@ namespace FFXIVClassic_Lobby_Server private void ProcessSessionAcknowledgement(ClientConnection client, SubPacket packet) { - //String sessionId = Utils.unsafeAsciiBytesToString(packet.data, 0x30); - //String clientVersion = Utils.unsafeAsciiBytesToString(packet.data, 0x70); + PacketStructs.SessionPacket sessionPacket = PacketStructs.toSessionStruct(packet.data); + String sessionId = sessionPacket.session; + String clientVersion = sessionPacket.version; - Debug.WriteLine("Got acknowledgment for secure session."); - // Debug.WriteLine("SESSION_ID: {0}", sessionId); - // Debug.WriteLine("CLIENT_VERSION: {0}", clientVersion); + Console.WriteLine("Got acknowledgment for secure session."); + Console.WriteLine("SESSION ID: {0}", sessionId); + Console.WriteLine("CLIENT VERSION: {0}", clientVersion); - //Check if got MYSQL Conn + uint userId = Database.getUserIdFromSession(sessionId); + client.currentUserId = userId; + if (userId == 0) + { + client.disconnect(); + Console.WriteLine("Invalid session, kicking..."); + } - //auto query = string_format("SELECT userId FROM ffxiv_sessions WHERE id = '%s' AND expiration > NOW()", sessionId.c_str()); - - //Console.WriteLine("UserId {0} logged in.", id); + Console.WriteLine("USER ID: {0}", userId); BasePacket outgoingPacket = new BasePacket("./packets/loginAck.bin"); BasePacket.encryptPacket(client.blowfish, outgoingPacket); client.queuePacket(outgoingPacket); @@ -137,7 +142,7 @@ namespace FFXIVClassic_Lobby_Server private void ProcessGetCharacters(ClientConnection client, SubPacket packet) { - Console.WriteLine("{0} => Get characters", client.getAddress()); + Console.WriteLine("{0} => Get characters", client.currentUserId == 0 ? client.getAddress() : "User " + client.currentUserId); BasePacket outgoingPacket = new BasePacket("./packets/getCharsPacket.bin"); BasePacket.encryptPacket(client.blowfish, outgoingPacket); client.queuePacket(outgoingPacket); @@ -153,7 +158,7 @@ namespace FFXIVClassic_Lobby_Server binReader.Close(); } - Console.WriteLine("{0} => Select character id {1}", client.getAddress(), characterId); + Console.WriteLine("{0} => Select character id {1}", client.currentUserId == 0 ? client.getAddress() : "User " + client.currentUserId, characterId); String serverIp = "141.117.162.99"; ushort port = 54992; @@ -180,7 +185,7 @@ namespace FFXIVClassic_Lobby_Server { packet.debugPrintSubPacket(); - CharacterRequestPacket.CharacterRequest charaReq = CharacterRequestPacket.toStruct(packet.data); + PacketStructs.CharacterRequestPacket charaReq = PacketStructs.toCharacterRequestStruct(packet.data); var slot = charaReq.slot; var code = charaReq.command; var name = charaReq.characterName; @@ -189,23 +194,26 @@ namespace FFXIVClassic_Lobby_Server switch (code) { case 0x01://Reserve - //Database.reserveCharacter(0, slot, worldId, name); + var alreadyTaken = Database.reserveCharacter(client.currentUserId, slot, worldId, name); + + if (alreadyTaken) + { } //Confirm Reserve BasePacket confirmReservePacket = new BasePacket("./packets/chara/confirmReserve.bin"); BasePacket.encryptPacket(client.blowfish, confirmReservePacket); client.queuePacket(confirmReservePacket); - Console.WriteLine("Reserving character \"{0}\"", charaReq.characterName); + Console.WriteLine("User {0} => Reserving character \"{1}\"", client.currentUserId, charaReq.characterName); break; case 0x02://Make Character character = Character.EncodedToCharacter(charaReq.characterInfoEncoded); - Database.makeCharacter(0, name, character); + Database.makeCharacter(client.currentUserId, name, character); //Confirm BasePacket confirmMakePacket = new BasePacket("./packets/chara/confirmMake.bin"); BasePacket.encryptPacket(client.blowfish, confirmMakePacket); client.queuePacket(confirmMakePacket); - Console.WriteLine("Character created!"); + Console.WriteLine("User {0} => Character created!", client.currentUserId); break; case 0x03://Rename break; @@ -216,7 +224,7 @@ namespace FFXIVClassic_Lobby_Server BasePacket deleteConfirmPacket = new BasePacket("./packets/chara/confirmDelete.bin"); BasePacket.encryptPacket(client.blowfish, deleteConfirmPacket); client.queuePacket(deleteConfirmPacket); - Console.WriteLine("Character deleted \"{0}\"", charaReq.characterName); + Console.WriteLine("User {0} => Character deleted \"{1}\"", client.currentUserId, charaReq.characterName); break; case 0x06://Rename Retainer break; diff --git a/FFXIVClassic_Lobby_Server/Server.cs b/FFXIVClassic_Lobby_Server/Server.cs index 7f3e8ef5..42eda318 100644 --- a/FFXIVClassic_Lobby_Server/Server.cs +++ b/FFXIVClassic_Lobby_Server/Server.cs @@ -121,7 +121,7 @@ namespace FFXIVClassic_Lobby_Server } else { - Console.WriteLine("Connection {0}:{1} has disconnected.", (conn.socket.RemoteEndPoint as IPEndPoint).Address, (conn.socket.RemoteEndPoint as IPEndPoint).Port); + Console.WriteLine("{0} has disconnected.", conn.currentUserId == 0 ? conn.getAddress() : "User " + conn.currentUserId); conn.socket.Close(); lock (mConnectionList) { @@ -133,7 +133,7 @@ namespace FFXIVClassic_Lobby_Server { if (conn.socket != null) { - Console.WriteLine("Connection @ {0}:{1} has disconnected.", (conn.socket.RemoteEndPoint as IPEndPoint).Address, (conn.socket.RemoteEndPoint as IPEndPoint).Port); + Console.WriteLine("Connection @ {0}:{1} has disconnected.", conn.currentUserId == 0 ? conn.getAddress() : "User " + conn.currentUserId); conn.socket.Close(); lock (mConnectionList) { diff --git a/FFXIVClassic_Lobby_Server/packets/CharacterRequestPacket.cs b/FFXIVClassic_Lobby_Server/packets/CharacterRequestPacket.cs deleted file mode 100644 index 0b63cded..00000000 --- a/FFXIVClassic_Lobby_Server/packets/CharacterRequestPacket.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Runtime.InteropServices; -using System.Text; -using System.Threading.Tasks; - -namespace FFXIVClassic_Lobby_Server.packets -{ - class CharacterRequestPacket - { - [StructLayout(LayoutKind.Sequential)] - public unsafe struct CharacterRequest - { - public uint sequence; - public uint unknown; - public uint characterId; - public uint unknown2; - public byte slot; - public byte command; - public ushort worldId; - [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 0x20)] - public String characterName; - [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 0x190)] - public String characterInfoEncoded; - } - - public static unsafe CharacterRequest toStruct(byte[] bytes) - { - fixed (byte* pdata = &bytes[0]) - { - return (CharacterRequest)Marshal.PtrToStructure(new IntPtr(pdata), typeof(CharacterRequest)); - } - } - } -} diff --git a/FFXIVClassic_Lobby_Server/packets/PacketStructs.cs b/FFXIVClassic_Lobby_Server/packets/PacketStructs.cs new file mode 100644 index 00000000..6b519120 --- /dev/null +++ b/FFXIVClassic_Lobby_Server/packets/PacketStructs.cs @@ -0,0 +1,57 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; + +namespace FFXIVClassic_Lobby_Server.packets +{ + class PacketStructs + { + [StructLayout(LayoutKind.Explicit)] + public unsafe struct SessionPacket + { + [FieldOffset(0)] + public uint sequence; + [FieldOffset(0x50)] + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 0x20)] + public String version; + [FieldOffset(0x70)] + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 0x20)] + public String session; + } + + [StructLayout(LayoutKind.Sequential)] + public unsafe struct CharacterRequestPacket + { + public uint sequence; + public uint unknown; + public uint characterId; + public uint unknown2; + public byte slot; + public byte command; + public ushort worldId; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 0x20)] + public String characterName; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 0x190)] + public String characterInfoEncoded; + } + + public static unsafe CharacterRequestPacket toCharacterRequestStruct(byte[] bytes) + { + fixed (byte* pdata = &bytes[0]) + { + return (CharacterRequestPacket)Marshal.PtrToStructure(new IntPtr(pdata), typeof(CharacterRequestPacket)); + } + } + + public static unsafe SessionPacket toSessionStruct(byte[] bytes) + { + fixed (byte* pdata = &bytes[0]) + { + return (SessionPacket)Marshal.PtrToStructure(new IntPtr(pdata), typeof(SessionPacket)); + } + } + } +}