Index: src/mangosd/Master.cpp =================================================================== --- src/mangosd/Master.cpp (revision 5031) +++ src/mangosd/Master.cpp (working copy) @@ -21,8 +21,7 @@ */ #include "Master.h" -#include "Network/SocketHandler.h" -#include "Network/ListenSocket.h" +#include "Network/Network.h" #include "WorldSocket.h" #include "WorldSocketMgr.h" #include "WorldRunnable.h" @@ -39,29 +38,21 @@ #include "ScriptCalls.h" #include "Util.h" -#include "Network/TcpSocket.h" -#include "Network/Utility.h" -#include "Network/Parse.h" -#include "Network/Socket.h" +#ifdef WIN32 +#include +#endif + #ifdef WIN32 #include "ServiceWin32.h" extern int m_ServiceStatus; #endif /// \todo Warning disabling not useful under VC++2005. Can somebody say on which compiler it is useful? -#pragma warning(disable:4305) +//#pragma warning(disable:4305) INSTANTIATE_SINGLETON_1( Master ); -Master::Master() -{ -} - -Master::~Master() -{ -} - /// Main function void Master::Run() { @@ -93,6 +84,23 @@ sLog.outString( "Daemon PID: %u\n", pid ); } +#ifdef USE_LEVENT + //show version of libevent at start + sLog.outBasic("Using %s version of LibEvent",event_get_version()); + bool isvalid_vlibevent=false; + const char* accepted_vlibevent[]=REQ_LEVENT_VER; + for(int i=0;accepted_vlibevent[i];i++) + if(!strcmp(event_get_version(),accepted_vlibevent[i])) + { + isvalid_vlibevent=true; + break; + } + if(!isvalid_vlibevent) + { + sLog.outError("Version of libevent is wrong, shutdown now"); + return; + } +#endif//USE_LEVENT ///- Start the databases if (!_StartDB()) @@ -101,21 +109,6 @@ ///- Initialize the World sWorld.SetInitialWorldSettings(); - ///- Launch the world listener socket - port_t wsport = sWorld.getConfig(CONFIG_PORT_WORLD); - - SocketHandler h; - - ListenSocket worldListenSocket(h); - if (worldListenSocket.Bind(wsport)) - { - clearOnlineAccounts(); - sLog.outError("MaNGOS cannot bind to port %d", wsport); - return; - } - - h.Add(&worldListenSocket); - ///- Catch termination signals _HookSignals(); @@ -137,22 +130,17 @@ } ///- Launch the RA listener socket - ListenSocket RAListenSocket(h); + ListenSocket* pRAListenSocket = NULL; if (sConfig.GetBoolDefault("Ra.Enable", false)) { - port_t raport = sConfig.GetIntDefault( "Ra.Port", 3443 ); + uint32 raport = sConfig.GetIntDefault( "Ra.Port", 3443 ); std::string stringip = sConfig.GetStringDefault( "Ra.IP", "0.0.0.0" ); - ipaddr_t raip; - if(!Utility::u2ip(stringip, raip)) - sLog.outError( "MaNGOS RA can not bind to ip %s", stringip.c_str()); - else if (RAListenSocket.Bind(raip, raport)) - sLog.outError( "MaNGOS RA can not bind to port %d on %s", raport, stringip.c_str()); + pRAListenSocket = new ListenSocket(stringip.c_str(), raport); + if (!pRAListenSocket->IsListernPortOpened()) + sLog.outString("Remote access lister on port %d on %s - FAILED", raport, stringip.c_str()); else - { - h.Add(&RAListenSocket); - - sLog.outString("Starting Remote access listner on port %d on %s", raport, stringip.c_str()); - } + { + sLog.outString("Starting Remote access lister on port %d on %s", raport, stringip.c_str()); } ///- Handle affinity for multiple processors and process priority on Windows @@ -199,42 +187,45 @@ } #endif - uint32 realCurrTime, realPrevTime; - realCurrTime = realPrevTime = getMSTime(); + // sSocketManager.SetupIOWorkers(); + ///- Launch the world listener socket - uint32 socketSelecttime = sWorld.getConfig(CONFIG_SOCKET_SELECTTIME); + uint32 wsport = sWorld.getConfig(CONFIG_PORT_WORLD); + ListenSocket worldListenSocket("0.0.0.0", wsport); + bool bListenPortOpened = worldListenSocket.IsListernPortOpened(); // maximum counter for next ping - uint32 numLoops = (sConfig.GetIntDefault( "MaxPingTime", 30 ) * (MINUTE * 1000000 / socketSelecttime)); - uint32 loopCounter = 0; + uint32 PingInterval = (sConfig.GetIntDefault( "MaxPingTime", 30 ) * MINUTE * 1000); + uint32 RestToPing = PingInterval; + uint32 time_to_sleep = 100; ///- Wait for termination signal - while (!World::m_stopEvent) + while (!World::m_stopEvent && bListenPortOpened) { #ifdef WIN32 if (m_ServiceStatus == 0) World::m_stopEvent = true; while (m_ServiceStatus == 2) Sleep(1000); #endif - if (realPrevTime > realCurrTime) - realPrevTime = 0; + Sleep(time_to_sleep); + if (RestToPing - time_to_sleep < 0) + RestToPing = 0; + else + RestToPing -= time_to_sleep; + if (RestToPing) + continue; - realCurrTime = getMSTime(); - sWorldSocketMgr.Update( realCurrTime - realPrevTime ); - realPrevTime = realCurrTime; - - h.Select(0, socketSelecttime); - - // ping if need - if( (++loopCounter) == numLoops ) - { - loopCounter = 0; + RestToPing = PingInterval; sLog.outDetail("Ping MySQL to keep connection alive"); delete WorldDatabase.Query("SELECT 1 FROM `command` LIMIT 1"); delete loginDatabase.Query("SELECT 1 FROM `realmlist` LIMIT 1"); delete CharacterDatabase.Query("SELECT 1 FROM `bugreport` LIMIT 1"); } - } + worldListenSocket.StopListening(); + sSocketManager.DisconnectAll(); + sSocketManager.StopIOWorkers(); + sAuthSocketManagerCleaner.Stop(); + // set server offline loginDatabase.PExecute("UPDATE `realmlist` SET `color` = 2 WHERE `id` = '%d'",realmID); Index: src/mangosd/RASocket.cpp =================================================================== --- src/mangosd/RASocket.cpp (revision 5031) +++ src/mangosd/RASocket.cpp (working copy) @@ -27,23 +27,19 @@ #include "World.h" #include "Config/ConfigEnv.h" +uint32 iSession=0; ///< Session number (incremented each time a new connection is made) +unsigned int iUsers=0; ///< Number of active administrators +typedef int(* pPrintf)(const char*,...); /// \todo Make this thread safe if in the future 2 admins should be able to log at the same time. -SOCKET r; - +SOCKET r=NULL; #define dropclient {Sendf("I'm busy right now, come back later."); \ - SetCloseAndDelete(); \ + Disconnect(); \ return; \ } - -uint32 iSession=0; ///< Session number (incremented each time a new connection is made) -unsigned int iUsers=0; ///< Number of active administrators - -typedef int(* pPrintf)(const char*,...); - void ParseCommand(pPrintf zprintf, char*command); /// RASocket constructor -RASocket::RASocket(ISocketHandler &h): TcpSocket(h) +RASocket::RASocket(SOCKET s): Socket(s) { ///- Increment the session number @@ -72,7 +68,7 @@ } /// Accept an incoming connection -void RASocket::OnAccept() +void RASocket::OnConnect() { std::string ss=GetRemoteAddress(); sLog.outRALog("Incoming connection from %s.\n",ss.c_str()); @@ -87,14 +83,11 @@ /// Read data from the network void RASocket::OnRead() { - ///- Read data and check input length - TcpSocket::OnRead(); - - unsigned int sz=ibuf.GetLength(); + unsigned int sz = ReadBuffer()->get_data_size(); if(iInputLength+sz>=RA_BUFF_SIZE) { sLog.outRALog("Input buffer overflow, possible DOS attack.\n"); - SetCloseAndDelete(); + Disconnect(); return; } @@ -103,7 +96,7 @@ dropclient char *inp = new char [sz+1]; - ibuf.Read(inp,sz); + ReadBuffer()->extract((uint8*)inp, sz); /// \todo Can somebody explain this 'Linux bugfix'? if(stage==NONE) @@ -153,7 +146,8 @@ { Sendf("-No such user.\r\n"); sLog.outRALog("User %s does not exist.\n",szLogin.c_str()); - if(bSecure)SetCloseAndDelete(); + if(bSecure) + Disconnect(); } else { @@ -166,7 +160,7 @@ { Sendf("-Not enough privileges.\r\n"); sLog.outRALog("User %s has no privilege.\n",szLogin.c_str()); - if(bSecure)SetCloseAndDelete(); + if(bSecure)Disconnect(); } else { stage=LG; @@ -201,7 +195,7 @@ ///- Else deny access Sendf("-Wrong pass.\r\n"); sLog.outRALog("User %s has failed to log in.\n",szLogin.c_str()); - if(bSecure)SetCloseAndDelete(); + if(bSecure)Disconnect(); } } break; @@ -227,13 +221,11 @@ if( !szText ) return 0; va_list ap; va_start(ap, szText); - /// \todo Remove buffer length here. Can be >1024 (e.g. list of users) - char *megabuffer=new char[1024]; - unsigned int sz=vsnprintf(megabuffer,1024,szText,ap); + char *megabuffer=new char[sizeof(szText)]; + unsigned int sz=vsnprintf(megabuffer,sizeof(szText),szText,ap); #ifdef RA_CRYPT Encrypt(megabuffer,sz); #endif - send(r,megabuffer,sz,0); delete [] megabuffer; va_end(ap); Index: src/realmd/AuthSocket.cpp =================================================================== --- src/realmd/AuthSocket.cpp (revision 5031) +++ src/realmd/AuthSocket.cpp (working copy) @@ -212,7 +212,7 @@ Patcher PatchesCache; /// Constructor - set the N and g values for SRP6 -AuthSocket::AuthSocket(ISocketHandler &h) : TcpSocket(h) +AuthSocket::AuthSocket(SOCKET h) : Socket(h) { N.SetHexStr("894B645E89E1535BBDAD5B8B290650530801B18EBFBF5E8FAB3C82872A3E9BB7"); g.SetDword(7); @@ -229,35 +229,30 @@ fclose(pPatch); } +void AuthSocket::OnDisconnect() +{ + sAuthSocketManagerCleaner.Add(this);//will be removed after 200 ms +} + /// Accept the connection and set the s random value for SRP6 -void AuthSocket::OnAccept() +void AuthSocket::OnConnect() { - sLog.outBasic("Accepting connection from '%s:%d'", - GetRemoteAddress().c_str(), GetRemotePort()); - - s.SetRand(s_BYTE_SIZE * 8); + sLog.outBasic("Accepting connection from '%s'", GetRemoteAddress().c_str()); + s.SetRand(s_BYTE_SIZE * 8); } /// Read the packet from the client void AuthSocket::OnRead() { ///- Read the packet - TcpSocket::OnRead(); uint8 _cmd; while (1) { - if (!ibuf.GetLength()) + if (!ReadBuffer()->get_data_size()) return; ///- Get the command out of it - ibuf.SoftRead((char *)&_cmd, 1); // UQ1: No longer exists in new net code ??? - //ibuf.Read((char *)&_cmd, 1); - /*char *command = (char *)malloc(1); - - ibuf.Read(command, 1); - - _cmd = (uint8)command;*/ - // assert(0); + ReadBuffer()->peek((uint8*)&_cmd, 1); // UQ1: No longer exists in new net code ??? size_t i; ///- Circle through known commands and call the correct command handler @@ -267,11 +262,11 @@ (table[i].status == STATUS_CONNECTED || (_authed && table[i].status == STATUS_AUTHED))) { - DEBUG_LOG("[Auth] got data for cmd %u ibuf length %u", (uint32)_cmd, ibuf.GetLength()); + DEBUG_LOG("[Auth] got data for cmd %u ibuf length %u", (uint32)_cmd, ReadBuffer()->get_data_size()); if (!(*this.*table[i].handler)()) { - DEBUG_LOG("Command handler failed for cmd %u ibuf length %u", (uint32)_cmd, ibuf.GetLength()); + DEBUG_LOG("Command handler failed for cmd %u ibuf length %u", (uint32)_cmd, ReadBuffer()->get_data_size()); return; } break; @@ -321,19 +316,22 @@ bool AuthSocket::_HandleLogonChallenge() { DEBUG_LOG("Entering _HandleLogonChallenge"); - if (ibuf.GetLength() < sizeof(sAuthLogonChallenge_C)) + if (ReadBuffer()->get_data_size() < sizeof(sAuthLogonChallenge_C)) return false; ///- Read the first 4 bytes (header) to get the length of the remaining of the packet std::vector buf; buf.resize(4); - ibuf.Read((char *)&buf[0], 4); + LockReading(); + ReadBuffer()->extract((uint8* )&buf[0], 4); + UnlockReading(); + uint16 remaining = ((sAuthLogonChallenge_C *)&buf[0])->size; DEBUG_LOG("[AuthChallenge] got header, body is %#04x bytes", remaining); - if ((remaining < sizeof(sAuthLogonChallenge_C) - buf.size()) || (ibuf.GetLength() < remaining)) - return false; + if ((remaining < sizeof(sAuthLogonChallenge_C) - buf.size()) || (ReadBuffer()->get_data_size() < remaining)) + return false; //No big fear of memory outage (size is int16, i.e. < 65536) buf.resize(remaining + buf.size() + 1); @@ -341,7 +339,9 @@ sAuthLogonChallenge_C *ch = (sAuthLogonChallenge_C*)&buf[0]; ///- Read the remaining of the packet - ibuf.Read((char *)&buf[4], remaining); + LockReading(); + ReadBuffer()->extract((uint8*)&buf[4], remaining); + UnlockReading(); DEBUG_LOG("[AuthChallenge] got full packet, %#04x bytes", ch->size); DEBUG_LOG("[AuthChallenge] name(%d): '%s'", ch->I_len, ch->I); @@ -522,19 +522,19 @@ ///- Send a packet to the client with the file length and MD5 hash uint8 data[2]={AUTH_LOGON_PROOF,REALM_AUTH_UPDATE_CLIENT}; - SendBuf((const char*)data,sizeof(data)); + Send((const uint8*)data,sizeof(data)); memcpy(&xferh,"0\x05Patch",7); xferh.cmd=XFER_INITIATE; fseek(pPatch,0,SEEK_END); xferh.file_size=ftell(pPatch); - SendBuf((const char*)&xferh,sizeof(xferh)); + Send((const uint8*)&xferh,sizeof(xferh)); return true; } } /// - SendBuf((char const*)pkt.contents(), pkt.size()); + Send((uint8*)pkt.contents(), pkt.size()); return true; } @@ -543,11 +543,13 @@ { DEBUG_LOG("Entering _HandleLogonProof"); ///- Read the packet - if (ibuf.GetLength() < sizeof(sAuthLogonProof_C)) + if (ReadBuffer()->get_data_size() < sizeof(sAuthLogonProof_C)) return false; sAuthLogonProof_C lp; - ibuf.Read((char *)&lp, sizeof(sAuthLogonProof_C)); + LockReading(); + ReadBuffer()->extract((uint8*)&lp, sizeof(sAuthLogonProof_C)); + UnlockReading(); ///- Continue the SRP6 calculation based on data received from the client BigNumber A; @@ -639,7 +641,7 @@ proof.unk2 = 0; proof.unk3 = 0; - SendBuf((char *)&proof, sizeof(proof)); + Send((uint8*)&proof, sizeof(proof)); ///- Set _authed to true! _authed = true; @@ -647,7 +649,7 @@ else { char data[4]={AUTH_LOGON_PROOF,REALM_AUTH_NO_MATCH,3,0}; - SendBuf(data,sizeof(data)); + Send((uint8*)data,sizeof(data)); } return true; } @@ -656,11 +658,14 @@ bool AuthSocket::_HandleRealmList() { DEBUG_LOG("Entering _HandleRealmList"); - if (ibuf.GetLength() < 5) + if (ReadBuffer()->get_data_size() < 5) return false; - ibuf.Remove(5); + LockReading(); + ReadBuffer()->remove(5); + UnlockReading(); + ///- Get the user id (else close the connection) // No SQL injection (escaped user name) @@ -668,7 +673,7 @@ if(!result) { sLog.outError("[ERROR] user %s tried to login and we cannot find him in the database.",_login.c_str()); - SetCloseAndDelete(); + Disconnect(); return false; } @@ -719,7 +724,7 @@ hdr << (uint16)pkt.size(); hdr.append(pkt); - SendBuf((char const*)hdr.contents(), hdr.size()); + Send(hdr.contents(), hdr.size()); // Set check field before possable relogin to realm _SetVSFields(rI); @@ -731,7 +736,7 @@ { DEBUG_LOG("Entering _HandleXferResume"); ///- Check packet length - if (ibuf.GetLength()<9) + if (ReadBuffer()->get_data_size() < 9) { sLog.outError("Error while resuming patch transfer (wrong packet)"); return false; @@ -739,8 +744,10 @@ ///- Launch a PatcherRunnable thread starting at given patch file offset uint64 start; - ibuf.Remove(1); - ibuf.Read((char*)&start,sizeof(start)); + LockReading(); + ReadBuffer()->remove(1); + ReadBuffer()->extract((uint8*)&start, sizeof(start)); + UnlockReading(); fseek(pPatch,start,0); ZThread::Thread u(new PatcherRunnable(this)); @@ -753,10 +760,14 @@ DEBUG_LOG("Entering _HandleXferCancel"); ///- Close and delete the socket - ibuf.Remove(1); //clear input buffer + LockReading(); + ReadBuffer()->remove(1); + UnlockReading(); + //clear input buffer //ZThread::Thread::sleep(15); - SetCloseAndDelete(); + /// \todo What is the difference between SetCloseAndDelete() and the this->Close() higher? + Disconnect(); return true; } @@ -766,7 +777,10 @@ { DEBUG_LOG("Entering _HandleXferAccept"); ///- Launch a PatcherRunnable thread, starting at the begining of the patch file - ibuf.Remove(1); //clear input buffer + LockReading(); + ReadBuffer()->remove(1); + UnlockReading(); + //clear input buffer fseek(pPatch,0,0); ZThread::Thread u(new PatcherRunnable(this)); @@ -777,7 +791,7 @@ /// Check if there is lag on the connection to the client bool AuthSocket::IsLag() { - return (TCP_BUFSIZE_READ-obuf.GetLength()< 2*ChunkSize); + return (SENDBUF_SIZE - WriteBuffer()->get_data_size() < 2 * ChunkSize); } PatcherRunnable::PatcherRunnable(class AuthSocket * as) @@ -791,16 +805,16 @@ XFER_DATA_STRUCT xfdata; xfdata.opcode = XFER_DATA; - while(!feof(mySocket->pPatch) && mySocket->Ready()) + while(!feof(mySocket->pPatch) && mySocket->IsConnected()) { ///- Wait until output buffer is reasonably empty - while(mySocket->Ready() && mySocket->IsLag()) + while(mySocket->IsConnected() && mySocket->IsLag()) { ZThread::Thread::sleep(1); } ///- And send content of the patch file to the client xfdata.data_size=fread(&xfdata.data,1,ChunkSize,mySocket->pPatch); - mySocket->SendBuf((const char*)&xfdata,xfdata.data_size +(sizeof(XFER_DATA_STRUCT)-ChunkSize)); +mySocket->Send((const uint8*)&xfdata, xfdata.data_size +(sizeof(XFER_DATA_STRUCT)-ChunkSize)); } } Index: src/realmd/AuthSocket.h =================================================================== --- src/realmd/AuthSocket.h (revision 5031) +++ src/realmd/AuthSocket.h (working copy) @@ -25,23 +25,19 @@ #include "Common.h" #include "Auth/BigNumber.h" -#include "Network/TcpSocket.h" -#include "Network/SocketHandler.h" -#include "Network/ListenSocket.h" -#include "Network/Utility.h" -#include "Network/Parse.h" -#include "Network/Socket.h" +#include "Network/Network.h" /// Handle login commands -class AuthSocket: public TcpSocket +class AuthSocket: public Socket { public: const static int s_BYTE_SIZE = 32; - AuthSocket(ISocketHandler& h); + AuthSocket(SOCKET h); ~AuthSocket(); - void OnAccept(); + void OnConnect(); + void OnDisconnect(); void OnRead(); bool _HandleLogonChallenge(); Index: src/realmd/Main.cpp =================================================================== --- src/realmd/Main.cpp (revision 5031) +++ src/realmd/Main.cpp (working copy) @@ -26,7 +26,7 @@ #include "Config/ConfigEnv.h" #include "Log.h" -#include "Network/ListenSocket.h" +#include "Network/Network.h" #include "AuthSocket.h" #include "SystemConfig.h" #include "Util.h" @@ -154,7 +154,23 @@ sLog.outString( "MaNGOS realm daemon %s", _FULLVERSION ); sLog.outString( " to stop.\n" ); - +#ifdef USE_LEVENT + //show version of libevent at start + sLog.outBasic("Using %s version of LibEvent",event_get_version()); + bool isvalid_vlibevent=false; + const char* accepted_vlibevent[]=REQ_LEVENT_VER; + for(int i=0;accepted_vlibevent[i];i++) + if(!strcmp(event_get_version(),accepted_vlibevent[i])) + { + isvalid_vlibevent=true; + break; + } + if(!isvalid_vlibevent) + { + sLog.outError("Version of libevent is wrong, shutdown now"); + return 1; + } +#endif//USE_LEVENT /// realmd PID file creation std::string pidfile = sConfig.GetStringDefault("PidFile", ""); if(!pidfile.empty()) @@ -182,19 +198,6 @@ return 1; } - ///- Launch the listening network socket - port_t rmport = sConfig.GetIntDefault( "RealmServerPort", DEFAULT_REALMSERVER_PORT ); - - SocketHandler h; - ListenSocket authListenSocket(h); - if ( authListenSocket.Bind(rmport)) - { - sLog.outError( "MaNGOS realmd can not bind to port %d", rmport ); - return 1; - } - - h.Add(&authListenSocket); - ///- Catch termination signals HookSignals(); @@ -242,18 +245,27 @@ #endif // maximum counter for next ping - uint32 numLoops = (sConfig.GetIntDefault( "MaxPingTime", 30 ) * (MINUTE * 1000000 / 100000)); - uint32 loopCounter = 0; + uint32 PingInterval = (sConfig.GetIntDefault( "MaxPingTime", 30 ) * MINUTE * 1000); + uint32 RestToPing = PingInterval; + uint32 time_to_sleep = 100; + ///- Launch the listening network socket + uint32 rmport = sConfig.GetIntDefault( "RealmServerPort", DEFAULT_REALMSERVER_PORT ); ///- Wait for termination signal - while (!stopEvent) + ListenSocket authListenSocket("0.0.0.0", rmport); + ///- Wait for termination signal or listen socket closing + while (!stopEvent && authListenSocket.IsListernPortOpened()) { + Sleep(time_to_sleep); + if (RestToPing - time_to_sleep < 0) + RestToPing = 0; + else + RestToPing -= time_to_sleep; + if (RestToPing) + continue; - h.Select(0, 100000); - - if( (++loopCounter) == numLoops ) - { - loopCounter = 0; + // ping if need + RestToPing = PingInterval; sLog.outDetail("Ping MySQL to keep connection alive"); delete dbRealmServer.Query("SELECT 1 FROM `realmlist` LIMIT 1"); } @@ -261,7 +273,10 @@ if (m_ServiceStatus == 0) stopEvent = true; while (m_ServiceStatus == 2) Sleep(1000); #endif - } + authListenSocket.StopListening(); + sSocketManager.DisconnectAll(); + sSocketManager.StopIOWorkers(); + sAuthSocketManagerCleaner.Stop(); ///- Wait for the delay thread to exit dbRealmServer.HaltDelayThread();