public static void HandleCharacterCreate(PacketStream P, ref LoginClient Client, ref CityServerListener CServerListener) { byte PacketLength = (byte)P.ReadByte(); //Length of the unencrypted data, excluding the header (ID, length, unencrypted length). byte UnencryptedLength = (byte)P.ReadByte(); P.DecryptPacket(Client.EncKey, Client.CryptoService, UnencryptedLength); Logger.LogDebug("Received CharacterCreate!"); string AccountName = P.ReadString(); Sim Char = new Sim(P.ReadString()); Char.Timestamp = P.ReadString(); Char.Name = P.ReadString(); Char.Sex = P.ReadString(); Char.CreatedThisSession = true; Client.CurrentlyActiveSim = Char; switch (Character.CreateCharacter(Char)) { case CharacterCreationStatus.NameAlreadyExisted: //TODO: Send packet. break; case CharacterCreationStatus.ExceededCharacterLimit: //TODO: Send packet. break; } }
/// <summary> /// Checks when a client's characters were last cached, against a timestamp received from the client. /// If the client's timestamp doesn't match the one in the DB (meaning it was older or newer), information /// about all the characters is sent to the client. /// </summary> /// <param name="Timestamp">The timestamp received from the client.</param> public static void CheckCharacterTimestamp(string AccountName, LoginClient Client, DateTime Timestamp) { MySqlCommand Command = new MySqlCommand("SELECT AccountName, NumCharacters, Character1, Character2, Character3 " + "FROM Accounts"); Command.Connection = m_Connection; EndCheckCharacterID(Command.BeginExecuteReader(System.Data.CommandBehavior.Default)); }
/// <summary> /// Checks when a client's characters were last cached, against a timestamp received from the client. /// If the client's timestamp doesn't match the one in the DB (meaning it was older or newer), information /// about all the characters is sent to the client. /// </summary> /// <param name="Timestamp">The timestamp received from the client.</param> public static void CheckCharacterTimestamp(string AccountName, LoginClient Client, DateTime Timestamp) { SqlCommand Command = new SqlCommand("SELECT AccountName, NumCharacters, Character1, Character2, Character3 " + "FROM Accounts"); Command.Connection = m_Connection; Command.BeginExecuteReader(new AsyncCallback(EndCheckCharacterID), new DatabaseAsyncObject(AccountName, ref Client, Timestamp, Command)); }
/// <summary> /// Checks whether or not an account existed, and whether or not the password supplied was correct. /// </summary> /// <param name="AccountName">The name of the account.</param> /// <param name="Client">The client that supplied the account.</param> /// <param name="Hash">The hash of the password (with the username as a salt).</param> public static void CheckAccount(string AccountName, LoginClient Client, byte[] Hash) { if (m_Connection == null) { if (GlobalSettings.Default.CreateAccountsOnLogin == false) { //TODO: Check if a flat file database exists, otherwise send an accountlogin failed packet. } else { //TODO: Write account into flat file DB if it doesn't exist. } } //Gets the data from both rows (AccountName & Password) MySqlCommand Command = new MySqlCommand("SELECT AccountName, Password FROM Accounts"); Command.Connection = m_Connection; EndCheckAccount(Command.BeginExecuteReader(System.Data.CommandBehavior.Default)); }
/// <summary> /// Constructs a DBAsyncObject instance. /// </summary> /// <param name="AccountName">The name of the client's account.</param> /// <param name="Client">The client.</param> /// <param name="Command">The SQL command.</param> public DatabaseAsyncObject(string AccountName, ref LoginClient Client, MySqlCommand Command, byte[] Hash) { m_Client = Client; m_AccountName = AccountName; m_MySqlCmd = Command; m_Hash = Hash; }
/// <summary> /// Creates a character in the DB. /// </summary> /// <param name="Character">The character that was created by a client.</param> /// <param name="CServerListener">A CityServerListener instance, that can be used to /// retrieve info about cityservers when sending a reply to the client.</param> public static void CreateCharacter(LoginClient Client, Sim Character, ref CityServerListener CServerListener) { SqlCommand Command = new SqlCommand("INSERT INTO Characters(LastCached, Name, Sex) VALUES('" + Character.Timestamp + "', '" + Character.Name + "', '" + Character.Sex + "')"); Command.BeginExecuteNonQuery(new AsyncCallback(EndCreateCharacter), new DatabaseAsyncObject(Client, Command, ref CServerListener)); }
public static void HandleCharacterInfoRequest(PacketStream P, LoginClient Client) { byte PacketLength = (byte)P.ReadByte(); //Length of the unencrypted data, excluding the header (ID, length, unencrypted length). byte UnencryptedLength = (byte)P.ReadByte(); P.DecryptPacket(Client.EncKey, Client.CryptoService, UnencryptedLength); Logger.LogDebug("Received CharacterInfoRequest!"); byte Length = (byte)P.ReadByte(); byte[] StrBuf = new byte[Length]; P.Read(StrBuf, 0, Length - 1); DateTime Timestamp = DateTime.Parse(Encoding.ASCII.GetString(StrBuf)); //Database.CheckCharacterTimestamp(Client.Username, Client, TimeStamp); Character[] Characters = Character.GetCharacters(Client.Username); if (Characters != null) { PacketStream Packet = new PacketStream(0x05, 0); MemoryStream PacketData = new MemoryStream(); BinaryWriter PacketWriter = new BinaryWriter(PacketData); //The timestamp for all characters should be equal, so just check the first character. if (Timestamp < DateTime.Parse(Characters[0].LastCached) || Timestamp > DateTime.Parse(Characters[0].LastCached)) { //Write the characterdata into a temporary buffer. if (Characters.Length == 1) { PacketWriter.Write(Characters[0].CharacterID); PacketWriter.Write(Characters[0].GUID); PacketWriter.Write(Characters[0].LastCached); PacketWriter.Write(Characters[0].Name); PacketWriter.Write(Characters[0].Sex); PacketWriter.Flush(); } else if (Characters.Length == 2) { PacketWriter.Write(Characters[0].CharacterID); PacketWriter.Write(Characters[0].GUID); PacketWriter.Write(Characters[0].LastCached); PacketWriter.Write(Characters[0].Name); PacketWriter.Write(Characters[0].Sex); PacketWriter.Write(Characters[1].CharacterID); PacketWriter.Write(Characters[1].GUID); PacketWriter.Write(Characters[1].LastCached); PacketWriter.Write(Characters[1].Name); PacketWriter.Write(Characters[1].Sex); PacketWriter.Flush(); } else if (Characters.Length == 3) { PacketWriter.Write(Characters[0].CharacterID); PacketWriter.Write(Characters[0].GUID); PacketWriter.Write(Characters[0].LastCached); PacketWriter.Write(Characters[0].Name); PacketWriter.Write(Characters[0].Sex); PacketWriter.Write(Characters[1].CharacterID); PacketWriter.Write(Characters[1].GUID); PacketWriter.Write(Characters[1].LastCached); PacketWriter.Write(Characters[1].Name); PacketWriter.Write(Characters[1].Sex); PacketWriter.Write(Characters[2].CharacterID); PacketWriter.Write(Characters[2].GUID); PacketWriter.Write(Characters[2].LastCached); PacketWriter.Write(Characters[2].Name); PacketWriter.Write(Characters[2].Sex); PacketWriter.Flush(); } Packet.WriteByte((byte)Characters.Length); //Total number of characters. Packet.Write(PacketData.ToArray(), 0, (int)PacketData.Length); PacketWriter.Close(); Client.SendEncrypted(0x05, Packet.ToArray()); } } else //No characters existed for the account. { PacketStream Packet = new PacketStream(0x05, 0); Packet.WriteByte(0x00); //0 characters. Client.SendEncrypted(0x05, Packet.ToArray()); } }
public static void Handle(PacketStream stream, LoginClient session) { byte ID = (byte)stream.ReadByte(); if (m_Handlers.ContainsKey(ID)) { m_Handlers[ID].Handler(ref session, stream); } }
public static void HandleLoginRequest(PacketStream P, ref LoginClient Client) { Logger.LogInfo("Received LoginRequest!\r\n"); byte PacketLength = (byte)P.ReadByte(); byte AccountStrLength = (byte)P.ReadByte(); byte[] AccountNameBuf = new byte[AccountStrLength]; P.Read(AccountNameBuf, 0, AccountStrLength); string AccountName = Encoding.ASCII.GetString(AccountNameBuf); Logger.LogInfo("Accountname: " + AccountName + "\r\n"); byte HashLength = (byte)P.ReadByte(); byte[] HashBuf = new byte[HashLength]; P.Read(HashBuf, 0, HashLength); Client.Hash = HashBuf; byte KeyLength = (byte)P.ReadByte(); Client.EncKey = new byte[KeyLength]; P.Read(Client.EncKey, 0, KeyLength); byte Version1 = (byte)P.ReadByte(); byte Version2 = (byte)P.ReadByte(); byte Version3 = (byte)P.ReadByte(); byte Version4 = (byte)P.ReadByte(); Logger.LogInfo("Done reading LoginRequest, checking account...\r\n"); //Database.CheckAccount(AccountName, Client, HashBuf); if (Account.DoesAccountExist(AccountName) && Account.IsCorrectPassword(AccountName, HashBuf)) { //0x01 = InitLoginNotify PacketStream OutPacket = new PacketStream(0x01, 2); OutPacket.WriteByte(0x01); OutPacket.WriteByte(0x01); Client.Username = AccountName; //This is neccessary to encrypt packets. Client.Password = Account.GetPassword(AccountName); Client.Send(OutPacket.ToArray()); Logger.LogInfo("Sent InitLoginNotify!\r\n"); } else { PacketStream OutPacket = new PacketStream(0x02, 2); P.WriteByte(0x02); P.WriteByte(0x01); Client.Send(P.ToArray()); Logger.LogInfo("Bad accountname - sent SLoginFailResponse!\r\n"); Client.Disconnect(); } }
/** * Actual packet handlers */ public static void HandleLoginRequest(ref LoginClient Client, PacketStream P) { Logger.LogInfo("Received LoginRequest!\r\n"); ushort PacketLength = (ushort)P.ReadUShort(); byte AccountStrLength = (byte)P.ReadByte(); byte[] AccountNameBuf = new byte[AccountStrLength]; P.Read(AccountNameBuf, 0, AccountStrLength); string AccountName = Encoding.ASCII.GetString(AccountNameBuf); Logger.LogInfo("Accountname: " + AccountName + "\r\n"); byte HashLength = (byte)P.ReadByte(); byte[] HashBuf = new byte[HashLength]; P.Read(HashBuf, 0, HashLength); Client.Hash = HashBuf; byte KeyLength = (byte)P.ReadByte(); Client.EncKey = new byte[KeyLength]; P.Read(Client.EncKey, 0, KeyLength); byte Version1 = (byte)P.ReadByte(); byte Version2 = (byte)P.ReadByte(); byte Version3 = (byte)P.ReadByte(); byte Version4 = (byte)P.ReadByte(); Logger.LogInfo("Done reading LoginRequest, checking account...\r\n"); using (var db = DataAccess.Get()) { var account = db.Accounts.GetByUsername(AccountName); if (account == null) { PacketStream OutPacket = new PacketStream(0x02, 2); OutPacket.WriteHeader(); OutPacket.WriteByte(0x01); Client.Send(OutPacket); Logger.LogInfo("Bad accountname - sent SLoginFailResponse!\r\n"); Client.Disconnect(); return; } if (account.IsCorrectPassword(AccountName, HashBuf)) { //0x01 = InitLoginNotify PacketStream OutPacket = new PacketStream(0x01, 1); OutPacket.WriteHeader(); Client.Username = AccountName; //This is neccessary to encrypt packets. //TODO: Put something else here //Client.Password = Account.GetPassword(AccountName); Client.Send(OutPacket.ToArray()); Logger.LogInfo("Sent InitLoginNotify!\r\n"); } } }
public void OnAccept(IAsyncResult AR) { Socket AcceptedSocket = m_ListenerSock.EndAccept(AR); if (AcceptedSocket != null) { Console.WriteLine("\nNew client connected!"); //Let sockets linger for 5 seconds after they're closed, in an attempt to make sure all //pending data is sent! AcceptedSocket.LingerState = new LingerOption(true, 5); LoginClient NewClient = new LoginClient(AcceptedSocket, this); m_LoginClients.Add(NewClient); } m_ListenerSock.BeginAccept(new AsyncCallback(OnAccept), m_ListenerSock); }
/// <summary> /// Removes a client from the internal list of connected clients. /// Should really only be called internally by the LoginClient.Disconnect() /// method. /// </summary> /// <param name="Client">The client to remove.</param> public void RemoveClient(LoginClient Client) { m_LoginClients.Remove(Client); }
/// <summary> /// Constructs a DBAsyncObject instance that can be used to communicate with a Microsoft SQL Server. /// </summary> /// <param name="AccountName">The name of the client's account.</param> /// <param name="Client">The client.</param> /// <param name="Command">The SQL command.</param> public DatabaseAsyncObject(string AccountName, ref LoginClient Client, SqlCommand Command) { m_Client = Client; m_AccountName = AccountName; m_Command = Command; }
/// <summary> /// Handles incoming packets from connected clients. /// </summary> private void m_Listener_OnReceiveEvent(PacketStream P, LoginClient Client) { byte ID = (byte)P.ReadByte(); switch (ID) { case 0x00: PacketHandlers.HandleLoginRequest(P, ref Client); break; case 0x05: PacketHandlers.HandleCharacterInfoRequest(P, Client); break; case 0x06: PacketHandlers.HandleCityInfoRequest(P, Client); break; case 0x07: PacketHandlers.HandleCharacterCreate(P, ref Client, ref NetworkFacade.CServerListener); break; default: Logger.LogInfo("Received unhandled packet - ID: " + P.PacketID); break; } }
/// <summary> /// Constructs a DBAsyncObject instance. /// </summary> /// <param name="Client">The client.</param> /// <param name="Command">The SQL command.</param> /// <param name="CSListener">A CityServerListener that holds information about connected CityServers. /// Must be passed by reference in order to ensure that any servers that might /// connect before a reply is sent to the client will be written into the reply.</param> public DatabaseAsyncObject(LoginClient Client, MySqlCommand Command, ref CityServerListener CSListener) { m_Client = Client; m_MySqlCmd = Command; m_CServerListener = CSListener; }
public static void HandleCityInfoRequest(ref LoginClient Client, PacketStream P) { ushort PacketLength = (ushort)P.ReadUShort(); //Length of the unencrypted data, excluding the header (ID, length, unencrypted length). ushort UnencryptedLength = (ushort)P.ReadUShort(); P.DecryptPacket(Client.EncKey, Client.CryptoService, UnencryptedLength); //This packet only contains a dummy byte, don't bother reading it. PacketStream Packet = new PacketStream(0x06, 0); MemoryStream PacketData = new MemoryStream(); BinaryWriter PacketWriter = new BinaryWriter(PacketData); PacketWriter.Write((byte)NetworkFacade.CServerListener.CityServers.Count); foreach (CityServerClient City in NetworkFacade.CServerListener.CityServers) { PacketWriter.Write((string)City.ServerInfo.Name); PacketWriter.Write((string)City.ServerInfo.Description); PacketWriter.Write((string)City.ServerInfo.IP); PacketWriter.Write((int)City.ServerInfo.Port); //Hack (?) to ensure status is written correctly. switch (City.ServerInfo.Status) { case CityInfoStatus.Ok: PacketWriter.Write((byte)1); break; case CityInfoStatus.Busy: PacketWriter.Write((byte)2); break; case CityInfoStatus.Full: PacketWriter.Write((byte)3); break; case CityInfoStatus.Reserved: PacketWriter.Write((byte)4); break; } PacketWriter.Write((ulong)City.ServerInfo.Thumbnail); PacketWriter.Write((string)City.ServerInfo.UUID); PacketWriter.Write((ulong)City.ServerInfo.Map); PacketWriter.Flush(); } Packet.Write(PacketData.ToArray(), 0, PacketData.ToArray().Length); PacketWriter.Close(); Client.SendEncrypted(0x06, Packet.ToArray()); }
public static void HandleCharacterInfoRequest(ref LoginClient Client, PacketStream P) { ushort PacketLength = (ushort)P.ReadUShort(); //Length of the unencrypted data, excluding the header (ID, length, unencrypted length). ushort UnencryptedLength = (ushort)P.ReadUShort(); P.DecryptPacket(Client.EncKey, Client.CryptoService, UnencryptedLength); Logger.LogDebug("Received CharacterInfoRequest!"); DateTime Timestamp = DateTime.Parse(P.ReadASCII()); //Database.CheckCharacterTimestamp(Client.Username, Client, TimeStamp); Character[] Characters = new Character[]{}; using (var db = DataAccess.Get()) { Characters = db.Characters.GetForAccount(Client.AccountID).ToArray(); } if (Characters != null) { PacketStream Packet = new PacketStream(0x05, 0); MemoryStream PacketData = new MemoryStream(); BinaryWriter PacketWriter = new BinaryWriter(PacketData); /** * Whats the point of checking a timestamp here? It saves a few bytes on a packet * sent once per user session. Premature optimization. */ PacketWriter.Write((byte)Characters.Length); foreach(Character avatar in Characters){ PacketWriter.Write(avatar.CharacterID); PacketWriter.Write(avatar.GUID.ToString()); PacketWriter.Write(avatar.LastCached); PacketWriter.Write(avatar.Name); PacketWriter.Write(avatar.Sex); } Packet.Write(PacketData.ToArray(), 0, (int)PacketData.Length); PacketWriter.Close(); Client.SendEncrypted(0x05, Packet.ToArray()); } else //No characters existed for the account. { PacketStream Packet = new PacketStream(0x05, 0); Packet.WriteByte(0x00); //0 characters. Client.SendEncrypted(0x05, Packet.ToArray()); } }
public static void HandleCharacterCreate(ref LoginClient Client, PacketStream P) { ushort PacketLength = (ushort)P.ReadUShort(); //Length of the unencrypted data, excluding the header (ID, length, unencrypted length). ushort UnencryptedLength = (ushort)P.ReadUShort(); P.DecryptPacket(Client.EncKey, Client.CryptoService, UnencryptedLength); Logger.LogDebug("Received CharacterCreate!"); string AccountName = P.ReadString(); //GUID generation should always be done on the server side //You cant trust the client side, it may have been hacked Sim Char = new Sim(Guid.NewGuid()); Char.Timestamp = P.ReadString(); Char.Name = P.ReadString(); Char.Sex = P.ReadString(); Char.CreatedThisSession = true; Client.CurrentlyActiveSim = Char; using (var db = DataAccess.Get()) { var characterModel = new Character(); characterModel.Name = Char.Name; characterModel.Sex = Char.Sex; characterModel.LastCached = Char.Timestamp; characterModel.GUID = Char.GUID; var status = db.Characters.CreateCharacter(characterModel); switch (status) { case CharacterCreationStatus.NameAlreadyExisted: //TODO: Send packet. break; case CharacterCreationStatus.ExceededCharacterLimit: //TODO: Send packet. break; } } }
/// <summary> /// Called by LoginClient instances /// when they've received some new data /// (a new packet). Should not be called /// from anywhere else. /// </summary> /// <param name="P"></param> public void OnReceivedData(PacketStream P, LoginClient Client) { PacketHandlers.Handle(P, Client); //OnReceiveEvent(P, Client); }
/// <summary> /// Called by LoginClient instances /// when they've received some new data /// (a new packet). Should not be called /// from anywhere else. /// </summary> /// <param name="P"></param> public void OnReceivedData(PacketStream P, LoginClient Client) { OnReceiveEvent(P, Client); }
/// <summary> /// Moves a client from the list of clients that are connected to this /// LoginServer to the list of clients that are transferring to a CityServer. /// </summary> /// <param name="Client">The client to move.</param> public void TransferClient(LoginClient Client) { m_LoginClients.Remove(Client); m_TransferringClients.Add(Client); }
/// <summary> /// Constructs a DBAsyncObject instance that can be used to communicate with a Microsoft SQL Server. /// </summary> /// <param name="AccountName">The name of the client's account.</param> /// <param name="Client">The client.</param> /// <param name="Timestamp">The timestamp of when a character was last cached by the client.</param> /// <param name="Command">The database command used to communicate with the DB.</param> public DatabaseAsyncObject(string AccountName, ref LoginClient Client, DateTime Timestamp, SqlCommand Command) { m_Client = Client; m_AccountName = AccountName; m_CharacterTimestamp = Timestamp; m_Command = Command; }
public static void HandleCityInfoRequest(PacketStream P, LoginClient Client) { byte PacketLength = (byte)P.ReadByte(); //Length of the unencrypted data, excluding the header (ID, length, unencrypted length). byte UnencryptedLength = (byte)P.ReadByte(); P.DecryptPacket(Client.EncKey, Client.CryptoService, UnencryptedLength); //This packet only contains a dummy byte, don't bother reading it. PacketStream Packet = new PacketStream(0x06, 0); MemoryStream PacketData = new MemoryStream(); BinaryWriter PacketWriter = new BinaryWriter(PacketData); PacketWriter.Write((byte)NetworkFacade.CServerListener.CityServers.Count); foreach (CityServerClient City in NetworkFacade.CServerListener.CityServers) { PacketWriter.Write(City.ServerInfo.Name); PacketWriter.Write(City.ServerInfo.Description); PacketWriter.Write(City.ServerInfo.IP); PacketWriter.Write(City.ServerInfo.Port); PacketWriter.Write((byte)City.ServerInfo.Status); PacketWriter.Write(City.ServerInfo.Thumbnail); PacketWriter.Write(City.ServerInfo.UUID); PacketWriter.Flush(); } Packet.Write(PacketData.ToArray(), 0, PacketData.ToArray().Length); PacketWriter.Close(); Client.SendEncrypted(0x06, Packet.ToArray()); }