#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_