1
0

clean /old/login/client

This commit is contained in:
Sky Johnson 2025-09-01 13:01:46 -05:00
parent ffb75045a4
commit c29ab9cb0a
2 changed files with 1409 additions and 868 deletions

File diff suppressed because it is too large Load Diff

View File

@ -4,128 +4,357 @@
This file is part of EQ2Emulator. This file is part of EQ2Emulator.
*/ */
#ifndef CLIENT_H
#define CLIENT_H
#pragma once
// Standard library includes
#include <cstdint>
#include <map>
#include <memory>
#include <mutex>
#include <string>
#include <string_view>
#include <vector>
// Project includes
#include "../common/linked_list.h" #include "../common/linked_list.h"
#include "../common/timer.h" #include "../common/timer.h"
#include "../common/TCPConnection.h" #include "../common/TCPConnection.h"
#include "../common/PacketStruct.h"
#include "login_structs.h" #include "login_structs.h"
#include "LoginAccount.h" #include "LoginAccount.h"
#include "../common/PacketStruct.h"
#include <string>
#include <vector>
enum eLoginMode { None, Normal, Registration }; // Forward declarations
class DelayQue; class DelayQue;
class EQStream;
class EQ2Packet;
class EQApplicationPacket;
/**
* @brief Login modes for client state management
*/
enum class LoginMode : std::uint8_t
{
None, // No login state
Normal, // Normal login process
Registration // Account registration mode
};
/**
* @brief Represents a connected client in the login server
*
* This class manages individual client connections, handling:
* - Authentication and login process
* - Character selection and creation
* - World server communication
* - Packet processing and queuing
*/
class Client class Client
{ {
public: public:
Client(EQStream* ieqnc); /**
* @brief Constructs a new client instance
* @param ieqnc The EQStream connection for this client
*/
explicit Client(EQStream* ieqnc);
/**
* @brief Destructor - ensures proper cleanup of client resources
*/
~Client(); ~Client();
void SendLoginDenied();
void SendLoginDeniedBadVersion(); // Disable copy operations
void SendLoginAccepted(int32 account_id = 1, int8 login_response = 0); Client(const Client&) = delete;
void SendWorldList(); Client& operator=(const Client&) = delete;
void SendCharList();
int16 AddWorldToList2(uchar* buffer, char* name, int32 id, int16* flags); // Login response methods
void GenerateChecksum(EQApplicationPacket* outapp); /**
int8 LoginKey[10]; * @brief Sends a login denied message to the client
int8 ClientSession[25]; */
bool Process(); void SendLoginDenied();
void SaveErrorsToDB(EQApplicationPacket* app, char* type, int32 version);
void CharacterApproved(int32 server_id,int32 char_id); /**
void CharacterRejected(int8 reason_number); * @brief Sends a login denied message due to version mismatch
EQStream* getConnection() { return eqnc; } */
LoginAccount* GetLoginAccount() { return login_account; } void SendLoginDeniedBadVersion();
void SetLoginAccount(LoginAccount* in_account) {
login_account = in_account; /**
if(in_account) * @brief Sends a login accepted message to the client
account_id = in_account->getLoginAccountID(); * @param account_id The account ID (default: 1)
} * @param login_response The login response code (default: 0)
int16 GetVersion(){ return version; } */
char* GetKey() { return key; } void SendLoginAccepted(std::int32_t account_id = 1, std::int8_t login_response = 0);
void SetKey(char* in_key) { strcpy(key,in_key); }
int32 GetIP() { return ip; } // World and character list methods
int16 GetPort() { return port; } /**
int32 GetAccountID() { return account_id; } * @brief Sends the world server list to the client
const char* GetAccountName(){ return (char*)account_name.c_str(); } */
void SetAccountName(const char* name){ account_name = string(name); } void SendWorldList();
void ProcessLogin(char* name, char* pass,int seq=0);
void QueuePacket(EQ2Packet* app); /**
void FatalError(int8 response); * @brief Sends the character list to the client
void WorldResponse(int32 worldid, int8 response, char* ip_address, int32 port, int32 access_key); */
bool AwaitingCharCreationRequest(){ void SendCharList();
if(createRequest)
return true; /**
else * @brief Adds a world server to the list buffer
return false; * @param buffer Output buffer for world data
} * @param name World server name
Timer* updatetimer; * @param id World server ID
Timer* updatelisttimer; * @param flags World server flags
Timer* disconnectTimer; * @return Size of data written to buffer
//Timer* keepalive; */
//Timer* logintimer; std::int16_t AddWorldToList2(unsigned char* buffer, const char* name,
int16 packettotal; std::int32_t id, std::int16_t* flags);
int32 requested_server_id;
int32 request_num; /**
LinkedList<DelayQue*> delay_que; * @brief Generates checksum for outgoing packet
void SendPlayFailed(int8 response); * @param outapp Packet to generate checksum for
*/
void StartDisconnectTimer(); void GenerateChecksum(EQApplicationPacket* outapp);
/**
* @brief Main processing loop for the client
* @return true if client is still active, false if should be removed
*/
bool Process();
/**
* @brief Saves client error logs to database
* @param app Packet containing error data
* @param type Type of error log
* @param version Client version
*/
void SaveErrorsToDB(EQApplicationPacket* app, const char* type, std::int32_t version);
// Character management methods
/**
* @brief Handles character creation approval from world server
* @param server_id World server ID
* @param char_id New character ID
*/
void CharacterApproved(std::int32_t server_id, std::int32_t char_id);
/**
* @brief Handles character creation rejection
* @param reason_number Rejection reason code
*/
void CharacterRejected(std::int8_t reason_number);
/**
* @brief Processes login attempt
* @param name Account name
* @param pass Account password
* @param seq Sequence number (default: 0)
*/
void ProcessLogin(const char* name, const char* pass, int seq = 0);
/**
* @brief Queues a packet for sending to the client
* @param app Packet to queue
*/
void QueuePacket(EQ2Packet* app);
/**
* @brief Sends a fatal error to the client
* @param response Error response code
*/
void FatalError(std::int8_t response);
/**
* @brief Handles world server response for play request
* @param worldid World server ID
* @param response Response code
* @param ip_address World server IP
* @param port World server port
* @param access_key Access key for world server
*/
void WorldResponse(std::int32_t worldid, std::int8_t response,
char* ip_address, std::int32_t port, std::int32_t access_key);
/**
* @brief Sends play failed message to client
* @param response Failure reason code
*/
void SendPlayFailed(std::int8_t response);
/**
* @brief Starts the disconnect timer
*/
void StartDisconnectTimer();
// Getter methods
[[nodiscard]] EQStream* getConnection() { return eqnc_; }
[[nodiscard]] LoginAccount* GetLoginAccount() { return login_account_.get(); }
[[nodiscard]] std::int16_t GetVersion() const { return version_; }
[[nodiscard]] char* GetKey() { return key_; }
[[nodiscard]] std::int32_t GetIP() const { return ip_; }
[[nodiscard]] std::int16_t GetPort() const { return port_; }
[[nodiscard]] std::int32_t GetAccountID() const { return account_id_; }
[[nodiscard]] const char* GetAccountName() const { return account_name_.c_str(); }
[[nodiscard]] bool AwaitingCharCreationRequest() const { return createRequest_ != nullptr; }
// Setter methods
void SetLoginAccount(LoginAccount* in_account)
{
login_account_.reset(in_account);
if (in_account)
{
account_id_ = in_account->getLoginAccountID();
}
}
void SetKey(const char* in_key)
{
std::strncpy(key_, in_key, sizeof(key_) - 1);
key_[sizeof(key_) - 1] = '\0';
}
void SetAccountName(const char* name) { account_name_ = name; }
// Public data members (legacy compatibility)
std::int8_t LoginKey[10]{}; // Login key for authentication
std::int8_t ClientSession[25]{}; // Client session data
// Timers
std::unique_ptr<Timer> updatetimer; // Timer for periodic updates
std::unique_ptr<Timer> updatelisttimer; // Timer for world list updates
std::unique_ptr<Timer> disconnectTimer; // Timer for disconnect timeout
// Request tracking
std::int16_t packettotal{0}; // Total packets processed
std::int32_t requested_server_id{0}; // Requested world server ID
std::int32_t request_num{0}; // Current request number
// Delay queue for packet scheduling
LinkedList<DelayQue*> delay_que;
private: private:
string pending_play_char_name; // Character play state
int32 pending_play_char_id; std::string pending_play_char_name_; // Name of character pending play
int8 update_position; std::int32_t pending_play_char_id_{0}; // ID of character pending play
int16 num_updates;
vector<PacketStruct*>* update_packets; // Update state
LoginAccount* login_account; std::int8_t update_position_{0}; // Current position in update sequence
EQStream* eqnc; std::int16_t num_updates_{0}; // Number of updates sent
std::vector<PacketStruct*>* update_packets_{nullptr}; // Update packet queue
int32 ip;
int16 port; // Account information
std::unique_ptr<LoginAccount> login_account_; // Login account data
int32 account_id; EQStream* eqnc_; // Network connection stream
string account_name;
char key[10]; // Connection details
int8 lsadmin; std::int32_t ip_{0}; // Client IP address
sint16 worldadmin; std::int16_t port_{0}; // Client port
int lsstatus;
bool kicked; // Account data
bool verified; std::int32_t account_id_{0}; // Account ID in database
bool start; std::string account_name_; // Account name
bool needs_world_list; char key_[10]{}; // Authentication key
int16 version; std::int8_t lsadmin_{0}; // Login server admin level
char bannedreason[30]; std::int16_t worldadmin_{0}; // World server admin level
bool sent_character_list; int lsstatus_{0}; // Login server status
eLoginMode LoginMode;
PacketStruct* createRequest; // Client state flags
Timer* playWaitTimer; bool kicked_{false}; // Client has been kicked
bool verified_{false}; // Client has been verified
bool start_{false}; // Client has started
bool needs_world_list_{true}; // Client needs world list
bool sent_character_list_{false}; // Character list has been sent
// Version and mode
std::int16_t version_{0}; // Client version
LoginMode login_mode_{LoginMode::None}; // Current login mode
// Character creation
char bannedreason_[30]{}; // Ban reason if applicable
PacketStruct* createRequest_{nullptr}; // Pending character creation request
std::unique_ptr<Timer> playWaitTimer_; // Timer for play request timeout
}; };
/**
* @brief Manages all connected clients
*
* Thread-safe container for managing multiple client connections
*/
class ClientList class ClientList
{ {
public: public:
ClientList() {} /**
~ClientList() {} * @brief Default constructor
*/
void Add(Client* client); ClientList() = default;
Client* Get(int32 ip, int16 port);
Client* FindByLSID(int32 lsaccountid); /**
void FindByCreateRequest(); * @brief Destructor
void SendPacketToAllClients(EQ2Packet* app); */
void Process(); ~ClientList() = default;
// Disable copy operations
ClientList(const ClientList&) = delete;
ClientList& operator=(const ClientList&) = delete;
/**
* @brief Adds a client to the list
* @param client Client to add
*/
void Add(Client* client);
/**
* @brief Finds a client by IP and port
* @param ip Client IP address
* @param port Client port
* @return Pointer to client if found, nullptr otherwise
*/
[[nodiscard]] Client* Get(std::int32_t ip, std::int16_t port);
/**
* @brief Finds a client by login server account ID
* @param lsaccountid Login server account ID
* @return Pointer to client if found, nullptr otherwise
*/
[[nodiscard]] Client* FindByLSID(std::int32_t lsaccountid);
/**
* @brief Finds clients waiting for character creation response
*/
void FindByCreateRequest();
/**
* @brief Sends a packet to all connected clients
* @param app Packet to send
*/
void SendPacketToAllClients(EQ2Packet* app);
/**
* @brief Processes all clients in the list
*/
void Process();
private: private:
Mutex MClientList; mutable std::mutex mutex_; // Mutex for thread safety
map<Client*, bool> client_list; std::map<Client*, bool> client_list_; // Map of clients to active status
}; };
class DelayQue {
/**
* @brief Delayed packet queue entry
*
* Holds a packet with an associated timer for delayed sending
*/
class DelayQue
{
public: public:
DelayQue(Timer* in_timer, EQApplicationPacket* in_packet){ /**
timer = in_timer; * @brief Constructs a delayed queue entry
packet = in_packet; * @param in_timer Timer for delay
}; * @param in_packet Packet to delay
Timer* timer; */
EQApplicationPacket* packet; DelayQue(Timer* in_timer, EQApplicationPacket* in_packet)
}; : timer(in_timer)
#endif , packet(in_packet)
{
}
Timer* timer; // Timer controlling the delay
EQApplicationPacket* packet; // Packet to be sent after delay
};