bool PPatchServer::ProcessClient(PClient *Client, PPatchState *State) { static const u8 HANDSHAKE0A[6]={0xfe, 0x03, 0x00, 0x80, 0x03, 0x6b}; if(!State) { PatchStateMap::iterator node = ClientStates.find(Client); if(node == ClientStates.end()) return false; State = node->second; } ConnectionTCP *Socket = Client->getTCPConn(); if(State->mWaitSend && Socket->getSendBufferSize()==0) return false; if(State->mState==PPatchState::PS_CONNECTED) { Console->Print("Sending Handshake 0A"); Socket->write(HANDSHAKE0A, sizeof(HANDSHAKE0A)); //short unsigned int packet = (short unsigned int) HANDSHAKE0A; //Socket->write(htons(packet)); State->mState = PPatchState::PS_HANDSHAKE0; Socket->flushSendBuffer(); } int PacketSize=0; const u8 *Packet = Socket->read(&PacketSize); if(PacketSize > 0) { switch(State->mState) { case PPatchState::PS_HANDSHAKE1 : case PPatchState::PS_HANDSHAKE0 : Console->Print("Handling Handshake 0 and 1"); return HandleHandshake(Client, State, Packet, PacketSize); case PPatchState::PS_VERSIONREQUEST : Console->Print("Handling Client Versionsrequest"); return HandleVersionRequest(Client, State, Packet, PacketSize); case PPatchState::PS_GETPATCHORFILE : case PPatchState::PS_SENDPATCH : case PPatchState::PS_SENDFILE : Console->Print("Getpatchforfile, sendpatch, sendfile"); return HandleFileRequests(Client, State, Packet, PacketSize); default: break; } } return true; }
bool PGameServer::HandleGameData( PClient *Client, PGameState *State, const u8 *Packet ) { static const u8 GAMEDATA[5] = {0xfe, 0x02, 0x00, 0x87, 0x3a}; ConnectionTCP *Socket = Client->getTCPConn(); if ( *( u16* )&Packet[3] == 0x3787 ) { Socket->write( GAMEDATA, 5 ); State->TCP.mState = PGameState::TCP::GS_REQUESTCHARS; } else { Console->Print( RED, BLACK, "[Notice] Gameserver protocol error (GS_GAMEDATA): invalid packet [%04x]", *( u16* )&Packet[3] ); return ( false ); } return ( true ); }
bool PGameServer::HandleGetStatus( PClient *Client, PGameState *State, const u8 *Packet ) { ConnectionTCP *Socket = Client->getTCPConn(); if ( *( u16* )&Packet[3] == 0x3787 ) { static const u8 STATUS[9] = {0xfe, 0x06, 0x00, 0x87, 0x3a, 0x11, 0x00, 0x00, 0x00}; Socket->write( STATUS, 9 ); State->TCP.mState = PGameState::TCP::GS_GAMEINFO; } else { Console->Print( RED, BLACK, "[Notice] Gameserver protocol error (GS_GETSTATUS): invalid packet [%04x]", *( u16* )&Packet[3] ); return ( false ); } return ( true ); }
bool PPatchServer::HandleVersionRequest(PClient *Client, PPatchState *State, const u8 *Packet, int PacketSize) { static u8 VERSIONPACKET[13]={0xfe, 0x0a, 0x00, 0x37, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; ConnectionTCP *Socket = Client->getTCPConn(); if(PacketSize==9 && *(u16*)&Packet[3]==0x007b) { State->mSerial = *(u16*)&Packet[7]; *(u16*)&VERSIONPACKET[7]=State->mSerial; u32 ver = Config->GetOptionInt("server_version"); *(u32*)&VERSIONPACKET[9]=ver; Socket->write(VERSIONPACKET, 13); State->mState = PPatchState::PS_GETPATCHORFILE; } else { Console->Print("Patchserver protocol error (PS_VERSIONREQUEST): invalid packet [%04x]", *(u16*)&Packet[3]); return false; } return true; }
bool PPatchServer::HandleHandshake(PClient *Client, PPatchState *State, const u8 *Packet, int PacketSize) { static const u8 HANDSHAKE1A[6]={0xfe, 0x03, 0x00, 0x80, 0x01, 0x73}; ConnectionTCP *Socket = Client->getTCPConn(); switch(State->mState) { case PPatchState::PS_HANDSHAKE0 : { if(PacketSize==6 && *(u16*)&Packet[3]==0x0280 && Packet[5]==0x64) { Socket->write(HANDSHAKE1A, sizeof(HANDSHAKE1A)); State->mState = PPatchState::PS_HANDSHAKE1; } else { Console->Print("Patchserver protocol error (PS_HANDSHAKE0): invalid packet [%04x]", *(u16*)&Packet[3]); return false; } break; } case PPatchState::PS_HANDSHAKE1 : { if(PacketSize==6 && *(u16*)&Packet[3]==0x0080 && Packet[5]==0x6c) State->mState = PPatchState::PS_VERSIONREQUEST; else { Console->Print("Patchserver protocol error (PS_HANDSHAKE1): invalid packet [%04x]", *(u16*)&Packet[3]); return false; } break; } default: break; } return true; }
bool PGameServer::ProcessClient( PClient *Client, PGameState *State ) { static const u8 HANDSHAKE0A[6] = {0xfe, 0x03, 0x00, 0x80, 0x01, 0x66}; if ( !State ) { GameStateMap::iterator node = ClientStates.find( Client ); if ( node == ClientStates.end() ) return ( false ); State = node->second; } ConnectionTCP *Socket = Client->getTCPConn(); if ( !Socket ) Console->Print( RED, BLACK, "PANIC: Client %d : TCP Socket is NULL !!!", Client->GetID() ); if ( State->TCP.mWaitSend && Socket->getSendBufferSize() == 0 ) return ( false ); if ( State->TCP.mState == PGameState::TCP::GS_CONNECTED ) { Socket->write( HANDSHAKE0A, 6 ); State->TCP.mState = PGameState::TCP::GS_HANDSHAKE0; } if ( State->TCP.mState == PGameState::TCP::GS_INGAME ) { return ( HandleGame( Client, State ) ); } else { int PacketSize = 0; const u8 *Packet = Socket->read( &PacketSize ); if ( PacketSize > 0 ) { switch ( State->TCP.mState ) { case PGameState::TCP::GS_HANDSHAKE0: return ( HandleHandshake( State, Packet, PacketSize ) ); case PGameState::TCP::GS_AUTHENTICATE: return ( HandleAuthenticate( Client, State, Packet, PacketSize ) ); case PGameState::TCP::GS_GAMEDATA: return ( HandleGameData( Client, State, Packet ) ); case PGameState::TCP::GS_REQUESTCHARS: return ( HandleRequestChars( Client, State, Packet ) ); case PGameState::TCP::GS_CHARLIST: return ( HandleCharList( Client, State, Packet, PacketSize ) ); case PGameState::TCP::GS_GETSTATUS: return ( HandleGetStatus( Client, State, Packet ) ); case PGameState::TCP::GS_GAMEINFO: return ( HandleGameInfo( Client, State, Packet ) ); default: break; } } } return ( true ); }
bool PGameServer::HandleGameInfo( PClient *Client, PGameState *State, const u8 *Packet ) { // Console->Print("Inside HandleGameInfo");//NEW added static u8 GameInfo[31] = {0xfe, 0x1c, 0x00, 0x83, 0x05, // header 0x00, 0x00, 0x00, 0x00, // account id 0x00, 0x00, 0x00, 0x00, // char id 0x00, 0x00, 0x00, 0x00, // udp ip 0x00, 0x00, // udp port 0x00, 0x00, 0x00, 0x00, // unknown 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // session key }; ConnectionTCP *Socket = Client->getTCPConn(); if ( *( u16* )&Packet[3] == 0x3c87 ) { //int PortFix = Config->GetOptionInt("debug_mode"); ConnectionUDP* udpConn = ServerSock->getUDPConnection( IPStringToDWord( Client->GetAddress() ), Client->GetRemoteUDPPort() ); Client->setUDPConnection( udpConn ); if ( !udpConn ) { Console->Print( RED, BLACK, "Client %d: UDP port setup failed", Client->GetID() ); ClientDisconnected( Client ); } u16 Port = Client->getUDPConn()->getPort(); if ( Port == 0 ) Console->Print( RED, BLACK, "Client->OpenUDP() failed" ); /* if(PortFix == 1) // removed, no more use { Port = Config->GetOptionInt("useudpport"); Console->Print(YELLOW, BLACK, "UDP Port set to non-standard for debugging!"); }; */ u32 IP; std::string IPServerString; // use [server_nat_ip] for server if client is NOT on [no_nat_net] (and [no_nat_net]!=0) if ( strcmp( Config->GetOption( "no_nat_net" ).c_str(), "0" ) && strncmp( Client->GetAddress(), Config->GetOption( "no_nat_net" ).c_str(), strlen( Config->GetOption( "no_nat_net" ).c_str() ) ) ) { IPServerString = Config->GetOption( "server_nat_ip" ); } else // else client is "local" so use [server_ip] { IPServerString = Config->GetOption( "server_ip" ); } IP = IPStringToDWord( IPServerString.c_str() ); //Console->Print("IP-1 %d", IP); if ( IP == 0 ) IP = 0x0100007f; //Console->Print("IP-2 %d", IP); *( u32* )&GameInfo[13] = IP; *( u16* )&GameInfo[17] = Port; Console->Print( GREEN, BLACK, "[Info] Using UDP %s:%d on server", IPServerString.c_str(), Port ); *( u32* )&GameInfo[5] = Client->GetAccountID(); *( u32* )&GameInfo[9] = Client->GetCharID(); Console->Print( GREEN, BLACK, "[Info] Serving char id :%d", Client->GetCharID() ); Socket->write( GameInfo, 31 ); Socket->flushSendBuffer(); static const u8 READY[7] = {0xfe, 0x04, 0x00, 0x83, 0x0d, 0x00, 0x00}; Socket->write( READY, 7 ); State->TCP.mState = PGameState::TCP::GS_INGAME; State->UDP.mState = PGameState::UDP::GUS_SYNC0; //Console->Print("Sync Reset"); Client->ResetTransactionID(); // Mark char as Online PChar *Char = Client->GetChar(); Char->SetOnlineStatus( true ); //Also using this info to check if Char may have to be saved at client disconnect Client->ChangeCharLocation( Char->GetLocation(), true ); // hello-message from server.. /* std::string serverName = Config->GetOption("server_name"); std::string helloMessage = "Welcome to " + serverName + " - A TinNS Neocron Server."; char* message = (char*) helloMessage.c_str(); Chat->send(Client, CHAT_DIRECT, "System", message, false); */ bool SendBC = false; if ( Config->GetOptionInt( "broadcast_new" ) == 1 ) { if ( Config->GetOptionInt( "broadcast_new_hidestaff" ) == 1 ) { if ( Client->GetAccountLevel() > PAL_REGPLAYER ) SendBC = false; else SendBC = true; } else { SendBC = true; } } if ( SendBC == true ) { std::string playerName = Chars->GetChar( Client->GetCharID() )->GetName(); std::string serverName = Config->GetOption( "server_name" ); std::string helloMessage = "Hello " + playerName + "! Welcome to " + serverName + " - A TinNS Neocron Server."; char* message = ( char* ) helloMessage.c_str(); Chat->sendOOCBroadcast( message ); } //Console->Print("UDP Setup: %s", nlGetErrorStr(nlGetError())); } else { Console->Print( RED, BLACK, "[Notice] Gameserver protocol error (GS_GAMEINFO): invalid packet [%04x]", *( u16* )&Packet[3] ); return ( false ); } return ( true ); }
bool PGameServer::HandleCharList( PClient *Client, PGameState *State, const u8 *Packet, int PacketSize ) { static u8 Answer[10] = {0xfe, 0x07, 0x00, 0x83, 0x86, 0, 0, 0, 0, 0}; ConnectionTCP *Socket = Client->getTCPConn(); if ( PacketSize > 9 && *( u16* )&Packet[3] == 0x8284 ) { u8 Mode = Packet[9]; switch ( Mode ) { case 6: // request list return ( HandleRequestChars( Client, State, Packet ) ); case 5: // validate name { if ( PacketSize < 31 ) return ( false ); // check for valid name string bool ValidString = false; for ( int i = 30; i < PacketSize; i++ ) if ( Packet[i] == 0 ) { ValidString = true; break; } const char *Name = ( char* ) & Packet[30]; if ( ValidString ) { ValidString = PChar::IsCharnameWellFormed( Name ); } if ( ValidString ) { if ( Chars->CharExist( std::string( Name ) ) ) { ValidString = false; } } if ( ValidString ) Answer[5] = 1; // ok else Answer[5] = 2; // 2..6 => 'char name already in use!' // Answer[5] = 0; // => 'unknown error' Socket->write( Answer, 10 ); return ( true ); } case 3: // delete char { PAccount Acc( Client->GetAccountID() ); u8 Num = Packet[PacketSize-1]; if ( Acc.GetID() ) { u32 CharID = Acc.GetCharIdBySlot( Num ); // Also check that char is out of game if (( CharID != 0 ) && ( Chars->GetChar( CharID ) == NULL ) ) { char query[100]; snprintf( query, 100, "DELETE FROM characters WHERE c_id = %d LIMIT 1", CharID ); if ( MySQL->GameQuery( query ) ) Console->Print( RED, BLACK, "[Notice] Char %d not deleted!", CharID ); else { Console->Print( GREEN, BLACK, "[Info] Char %d deleted!", CharID ); snprintf( query, 100, "DELETE FROM buddy_list WHERE bud_charid = %d", CharID ); if ( MySQL->GameQuery( query ) ) Console->Print( YELLOW, BLACK, "[Notice] Char %d's buddy list not removed!", CharID ); snprintf( query, 100, "DELETE FROM genrep WHERE g_charid = %d", CharID ); if ( MySQL->GameQuery( query ) ) Console->Print( YELLOW, BLACK, "[Notice] Char %d's genrep list not removed!", CharID ); snprintf( query, 100, "DELETE FROM inventory WHERE inv_charid = %d", CharID ); if ( MySQL->GameQuery( query ) ) Console->Print( YELLOW, BLACK, "[Notice] Char %d's inventory not removed!", CharID ); Appartements->DeleteCharAppartements( CharID ); } } else return false; } return ( true ); } case 7: // create char { if ( PacketSize < 64 ) return ( false ); u32 Slot = * ( u32* ) & Packet[30]; //u32 nClass =* (u32*)&Packet[34]; // Not used - indirectly redundant with Profession u32 Profession = * ( u32* ) & Packet[38]; u32 Gender = * ( u32* ) & Packet[42]; u32 Head = * ( u32* ) & Packet[46]; u32 Torso = * ( u32* ) & Packet[50]; u32 Legs = * ( u32* ) & Packet[54]; u32 Faction = * ( u32* ) & Packet[58]; u8 NameLen = Packet[62]; u8 NZSNb = Packet[63]; char TempName[256]; std::strncpy( TempName, ( const char* )&Packet[64], NameLen ); TempName[NameLen] = 0; Answer[5] = 2; // return error if char creation fails if ( PChar::IsCharnameWellFormed( TempName ) ) { // check for already used char name - should not happen though if ( ! Chars->CharExist( std::string( TempName ) ) ) { PAccount Acc( Client->GetAccountID() ); PChar* nChar = new PChar(); if ( nChar->CreateNewChar( Acc.GetID(), TempName, Gender, Profession, Faction, Head, Torso, Legs, NZSNb, ( const char* )&Packet[64+NameLen], Slot ) ) { Answer[5] = 1; // return success } delete nChar; } } Socket->write( Answer, 10 ); return ( true ); } } } else { Console->Print( RED, BLACK, "[Notice] Gameserver protocol error (GS_CHARLIST): invalid packet [%04x]", *( u16* )&Packet[3] ); return ( false ); } return true; }
bool PGameServer::HandleRequestChars( PClient *Client, PGameState *State, const u8 *Packet ) { PAccount Account( Client->GetAccountID() ); if ( !Account.GetID() ) return false; ConnectionTCP *Socket = Client->getTCPConn(); struct PCharList { u16 Unknown1; u16 NumSlots; u16 Unknown2; } CharList; PCharProfile CharEntry[MAX_CHARS_PER_ACCOUNT]; const int CHARBASESIZE = 28; if ( *( u16* )&Packet[3] == 0x8284 ) { CharList.NumSlots = MAX_CHARS_PER_ACCOUNT; int NameLengths = 0; for ( int i = 0; i < MAX_CHARS_PER_ACCOUNT; i++ ) { CharEntry[i].CharID = 0; CharEntry[i].Type = 0; CharEntry[i].Color0 = 0; CharEntry[i].Location = 1; CharEntry[i].Unknown1 = 0; CharEntry[i].Head = 0; CharEntry[i].Torso = 0; CharEntry[i].Legs = 0; CharEntry[i].Unknown3 = 1; CharEntry[i].Unknown4 = 1; CharEntry[i].Unknown5 = 1; CharEntry[i].Unknown6 = 1; CharEntry[i].Unknown7 = 1; CharEntry[i].Unknown8 = 0; CharEntry[i].Unknown9 = 0; CharEntry[i].Unknown10 = 0; CharEntry[i].Unknown11 = 0; CharEntry[i].Unknown12 = 0; CharEntry[i].in_use = false; } Chars->GetCharProfiles( Account.GetID(), CharEntry, MAX_CHARS_PER_ACCOUNT ); for ( int i = 0; i < MAX_CHARS_PER_ACCOUNT; i++ ) { if ( CharEntry[i].in_use ) { NameLengths += CharEntry[i].NameLen; } else { CharEntry[i].CharID = 0xffffffff; CharEntry[i].NameLen = 0; } } u8 PacketHeader[5] = {0xfe, 0x00, 0x00, 0x83, 0x85}; *( u16* )&PacketHeader[1] = sizeof( u16 ) * 3 + ( MAX_CHARS_PER_ACCOUNT * CHARBASESIZE ) + NameLengths + 2; Socket->write( PacketHeader, 5 ); CharList.Unknown1 = 0x0000; CharList.Unknown2 = CHARBASESIZE; Socket->write( CharList.Unknown1 ); Socket->write( CharList.NumSlots ); Socket->write( CharList.Unknown2 ); for ( int i = 0; i < MAX_CHARS_PER_ACCOUNT; i++ ) { Socket->write( CharEntry[i].CharID ); Socket->write( CharEntry[i].Type ); Socket->write( CharEntry[i].Color0 ); Socket->write( CharEntry[i].Unknown1 ); Socket->write( CharEntry[i].Head ); Socket->write( CharEntry[i].Torso ); Socket->write( CharEntry[i].Legs ); Socket->write( CharEntry[i].Location ); Socket->write( CharEntry[i].NameLen ); Socket->write( CharEntry[i].Unknown3 ); Socket->write( CharEntry[i].Unknown4 ); Socket->write( CharEntry[i].Unknown5 ); Socket->write( CharEntry[i].Unknown6 ); Socket->write( CharEntry[i].Unknown7 ); Socket->write( CharEntry[i].Unknown8 ); Socket->write( CharEntry[i].Unknown9 ); Socket->write( CharEntry[i].Unknown10 ); Socket->write( CharEntry[i].Unknown11 ); Socket->write( CharEntry[i].Unknown12 ); if ( CharEntry[i].Name.length() > 0 ) { Socket->write( CharEntry[i].Name.c_str() ); Socket->write(( u8 )0 ); } } State->TCP.mState = PGameState::TCP::GS_CHARLIST; } else { Console->Print( RED, BLACK, "Gameserver protocol error (GS_REQUESTCHARS): invalid packet [%04x]", *( u16* )&Packet[3] ); return ( false ); } return ( true ); }
bool PGameServer::HandleAuthenticate( PClient *Client, PGameState *State, const u8 *Packet, int PacketSize ) { ConnectionTCP *Socket = Client->getTCPConn(); if ( PacketSize > 20 && *( u16* )&Packet[3] == 0x8084 ) { // authentication method #1 const u8 *Key = &Packet[5]; // password key u16 ULen = *( u16* ) & Packet[16]; // username length u16 PLen = *( u16* ) & Packet[18]; // password length char *UserName = ( char* ) & Packet[20]; // account name const u8 *PW = &Packet[20+ULen]; // encoded password // Safety controls if ( 15 + ULen + PLen > PacketSize ) { Console->Print( RED, BLACK, "[Notice] Gameserver protocol error (GS_AUTHENTICATE): Exessive internal size fields" ); return false; } if ( strnlen( UserName, ULen ) == ULen ) { Console->Print( RED, BLACK, "[Notice] Gameserver protocol error (GS_AUTHENTICATE): non-terminated username field" ); return false; } bool Failed = false; PAccount Account( UserName ); if ( Account.GetID() == 0 ) { Console->Print( YELLOW, BLACK, "[Info] Gameserver: Unknown user %s", UserName ); Failed = true; } else if ( !Account.Authenticate( PW, PLen, Key ) ) { Console->Print( YELLOW, BLACK, "[Info] Gameserver: User '%s': authentication failed", UserName ); Failed = true; } if ( !Failed ) { Console->Print( GREEN, BLACK, "[Info] Gameserver: User '%s' authentication successful", UserName ); if ( Account.GetLevel() == PAL_BANNED ) { Console->Print( YELLOW, BLACK, "[Info] User %s is banned, connection refused", UserName ); // TODO: ban ip for an adjustable time span? Failed = true; // player is banned } if ( Account.GetLevel() == PAL_UNREGPLAYER || Account.GetLevel() == PAL_REGPLAYER ) { if ( Server->GetNumClients() > Server->GetMaxClients() ) { Console->Print( YELLOW, BLACK, "[Info] Server full, refusing connection from user '%s'", UserName ); Failed = true; // server full } } } if ( Failed ) { // TODO: is this packet correct here? u8 AUTHFAILED[15] = {0xfe, 0x0c, 0x00, 0x83, 0x86, 0x05, 0x00, 0x06, 0x00, 'E', 'R', 'R', 'O', 'R', 0 }; // TODO: send actual reason instead of ERROR Socket->write( AUTHFAILED, 15 ); FinalizeClientDelayed( Client, State ); State->TCP.mState = PGameState::TCP::GS_UNKNOWN; Console->Print( YELLOW, BLACK, "[Info] Gameserver: User '%s' login refused", UserName ); } else { Client->LoggedIn( &Account ); u8 AUTHOK[28] = {0xfe, 0x19, 0x00, 0x83, 0x81, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; *( u32* )&AUTHOK[5] = Account.GetID(); Socket->write( AUTHOK, 28 ); State->TCP.mState = PGameState::TCP::GS_GAMEDATA; Console->Print( GREEN, BLACK, "[Info] Gameserver: User '%s' logged in", UserName ); } } else if ( PacketSize > 29 && *( u16* )&Packet[3] == 0x0183 ) { // authentication method #2, sent when game starts const u8 *Key = &Packet[13]; // password key u16 PLen = *( u16* ) & Packet[25]; // password length u16 ULen = *( u16* ) & Packet[27]; // username length char *UserName = ( char* ) & Packet[29]; // account name const u8 *PW = &Packet[29+ULen]; // encoded password // Safety controls if ( 24 + ULen + PLen > PacketSize ) { Console->Print( RED, BLACK, "[Notice] Gameserver protocol error (GS_AUTHENTICATE): Exessive internal size fields" ); return false; } if ( strnlen( UserName, ULen ) == ULen ) { Console->Print( RED, BLACK, "[Notice] Gameserver protocol error (GS_AUTHENTICATE): non-terminated username field" ); return false; } bool Failed = false; PAccount Account( UserName ); if ( Account.GetID() == 0 ) { Console->Print( YELLOW, BLACK, "[Info] Gameserver: Unknown user %s", UserName ); Failed = true; } else if ( !Account.Authenticate( PW, PLen, Key ) ) { Console->Print( YELLOW, BLACK, "[Info] Gameserver: User '%s': authentication failed", UserName ); Failed = true; } if ( !Failed ) { if ( Account.GetLevel() == PAL_BANNED ) { Console->Print( YELLOW, BLACK, "[Info] User %s is banned, connection refused", UserName ); // TODO: ban ip for an adjustable time span? Failed = true; // player is banned } if ( Account.GetLevel() == PAL_UNREGPLAYER || Account.GetLevel() == PAL_REGPLAYER ) { if ( Server->GetNumClients() > ( Server->GetMaxClients() - Server->GetGMSlots() ) ) { Console->Print( YELLOW, BLACK, "[Info] Server full, refusing connection from regular user '%s'", UserName ); Failed = true; // server full for non-GM users } } else if ( Config->GetOptionInt( "require_validation" ) == 1 && Account.GetLevel() == PAL_UNREGPLAYER ) { Console->Print( YELLOW, BLACK, "[Info] Rejecting connection from regular user '%s', account not activated yet", UserName ); Failed = true; } else if ( Config->GetOptionInt( "minlevel" ) > Account.GetLevel() ) { Console->Print( YELLOW, BLACK, "[Info] Rejecting connection from regular user '%s', insufficient level %d vs %d required", UserName, Account.GetLevel(), Config->GetOptionInt( "minlevel" ) ); Failed = true; } else if ( Server->GetNumClients() > Server->GetMaxClients() ) { Console->Print( YELLOW, BLACK, "[Info] Server full, refusing connection from privileged user '%s'", UserName ); Failed = true; // server full even for GM users } } if ( !Failed ) { int value = *( u32* ) & Packet[21];//i think here we must read u32 instead of u8 u32 CharID = Account.GetCharIdBySlot( value ); if ( Chars->LoadChar( CharID ) ) { Client->SetCharID( CharID ); } else { Failed = true; } } if ( Failed ) // something strange happened FinalizeClientDelayed( Client, State ); else { Client->LoggedIn( &Account ); /*u8 AUTHOK[28]={0xfe, 0x19, 0x00, 0x83, 0x81, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; *(u32*)&AUTHOK[5]=Account->GetID(); Socket->Write(AUTHOK, 28);*/ //Client->SetRemoteUDPAddr(*(u32*)&Packet[5], *(u16*)&Packet[9]); State->TCP.mState = PGameState::TCP::GS_GETSTATUS; Console->Print( "Gameserver: User '%s' entered game (%08x:%04x)", UserName, *( u32* )&Packet[5], *( u16* )&Packet[9] ); Client->SetRemoteUDPPort( *( int* )&Packet[9] ); } } else { Console->Print( RED, BLACK, "[Notice] Gameserver protocol error (GS_AUTHENTICATE): invalid packet [%04x]", *( u16* )&Packet[3] ); return ( false ); } return ( true ); }
bool PPatchServer::HandleFileRequests(PClient *Client, PPatchState *State, const u8 *Packet, int PacketSize) { static u8 STARTPATCH[13]={0xfe, 0x0a, 0x00, 0x38, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; static u8 STARTFILE[13]={0xfe, 0x0a, 0x00, 0x3b, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; static u8 FILEERROR[9]={0xfe, 0x06, 0x00, 0x3d, 0x02, 0x00, 0x00, 0x00, 0x00}; ConnectionTCP *Socket = Client->getTCPConn(); // request patch if(PacketSize==13 && *(u16*)&Packet[3]==0x007c) { int nmax = Config->GetOptionInt("max_file_xfers"); if(mNumFileTransfers>=nmax) { Console->Print("Patchserver: max file xfers exceed, killing client %i", Client->GetIndex()); return false; } if(State->mPatchFile) { std::fclose(State->mPatchFile); State->mPatchFile=0; --mNumFileTransfers; } if(State->mSendFile) { Filesystem->Close(State->mSendFile); State->mSendFile=0; --mNumFileTransfers; } State->mSerial = *(u16*)&Packet[7]; State->mCurrentPatch = *(u32*)&Packet[9]; Console->Print("Patchserver: Patch request from client %i (v%i)", Client->GetIndex(), State->mCurrentPatch); if((bool)(State->mPatchSize = StartPatch(State))) { Console->Print("Patchserver: Patch is available, %d bytes", State->mPatchSize); *(u16*)&STARTPATCH[7]=State->mSerial; *(u32*)&STARTPATCH[9]=State->mPatchSize; Socket->write(STARTPATCH, 13); State->mState = PPatchState::PS_SENDPATCH; } else { Console->Print("Patchserver: Patch not available"); *(u16*)&FILEERROR[7]=State->mSerial; Socket->write(FILEERROR, 9); FinalizeClientDelayed(Client, State); State->mState=PPatchState::PS_UNKNOWN; return true; } } else // request file if(PacketSize > 9 && *(u16*)&Packet[3]==0x004d) { int nmax = Config->GetOptionInt("max_file_xfers"); if(mNumFileTransfers>=nmax) { Console->Print("Patchserver: max file xfers exceed, killing client %i", Client->GetIndex()); return false; } if(State->mPatchFile) { std::fclose(State->mPatchFile); State->mPatchFile=0; --mNumFileTransfers; } if(State->mSendFile) { Filesystem->Close(State->mSendFile); State->mSendFile=0; --mNumFileTransfers; } // request file State->mSerial = *(u16*)&Packet[7]; char fn[256]; strncpy(fn, (const char*)&Packet[10], Packet[9]); fn[Packet[9]]=0; State->mCurrentFile = fn; Console->Print("Patchserver: File request from client %i (%s)", Client->GetIndex(), fn); if((bool)(State->mFileSize = StartFile(State))) { Console->Print("Patchserver: File %s is available, %d bytes", State->mCurrentFile.c_str(), State->mFileSize); *(u16*)&STARTFILE[7]=State->mSerial; *(u32*)&STARTFILE[9]=State->mFileSize; Socket->write(STARTFILE, 13); State->mState = PPatchState::PS_SENDFILE; } else { Console->Print("Patchserver: Requested file %s not available", State->mCurrentFile.c_str()); *(u16*)&FILEERROR[7]=State->mSerial; Socket->write(FILEERROR, 9); FinalizeClientDelayed(Client, State); State->mState=PPatchState::PS_UNKNOWN; return true; } } else // send patch data if(PacketSize==17 && *(u16*)&Packet[3]==0x007d) { State->mSerial = *(u16*)&Packet[7]; State->mCurrentPatch = *(u32*)&Packet[9]; State->mPatchOffset = *(u32*)&Packet[13]; if(!SendPatchData(Client, State)) { Console->Print("Patchserver: SendPatchData failed on client %i", Client->GetIndex()); Console->Print("Patchserver: (probably due to garbage packets)"); // state is undefined now, kill this client return false; } } else // send file data if(PacketSize > 13 && *(u16*)&Packet[3]==0x00037) { State->mSerial = *(u16*)&Packet[7]; State->mFileOffset = *(u32*)&Packet[9]; if(!SendFileData(Client, State)) { Console->Print("Patchserver: SendFileData failed on client %i", Client->GetIndex()); Console->Print("Patchserver: (probably due to garbage packets)"); // state is undefined now, kill this client return false; } } else { Console->Print("Patchserver protocol error (PS_GETPATCHORFILE): unknown packet"); return false; } return true; }