/*
* 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 "StdAfx.h"
initialiseSingleton(LogonCommHandler);
#ifndef CLUSTERING
LogonCommHandler::LogonCommHandler()
{
idhigh = 1;
next_request = 1;
pings = !Config.MainConfig.GetBoolDefault("LogonServer", "DisablePings", false);
string logon_pass = Config.MainConfig.GetStringDefault("LogonServer", "RemotePassword", "r3m0t3");
// sha1 hash it
Sha1Hash hash;
hash.UpdateData(logon_pass);
hash.Finalize();
memcpy(sql_passhash, hash.GetDigest(), 20);
}
LogonCommHandler::~LogonCommHandler()
{
for(set::iterator i = servers.begin(); i != servers.end(); ++i)
delete (*i);
for(set::iterator i = realms.begin(); i != realms.end(); ++i)
delete (*i);
}
LogonCommClientSocket * LogonCommHandler::ConnectToLogon(string Address, uint32 Port)
{
LogonCommClientSocket * conn = ConnectTCPSocket(Address.c_str(), Port);
return conn;
}
void LogonCommHandler::RequestAddition(LogonCommClientSocket * Socket)
{
set::iterator itr = realms.begin();
WorldPacket data(RCMSG_REGISTER_REALM, 100);
for(; itr != realms.end(); ++itr)
{
data.clear();
// Add realm to the packet
Realm * realm = *itr;
data << realm->Name;
data << realm->Address;
data << realm->Colour;
data << realm->Icon;
data << realm->TimeZone;
data << realm->Population;
Socket->SendPacket(&data);
}
}
void LogonCommHandler::Startup()
{
// Try to connect to all logons.
sLog.outColor(TNORMAL, "\n >> loading realms and logon server definitions... ");
LoadRealmConfiguration();
sLog.outColor(TNORMAL, " >> attempting to connect to all logon servers... \n");
for(set::iterator itr = servers.begin(); itr != servers.end(); ++itr)
Connect(*itr);
sLog.outColor(TNORMAL, "\n");
}
void LogonCommHandler::Connect(LogonServer * server)
{
sLog.outColor(TNORMAL, " >> connecting to `%s` on `%s:%u`...", server->Name.c_str(), server->Address.c_str(), server->Port);
server->RetryTime = time(NULL) + 10;
server->Registered = false;
LogonCommClientSocket * conn = ConnectToLogon(server->Address, server->Port);
logons[server] = conn;
if(conn == 0)
{
sLog.outColor(TRED, " fail!\n server connection failed. I will try again later.");
sLog.outColor(TNORMAL, "\n");
return;
}
sLog.outColor(TGREEN, " ok!\n");
sLog.outColor(TNORMAL, " >> authenticating...\n");
sLog.outColor(TNORMAL, " >> ");
uint32 tt = time(NULL) + 10;
conn->SendChallenge();
sLog.outColor(TNORMAL, " >> result:");
while(!conn->authenticated)
{
if((uint32)time(NULL) >= tt)
{
sLog.outColor(TYELLOW, " timeout.\n");
return;
}
Sleep(50);
}
if(conn->authenticated != 1)
{
sLog.outColor(TRED, " failure.\n");
logons[server] = 0;
conn->Disconnect();
return;
}
else
sLog.outColor(TGREEN, " ok!\n");
// Send the initial ping
conn->SendPing();
sLog.outColor(TNORMAL, " >> registering realms... ");
conn->_id = server->ID;
RequestAddition(conn);
uint32 st = time(NULL) + 10;
// Wait for register ACK
while(server->Registered == false)
{
// Don't wait more than.. like 10 seconds for a registration
if((uint32)time(NULL) >= st)
{
sLog.outColor(TYELLOW, "timeout.");
logons[server] = 0;
conn->Disconnect();
break;
}
Sleep(50);
}
if(!server->Registered)
return;
// Wait for all realms to register
Sleep(200);
sLog.outColor(TNORMAL, "\n >> ping test: ");
sLog.outColor(TYELLOW, "%ums", conn->latency);
sLog.outColor(TNORMAL, "\n");
}
void LogonCommHandler::AdditionAck(uint32 ID, uint32 ServID)
{
map::iterator itr = logons.begin();
for(; itr != logons.end(); ++itr)
{
if(itr->first->ID == ID)
{
itr->first->ServerID = ServID;
itr->first->Registered = true;
return;
}
}
}
void LogonCommHandler::UpdateSockets()
{
mapLock.Acquire();
map::iterator itr = logons.begin();
LogonCommClientSocket * cs;
uint32 t = time(NULL);
for(; itr != logons.end(); ++itr)
{
cs = itr->second;
if(cs != 0)
{
if(!pings) continue;
if(cs->IsDeleted() || !cs->IsConnected())
{
cs->_id = 0;
itr->second = 0;
continue;
}
if(cs->last_pong < t && ((t - cs->last_pong) > 60))
{
// no pong for 60 seconds -> remove the socket
printf(" >> realm id %u connection dropped due to pong timeout.\n", (unsigned int)itr->first->ID);
cs->_id = 0;
cs->Disconnect();
itr->second = 0;
continue;
}
if( (t - cs->last_ping) > 15 )
{
// send a ping packet.
cs->SendPing();
}
}
else
{
// check retry time
if(t >= itr->first->RetryTime)
{
Connect(itr->first);
}
}
}
mapLock.Release();
}
void LogonCommHandler::ConnectionDropped(uint32 ID)
{
mapLock.Acquire();
map::iterator itr = logons.begin();
for(; itr != logons.end(); ++itr)
{
if(itr->first->ID == ID && itr->second != 0)
{
sLog.outColor(TNORMAL, " >> realm id %u connection was dropped unexpectedly. reconnecting next loop.", ID);
sLog.outColor(TNORMAL, "\n");
itr->second = 0;
break;
}
}
mapLock.Release();
}
uint32 LogonCommHandler::ClientConnected(string AccountName, WorldSocket * Socket)
{
uint32 request_id = next_request++;
sLog.outDebug ( " >> sending request for account information: `%s` (request %u).", AccountName.c_str(), request_id);
// sLog.outColor(TNORMAL, "\n");
// Send request packet to server.
map::iterator itr = logons.begin();
if(logons.size() == 0 || itr->second == 0)
{
// No valid logonserver is connected.
return (uint32)-1;
}
pendingLock.Acquire();
WorldPacket data(RCMSG_REQUEST_SESSION, 100);
data << request_id;
data << AccountName;
itr->second->SendPacket(&data);
pending_logons[request_id] = Socket;
pendingLock.Release();
return request_id;
}
void LogonCommHandler::UnauthedSocketClose(uint32 id)
{
pendingLock.Acquire();
pending_logons.erase(id);
pendingLock.Release();
}
void LogonCommHandler::RemoveUnauthedSocket(uint32 id)
{
pending_logons.erase(id);
}
void LogonCommHandler::LogonDatabaseSQLExecute(const char* str, ...)
{
va_list ap;
va_start(ap, str);
char query[1024];
vsnprintf(query, 1024, str, ap);
va_end(ap);
string q = string(query);
WorldPacket data(RCMSG_SQL_EXECUTE, q.size()+1);
data << q;
// Send request packet to server.
map::iterator itr = logons.begin();
if(logons.size() == 0 || itr->second == 0)
{
// No valid logonserver is connected.
return;
}
itr->second->SendPacket(&data);
}
void LogonCommHandler::LogonDatabaseReloadAccounts()
{
WorldPacket data(RCMSG_RELOAD_ACCOUNTS, 1);
map::iterator itr = logons.begin();
if(logons.size() == 0 || itr->second == 0)
{
// No valid logonserver is connected.
return;
}
itr->second->SendPacket(&data);
}
void LogonCommHandler::LoadRealmConfiguration()
{
LogonServer * ls = new LogonServer;
ls->ID = idhigh++;
ls->Name = Config.RealmConfig.GetStringDefault("LogonServer", "Name", "UnkLogon");
ls->Address = Config.RealmConfig.GetStringDefault("LogonServer", "Address", "127.0.0.1");
ls->Port = Config.RealmConfig.GetIntDefault("LogonServer", "Port", 8093);
servers.insert(ls);
sLog.outColor(TYELLOW, "1 servers, ");
uint32 realmcount = Config.RealmConfig.GetIntDefault("LogonServer", "RealmCount", 1);
if(realmcount == 0)
{
sLog.outColor(TRED, "\n >> no realms found. this server will not be online anywhere!\n");
}
else
{
for(uint32 i = 1; i < realmcount+1; ++i)
{
Realm * realm = new Realm;
realm->Name = Config.RealmConfig.GetStringVA("Name", "SomeRealm", "Realm%u", i);
realm->Address = Config.RealmConfig.GetStringVA("Address", "127.0.0.1:8129", "Realm%u", i);
realm->Colour = Config.RealmConfig.GetIntVA("Colour", 1, "Realm%u", i);
realm->TimeZone = Config.RealmConfig.GetIntVA("TimeZone", 1, "Realm%u", i);
realm->Population = Config.RealmConfig.GetFloatVA("Population", 0, "Realm%u", i);
string rt = Config.RealmConfig.GetStringVA("Icon", "Normal", "Realm%u", i);
uint32 type;
// process realm type
if(!stricmp(rt.c_str(), "pvp"))
type = REALMTYPE_PVP;
else if(!stricmp(rt.c_str(), "rp"))
type = REALMTYPE_RP;
else if(!stricmp(rt.c_str(), "rppvp"))
type = REALMTYPE_RPPVP;
else
type = REALMTYPE_NORMAL;
_realmType = type;
realm->Icon = type;
realms.insert(realm);
}
sLog.outColor(TBLUE, "%u realms.\n", realmcount);
}
}
void LogonCommHandler::UpdateAccountCount(uint32 account_id, uint8 add)
{
// Send request packet to server.
map::iterator itr = logons.begin();
if(logons.size() == 0 || itr->second == 0)
{
// No valid logonserver is connected.
return;
}
itr->second->UpdateAccountCount(account_id, add);
}
#endif