login/src/login.hh
2025-08-15 14:59:56 -03:00

402 lines
9.6 KiB
C++

#ifndef TIBIA_LOGIN_HH_
#define TIBIA_LOGIN_HH_ 1
#include "common.hh"
// Shutdown Signal
extern int g_ShutdownSignal;
// Time
extern int g_MonotonicTimeMS;
// Config
extern char g_Motd[256];
extern int g_UpdateRate;
extern int g_LoginPort;
extern int g_MaxConnections;
extern int g_LoginTimeout;
extern char g_QueryManagerHost[100];
extern int g_QueryManagerPort;
extern char g_QueryManagerPassword[30];
// Buffer Utility
//==============================================================================
inline uint8 BufferRead8(const uint8 *Buffer){
return Buffer[0];
}
inline uint16 BufferRead16LE(const uint8 *Buffer){
return (uint16)Buffer[0]
| ((uint16)Buffer[1] << 8);
}
inline uint16 BufferRead16BE(const uint8 *Buffer){
return ((uint16)Buffer[0] << 8)
| (uint16)Buffer[1];
}
inline uint32 BufferRead32LE(const uint8 *Buffer){
return (uint32)Buffer[0]
| ((uint32)Buffer[1] << 8)
| ((uint32)Buffer[2] << 16)
| ((uint32)Buffer[3] << 24);
}
inline uint32 BufferRead32BE(const uint8 *Buffer){
return ((uint32)Buffer[0] << 24)
| ((uint32)Buffer[1] << 16)
| ((uint32)Buffer[2] << 8)
| (uint32)Buffer[3];
}
inline uint64 BufferRead64LE(const uint8 *Buffer){
return (uint64)Buffer[0]
| ((uint64)Buffer[1] << 8)
| ((uint64)Buffer[2] << 16)
| ((uint64)Buffer[3] << 24)
| ((uint64)Buffer[4] << 32)
| ((uint64)Buffer[5] << 40)
| ((uint64)Buffer[6] << 48)
| ((uint64)Buffer[7] << 56);
}
inline uint64 BufferRead64BE(const uint8 *Buffer){
return ((uint64)Buffer[0] << 56)
| ((uint64)Buffer[1] << 48)
| ((uint64)Buffer[2] << 40)
| ((uint64)Buffer[3] << 32)
| ((uint64)Buffer[4] << 24)
| ((uint64)Buffer[5] << 16)
| ((uint64)Buffer[6] << 8)
| (uint64)Buffer[7];
}
inline void BufferWrite8(uint8 *Buffer, uint8 Value){
Buffer[0] = Value;
}
inline void BufferWrite16LE(uint8 *Buffer, uint16 Value){
Buffer[0] = (uint8)(Value >> 0);
Buffer[1] = (uint8)(Value >> 8);
}
inline void BufferWrite16BE(uint8 *Buffer, uint16 Value){
Buffer[0] = (uint8)(Value >> 8);
Buffer[1] = (uint8)(Value >> 0);
}
inline void BufferWrite32LE(uint8 *Buffer, uint32 Value){
Buffer[0] = (uint8)(Value >> 0);
Buffer[1] = (uint8)(Value >> 8);
Buffer[2] = (uint8)(Value >> 16);
Buffer[3] = (uint8)(Value >> 24);
}
inline void BufferWrite32BE(uint8 *Buffer, uint32 Value){
Buffer[0] = (uint8)(Value >> 24);
Buffer[1] = (uint8)(Value >> 16);
Buffer[2] = (uint8)(Value >> 8);
Buffer[3] = (uint8)(Value >> 0);
}
inline void BufferWrite64LE(uint8 *Buffer, uint64 Value){
Buffer[0] = (uint8)(Value >> 0);
Buffer[1] = (uint8)(Value >> 8);
Buffer[2] = (uint8)(Value >> 16);
Buffer[3] = (uint8)(Value >> 24);
Buffer[4] = (uint8)(Value >> 32);
Buffer[5] = (uint8)(Value >> 40);
Buffer[6] = (uint8)(Value >> 48);
Buffer[7] = (uint8)(Value >> 56);
}
inline void BufferWrite64BE(uint8 *Buffer, uint64 Value){
Buffer[0] = (uint8)(Value >> 56);
Buffer[1] = (uint8)(Value >> 48);
Buffer[2] = (uint8)(Value >> 40);
Buffer[3] = (uint8)(Value >> 32);
Buffer[4] = (uint8)(Value >> 24);
Buffer[5] = (uint8)(Value >> 16);
Buffer[6] = (uint8)(Value >> 8);
Buffer[7] = (uint8)(Value >> 0);
}
struct TReadBuffer{
uint8 *Buffer;
int Size;
int Position;
TReadBuffer(void) : TReadBuffer(NULL, 0) {}
TReadBuffer(uint8 *Buffer, int Size)
: Buffer(Buffer), Size(Size), Position(0) {}
bool CanRead(int Bytes){
return (this->Position + Bytes) <= this->Size;
}
bool Overflowed(void){
return this->Position > this->Size;
}
bool ReadFlag(void){
return this->Read8() != 0x00;
}
uint8 Read8(void){
uint8 Result = 0;
if(this->CanRead(1)){
Result = BufferRead8(this->Buffer + this->Position);
}
this->Position += 1;
return Result;
}
uint16 Read16(void){
uint16 Result = 0;
if(this->CanRead(2)){
Result = BufferRead16LE(this->Buffer + this->Position);
}
this->Position += 2;
return Result;
}
uint16 Read16BE(void){
uint16 Result = 0;
if(this->CanRead(2)){
Result = BufferRead16BE(this->Buffer + this->Position);
}
this->Position += 2;
return Result;
}
uint32 Read32(void){
uint32 Result = 0;
if(this->CanRead(4)){
Result = BufferRead32LE(this->Buffer + this->Position);
}
this->Position += 4;
return Result;
}
uint32 Read32BE(void){
uint32 Result = 0;
if(this->CanRead(4)){
Result = BufferRead32BE(this->Buffer + this->Position);
}
this->Position += 4;
return Result;
}
void ReadString(char *Dest, int DestCapacity){
int Length = (int)this->Read16();
if(Length == 0xFFFF){
Length = (int)this->Read32();
}
if(Dest != NULL && DestCapacity > 0){
if(Length < DestCapacity && this->CanRead(Length)){
memcpy(Dest, this->Buffer + this->Position, Length);
Dest[Length] = 0;
}else{
Dest[0] = 0;
}
}
this->Position += Length;
}
void ReadBytes(uint8 *Buffer, int Count){
if(this->CanRead(Count)){
memcpy(Buffer, this->Buffer + this->Position, Count);
}
this->Position += Count;
}
};
struct TWriteBuffer{
uint8 *Buffer;
int Size;
int Position;
TWriteBuffer(void) : TWriteBuffer(NULL, 0) {}
TWriteBuffer(uint8 *Buffer, int Size)
: Buffer(Buffer), Size(Size), Position(0) {}
bool CanWrite(int Bytes){
return (this->Position + Bytes) <= this->Size;
}
bool Overflowed(void){
return this->Position > this->Size;
}
void WriteFlag(bool Value){
this->Write8(Value ? 0x01 : 0x00);
}
void Write8(uint8 Value){
if(this->CanWrite(1)){
BufferWrite8(this->Buffer + this->Position, Value);
}
this->Position += 1;
}
void Write16(uint16 Value){
if(this->CanWrite(2)){
BufferWrite16LE(this->Buffer + this->Position, Value);
}
this->Position += 2;
}
void Write16BE(uint16 Value){
if(this->CanWrite(2)){
BufferWrite16BE(this->Buffer + this->Position, Value);
}
this->Position += 2;
}
void Write32(uint32 Value){
if(this->CanWrite(4)){
BufferWrite32LE(this->Buffer + this->Position, Value);
}
this->Position += 4;
}
void Write32BE(uint32 Value){
if(this->CanWrite(4)){
BufferWrite32BE(this->Buffer + this->Position, Value);
}
this->Position += 4;
}
void WriteString(const char *String){
int StringLength = 0;
if(String != NULL){
StringLength = (int)strlen(String);
}
if(StringLength < 0xFFFF){
this->Write16((uint16)StringLength);
}else{
this->Write16(0xFFFF);
this->Write32((uint32)StringLength);
}
if(StringLength > 0 && this->CanWrite(StringLength)){
memcpy(this->Buffer + this->Position, String, StringLength);
}
this->Position += StringLength;
}
void Rewrite16(int Position, uint16 Value){
if((Position + 2) <= this->Position && !this->Overflowed()){
BufferWrite16LE(this->Buffer + Position, Value);
}
}
void Insert32(int Position, uint32 Value){
if(Position <= this->Position){
if(this->CanWrite(4)){
memmove(this->Buffer + Position + 4,
this->Buffer + Position,
this->Position - Position);
BufferWrite32LE(this->Buffer + Position, Value);
}
this->Position += 4;
}
}
};
// crypto.cc
//==============================================================================
typedef void RSAKey;
RSAKey *RSALoadPEM(const char *FileName);
void RSAFree(RSAKey *Key);
bool RSADecrypt(RSAKey *Key, uint8 *Data, int Size);
void XTEAEncrypt(const uint32 *Key, uint8 *Data, int Size);
void XTEADecrypt(const uint32 *Key, uint8 *Data, int Size);
// query.cc
//==============================================================================
enum : int {
APPLICATION_TYPE_GAME = 1,
APPLICATION_TYPE_LOGIN = 2,
APPLICATION_TYPE_WEB = 3,
};
enum : int {
QUERY_STATUS_OK = 0,
QUERY_STATUS_ERROR = 1,
QUERY_STATUS_FAILED = 3,
};
struct TCharacterLoginData{
char Name[30];
char WorldName[30];
int WorldAddress;
int WorldPort;
};
struct TQueryManagerConnection{
int Socket;
uint8 Buffer[KB(16)];
};
bool Connect(TQueryManagerConnection *Connection);
void Disconnect(TQueryManagerConnection *Connection);
bool IsConnected(TQueryManagerConnection *Connection);
TWriteBuffer PrepareQuery(TQueryManagerConnection *Connection, int QueryType);
int ExecuteQuery(TQueryManagerConnection *Connection, bool AutoReconnect,
TWriteBuffer *WriteBuffer, TReadBuffer *OutReadBuffer);
int LoginAccount(int AccountID, const char *Password, const char *IPAddress,
int MaxCharacters, int *NumCharacters, TCharacterLoginData *Characters,
int *PremiumDays);
bool InitQuery(void);
void ExitQuery(void);
// connections.cc
//==============================================================================
enum ConnectionState{
CONNECTION_FREE = 0,
CONNECTION_HANDSHAKE = 1,
CONNECTION_LOGIN = 2,
CONNECTION_WRITE = 3,
};
struct TConnection{
ConnectionState State;
int Socket;
int StartTime;
int RWSize;
int RWPosition;
uint32 RandomSeed;
uint32 XTEA[4];
char IPAddress[16];
char RemoteAddress[30];
uint8 Buffer[KB(2)];
};
int ListenerBind(uint16 Port);
int ListenerAccept(int Listener, uint32 *OutAddr, uint16 *OutPort);
void CloseConnection(TConnection *Connection);
TConnection *AssignConnection(int Socket, uint32 Addr, uint16 Port);
void ReleaseConnection(TConnection *Connection);
void ProcessLoginRequest(TConnection *Connection);
void CheckConnectionInput(TConnection *Connection, int Events);
void CheckConnectionOutput(TConnection *Connection, int Events);
void CheckConnection(TConnection *Connection, int Events);
void ProcessConnections(void);
bool InitConnections(void);
void ExitConnections(void);
TWriteBuffer PrepareResponse(TConnection *Connection);
void SendResponse(TConnection *Connection, TWriteBuffer *WriteBuffer);
void SendLoginError(TConnection *Connection, const char *Message);
void SendCharacterList(TConnection *Connection, int NumCharacters,
TCharacterLoginData *Characters, int PremiumDays);
void ProcessLoginRequest(TConnection *Connection);
#endif //TIBIA_LOGIN_HH_