/* * Ascent MMORPG Server * Copyright (C) 2005-2007 Ascent Team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ #include "LogonStdAfx.h" #pragma pack(push, 1) typedef struct { uint16 opcode; uint32 size; }logonpacket; #pragma pack(pop) LogonCommServerSocket::LogonCommServerSocket(SOCKET fd) : Socket(fd, 65536, 524288) { // do nothing last_ping = time(NULL); remaining = opcode = 0; sInfoCore.AddServerSocket(this); removed = false; use_crypto = false; authenticated = 0; } LogonCommServerSocket::~LogonCommServerSocket() { } void LogonCommServerSocket::OnDisconnect() { // if we're registered -> de-register if(!removed) { set::iterator itr = server_ids.begin(); for(; itr != server_ids.end(); ++itr) sInfoCore.RemoveRealm((*itr)); sInfoCore.RemoveServerSocket(this); } } void LogonCommServerSocket::OnRead() { while(true) { if(!remaining) { if(GetReadBufferSize() < 4) return; // no header // read header Read(2, (uint8*)&opcode); Read(4, (uint8*)&remaining); if(use_crypto) { // decrypt the packet recvCrypto.Process((unsigned char*)&opcode, (unsigned char*)&opcode, 2); recvCrypto.Process((unsigned char*)&remaining, (unsigned char*)&remaining, 4); } #ifdef USING_BIG_ENDIAN opcode = swap16(opcode); #else /* reverse byte order */ remaining = ntohl(remaining); #endif } // do we have a full packet? if(GetReadBufferSize() < remaining) return; // create the buffer WorldPacket buff(opcode, remaining); if(remaining) { buff.resize(remaining); Read(remaining, (uint8*)buff.contents()); } if(use_crypto && remaining) recvCrypto.Process((unsigned char*)buff.contents(), (unsigned char*)buff.contents(), remaining); // handle the packet HandlePacket(buff); remaining = 0; opcode = 0; } } void LogonCommServerSocket::HandlePacket(WorldPacket & recvData) { if(authenticated == 0 && recvData.GetOpcode() != RCMSG_AUTH_CHALLENGE) { // invalid Disconnect(); return; } static logonpacket_handler Handlers[RMSG_COUNT] = { NULL, // RMSG_NULL &LogonCommServerSocket::HandleRegister, // RCMSG_REGISTER_REALM NULL, // RSMSG_REALM_REGISTERED &LogonCommServerSocket::HandleSessionRequest, // RCMSG_REQUEST_SESSION NULL, // RSMSG_SESSION_RESULT &LogonCommServerSocket::HandlePing, // RCMSG_PING NULL, // RSMSG_PONG &LogonCommServerSocket::HandleSQLExecute, // RCMSG_SQL_EXECUTE &LogonCommServerSocket::HandleReloadAccounts, // RCMSG_RELOAD_ACCOUNTS &LogonCommServerSocket::HandleAuthChallenge, // RCMSG_AUTH_CHALLENGE NULL, // RSMSG_AUTH_RESPONSE NULL, // RSMSG_REQUEST_ACCOUNT_CHARACTER_MAPPING &LogonCommServerSocket::HandleMappingReply, // RCMSG_ACCOUNT_CHARACTER_MAPPING_REPLY &LogonCommServerSocket::HandleUpdateMapping, // RCMSG_UPDATE_CHARACTER_MAPPING_COUNT }; if(recvData.GetOpcode() >= RMSG_COUNT || Handlers[recvData.GetOpcode()] == 0) { printf("Got unknwon packet from logoncomm: %u\n", recvData.GetOpcode()); return; } (this->*(Handlers[recvData.GetOpcode()]))(recvData); } void LogonCommServerSocket::HandleRegister(WorldPacket & recvData) { Realm * realm = new Realm; recvData >> realm->Name >> realm->Address; recvData >> realm->Colour >> realm->Icon >> realm->TimeZone >> realm->Population; uint32 my_id = sInfoCore.GenerateRealmID(); sLog.outString("Registering realm `%s` under ID %u.", realm->Name.c_str(), my_id); // Add to the main realm list sInfoCore.AddRealm(my_id, realm); // Send back response packet. WorldPacket data(RSMSG_REALM_REGISTERED, 4); data << uint32(0); // Error data << my_id; // Realm ID data << realm->Name; SendPacket(&data); server_ids.insert(my_id); /* request character mapping for this realm */ data.Initialize(RSMSG_REQUEST_ACCOUNT_CHARACTER_MAPPING); data << my_id; SendPacket(&data); } void LogonCommServerSocket::HandleSessionRequest(WorldPacket & recvData) { uint32 request_id; string account_name; recvData >> request_id; recvData >> account_name; // get sessionkey! uint32 error = 0; Account * acct = sAccountMgr.GetAccount(account_name); BigNumber * sessionkey = acct ? sInfoCore.GetSessionKey(acct->AccountId) : 0; if(sessionkey == 0 || acct == 0) error = 1; // Unauthorized user. // build response packet WorldPacket data(RSMSG_SESSION_RESULT, 150); data << request_id; data << error; if(!error) { // Append account information. data << acct->AccountId; data << acct->Username; data << acct->GMFlags; data << acct->AccountFlags; data.append(sessionkey->AsByteArray(), 40); } SendPacket(&data); } void LogonCommServerSocket::HandlePing(WorldPacket & recvData) { WorldPacket data(RSMSG_PONG, 4); SendPacket(&data); last_ping = time(NULL); } void LogonCommServerSocket::SendPacket(WorldPacket * data) { bool rv; BurstBegin(); logonpacket header; #ifndef USING_BIG_ENDIAN header.opcode = data->GetOpcode(); header.size = ntohl(data->size()); #else header.opcode = swap16(uint16(data->GetOpcode())); header.size = data->size(); #endif if(use_crypto) sendCrypto.Process((unsigned char*)&header, (unsigned char*)&header, 6); rv=BurstSend((uint8*)&header, 6); if(data->size() > 0 && rv) { if(use_crypto) sendCrypto.Process((unsigned char*)data->contents(), (unsigned char*)data->contents(), data->size()); rv=BurstSend(data->contents(), data->size()); } if(rv) BurstPush(); BurstEnd(); } void LogonCommServerSocket::HandleSQLExecute(WorldPacket & recvData) { string Query; recvData >> Query; sLogonSQL->Execute(Query.c_str()); } void LogonCommServerSocket::HandleReloadAccounts(WorldPacket & recvData) { sAccountMgr.ReloadAccounts(true); } void LogonCommServerSocket::HandleAuthChallenge(WorldPacket & recvData) { unsigned char key[20]; uint32 result = 1; recvData.read(key, 20); // check if we have the correct password if(memcmp(key, LogonServer::getSingleton().sql_hash, 20)) result = 0; sLog.outString("Authentication request from %s, result %s.", GetRemoteIP().c_str(), result ? "OK" : "FAIL"); printf("Key: "); for(int i = 0; i < 20; ++i) printf("%.2X", key[i]); printf("\n"); recvCrypto.Setup(key, 20); sendCrypto.Setup(key, 20); /* packets are encrypted from now on */ use_crypto = true; /* send the response packet */ WorldPacket data(RSMSG_AUTH_RESPONSE, 1); data << result; SendPacket(&data); /* set our general var */ authenticated = result; } void LogonCommServerSocket::HandleMappingReply(WorldPacket & recvData) { /* this packet is gzipped, whee! :D */ uint32 real_size; recvData >> real_size; uLongf rsize = real_size; ByteBuffer buf(real_size); buf.resize(real_size); if(uncompress((uint8*)buf.contents(), &rsize, recvData.contents() + 4, recvData.size() - 4) != Z_OK) { printf("Uncompress of mapping failed.\n"); return; } uint32 account_id; uint8 number_of_characters; uint32 count; uint32 realm_id; buf >> realm_id; Realm * realm = sInfoCore.GetRealm(realm_id); if(!realm) return; sInfoCore.getRealmLock().Acquire(); HM_NAMESPACE::hash_map::iterator itr; buf >> count; printf("Got mapping packet for realm %u, total of %u entries.\n", (unsigned int)realm_id, (unsigned int)count); for(uint32 i = 0; i < count; ++i) { buf >> account_id >> number_of_characters; itr = realm->CharacterMap.find(account_id); if(itr != realm->CharacterMap.end()) itr->second = number_of_characters; else realm->CharacterMap.insert( make_pair( account_id, number_of_characters ) ); } sInfoCore.getRealmLock().Release(); } void LogonCommServerSocket::HandleUpdateMapping(WorldPacket & recvData) { uint32 realm_id; uint32 account_id; uint8 chars_to_add; recvData >> realm_id; Realm * realm = sInfoCore.GetRealm(realm_id); if(!realm) return; sInfoCore.getRealmLock().Acquire(); recvData >> account_id >> chars_to_add; HM_NAMESPACE::hash_map::iterator itr = realm->CharacterMap.find(account_id); if(itr != realm->CharacterMap.end()) itr->second += chars_to_add; else realm->CharacterMap.insert( make_pair( account_id, chars_to_add ) ); sInfoCore.getRealmLock().Release(); }