diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/trinityrealm/AuthSocket.cpp | 187 | ||||
-rw-r--r-- | src/trinityrealm/AuthSocket.h | 21 | ||||
-rw-r--r-- | src/trinityrealm/CMakeLists.txt | 3 | ||||
-rw-r--r-- | src/trinityrealm/Main.cpp | 33 | ||||
-rw-r--r-- | src/trinityrealm/RealmAcceptor.h | 52 | ||||
-rw-r--r-- | src/trinityrealm/RealmSocket.cpp | 312 | ||||
-rw-r--r-- | src/trinityrealm/RealmSocket.h | 84 |
7 files changed, 541 insertions, 151 deletions
diff --git a/src/trinityrealm/AuthSocket.cpp b/src/trinityrealm/AuthSocket.cpp index c9b88833667..1867f317282 100644 --- a/src/trinityrealm/AuthSocket.cpp +++ b/src/trinityrealm/AuthSocket.cpp @@ -233,47 +233,39 @@ const AuthHandler table[] = Patcher PatchesCache; /// Constructor - set the N and g values for SRP6 -AuthSocket::AuthSocket(ISocketHandler &h) : TcpSocket(h) +AuthSocket::AuthSocket(RealmSocket& socket) : socket_(socket) { N.SetHexStr("894B645E89E1535BBDAD5B8B290650530801B18EBFBF5E8FAB3C82872A3E9BB7"); g.SetDword(7); _authed = false; - pPatch = NULL; _accountSecurityLevel = SEC_PLAYER; } /// Close patch file descriptor before leaving -AuthSocket::~AuthSocket() +AuthSocket::~AuthSocket(void) { - ACE_Guard<ACE_Thread_Mutex> g(patcherLock); - - if (pPatch) - fclose(pPatch); } /// Accept the connection and set the s random value for SRP6 -void AuthSocket::OnAccept() +void AuthSocket::OnAccept(void) { - sLog.outBasic("Accepting connection from '%s:%d'", - GetRemoteAddress().c_str(), GetRemotePort()); + sLog.outBasic("Accepting connection from '%s'", socket().get_remote_address().c_str()); +} +void AuthSocket::OnClose(void) +{ + sLog.outDebug("AuthSocket::OnClose"); } /// Read the packet from the client void AuthSocket::OnRead() { - ///- Read the packet - TcpSocket::OnRead(); uint8 _cmd; while (1) { - if (!ibuf.GetLength()) + if(!socket().recv_soft((char *)&_cmd, 1)) return; - - ///- Get the command out of it - ibuf.SoftRead((char *)&_cmd, 1); // UQ1: No longer exists in new net code ??? - size_t i; ///- Circle through known commands and call the correct command handler @@ -283,11 +275,11 @@ void AuthSocket::OnRead() (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 recv length %u", (uint32)_cmd, (uint32)socket().recv_len()); 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 recv length %u", (uint32)_cmd, (uint32)socket().recv_len()); return; } break; @@ -296,11 +288,7 @@ void AuthSocket::OnRead() ///- Report unknown commands in the debug log if (i == AUTH_TOTAL_COMMANDS) - { - DEBUG_LOG("[Auth] got unknown packet from '%s:%d'", GetRemoteAddress().c_str(), GetRemotePort()); - SetCloseAndDelete(); return; - } } } @@ -340,20 +328,20 @@ void AuthSocket::_SetVSFields(const std::string& rI) bool AuthSocket::_HandleLogonChallenge() { DEBUG_LOG("Entering _HandleLogonChallenge"); - if (ibuf.GetLength() < sizeof(sAuthLogonChallenge_C)) + if (socket().recv_len() < sizeof(sAuthLogonChallenge_C)) return false; ///- Read the first 4 bytes (header) to get the length of the remaining of the packet std::vector<uint8> buf; buf.resize(4); - ibuf.Read((char *)&buf[0], 4); + socket().recv((char *)&buf[0], 4); EndianConvert(*((uint16*)(buf[0]))); 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)) + if ((remaining < sizeof(sAuthLogonChallenge_C) - buf.size()) || (socket().recv_len() < remaining)) return false; //No big fear of memory outage (size is int16, i.e. < 65536) @@ -362,7 +350,7 @@ bool AuthSocket::_HandleLogonChallenge() sAuthLogonChallenge_C *ch = (sAuthLogonChallenge_C*)&buf[0]; ///- Read the remaining of the packet - ibuf.Read((char *)&buf[4], remaining); + socket().recv((char *)&buf[4], remaining); DEBUG_LOG("[AuthChallenge] got full packet, %#04x bytes", ch->size); DEBUG_LOG("[AuthChallenge] name(%d): '%s'", ch->I_len, ch->I); @@ -390,6 +378,8 @@ bool AuthSocket::_HandleLogonChallenge() _safelogin = _login; loginDatabase.escape_string(_safelogin); + _build = ch->build; + pkt << (uint8) AUTH_LOGON_CHALLENGE; pkt << (uint8) 0x00; @@ -397,13 +387,13 @@ bool AuthSocket::_HandleLogonChallenge() // No SQL injection possible (paste the IP address as passed by the socket) loginDatabase.Execute("DELETE FROM ip_banned WHERE unbandate<=UNIX_TIMESTAMP() AND unbandate<>bandate"); - std::string address = GetRemoteAddress(); + std::string address(socket().get_remote_address().c_str()); loginDatabase.escape_string(address); QueryResult_AutoPtr result = loginDatabase.PQuery("SELECT * FROM ip_banned WHERE ip = '%s'",address.c_str()); if (result) { pkt << (uint8)REALM_AUTH_ACCOUNT_BANNED; - sLog.outBasic("[AuthChallenge] Banned ip %s tries to login!",GetRemoteAddress().c_str ()); + sLog.outBasic("[AuthChallenge] Banned ip %s tries to login!", address.c_str ()); } else { @@ -423,22 +413,18 @@ bool AuthSocket::_HandleLogonChallenge() if ((*result)[2].GetUInt8() == 1) // if ip is locked { DEBUG_LOG("[AuthChallenge] Account '%s' is locked to IP - '%s'", _login.c_str(), (*result)[3].GetString()); - DEBUG_LOG("[AuthChallenge] Player address is '%s'", GetRemoteAddress().c_str()); - if (strcmp((*result)[3].GetString(),GetRemoteAddress().c_str())) + DEBUG_LOG("[AuthChallenge] Player address is '%s'", socket().get_remote_address().c_str()); + if (strcmp((*result)[3].GetString(),socket().get_remote_address().c_str())) { DEBUG_LOG("[AuthChallenge] Account IP differs"); pkt << (uint8) REALM_AUTH_ACCOUNT_FREEZED; locked=true; } else - { DEBUG_LOG("[AuthChallenge] Account IP matches"); - } } else - { DEBUG_LOG("[AuthChallenge] Account '%s' is not locked to ip", _login.c_str()); - } if (!locked) { @@ -538,7 +524,7 @@ bool AuthSocket::_HandleLogonChallenge() pkt<< (uint8) REALM_AUTH_NO_MATCH; } } - SendBuf((char const*)pkt.contents(), pkt.size()); + socket().send((char const*)pkt.contents(), pkt.size()); return true; } @@ -547,63 +533,18 @@ bool AuthSocket::_HandleLogonProof() { DEBUG_LOG("Entering _HandleLogonProof"); ///- Read the packet - if (ibuf.GetLength() < sizeof(sAuthLogonProof_C)) - return false; sAuthLogonProof_C lp; - ibuf.Read((char *)&lp, sizeof(sAuthLogonProof_C)); + if(!socket().recv((char *)&lp, sizeof(sAuthLogonProof_C))) + return false; /// <ul><li> If the client has no valid version if (_expversion == NO_VALID_EXP_FLAG) { ///- Check if we have the appropriate patch on the disk - // 24 = len("./patches/65535enGB.mpq")+1 - char tmp[24]; - // No buffer overflow (fixed length of arguments) - sprintf(tmp, "./patches/%d%s.mpq", _build, _localizationName.c_str()); - // This will be closed at the destruction of the AuthSocket (client disconnection) - FILE *pFile = fopen(tmp, "rb"); - - if (!pFile) - { - ByteBuffer pkt; - pkt << (uint8) AUTH_LOGON_CHALLENGE; - pkt << (uint8) 0x00; - pkt << (uint8) REALM_AUTH_WRONG_BUILD_NUMBER; - DEBUG_LOG("[AuthChallenge] %u is not a valid client version!", _build); - DEBUG_LOG("[AuthChallenge] Patch %s not found", tmp); - SendBuf((char const*)pkt.contents(), pkt.size()); - return true; - } - else // have patch - { - pPatch = pFile; - XFER_INIT xferh; - - ///- Get the MD5 hash of the patch file (get it from preloaded Patcher cache or calculate it) - if (PatchesCache.GetHash(tmp, (uint8*)&xferh.md5)) - { - DEBUG_LOG("\n[AuthChallenge] Found precached patch info for patch %s", tmp); - } - else - { // calculate patch md5 - printf("\n[AuthChallenge] Patch info for %s was not cached.", tmp); - PatchesCache.LoadPatchMD5(tmp); - PatchesCache.GetHash(tmp, (uint8*)&xferh.md5); - } - - ///- 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)); - - 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)); - return true; - } + sLog.outDebug("Client with invalid version, patching is not implemented"); + socket().shutdown(); + return true; } /// </ul> @@ -614,7 +555,10 @@ bool AuthSocket::_HandleLogonProof() // SRP safeguard: abort if A==0 if (A.isZero()) - return false; + { + socket().shutdown(); + return true; + } Sha1Hash sha; sha.UpdateBigNumbers(&A, &B, NULL); @@ -689,7 +633,7 @@ bool AuthSocket::_HandleLogonProof() ///- Update the sessionkey, last_ip, last login time and reset number of failed logins in the account table for this account // No SQL injection (escaped user name) and IP address as received by socket const char* K_hex = K.AsHexStr(); - loginDatabase.PExecute("UPDATE account SET sessionkey = '%s', last_ip = '%s', last_login = NOW(), locale = '%u', failed_logins = 0 WHERE username = '%s'", K_hex, GetRemoteAddress().c_str(), GetLocaleByName(_localizationName), _safelogin.c_str()); + loginDatabase.PExecute("UPDATE account SET sessionkey = '%s', last_ip = '%s', last_login = NOW(), locale = '%u', failed_logins = 0 WHERE username = '%s'", K_hex, socket().get_remote_address().c_str(), GetLocaleByName(_localizationName), _safelogin.c_str()); OPENSSL_free((void*)K_hex); ///- Finish SRP6 and send the final result to the client @@ -706,7 +650,7 @@ bool AuthSocket::_HandleLogonProof() proof.unk1 = 0x00800000; proof.unk2 = 0x00; proof.unk3 = 0x00; - SendBuf((char *)&proof, sizeof(proof)); + socket().send((char *)&proof, sizeof(proof)); }else{ sAuthLogonProof_S_Old proof; memcpy(proof.M2, sha.GetDigest(), 20); @@ -715,7 +659,7 @@ bool AuthSocket::_HandleLogonProof() //proof.unk1 = 0x00800000; proof.unk2 = 0x00; //proof.unk3 = 0x00; - SendBuf((char *)&proof, sizeof(proof)); + socket().send((char *)&proof, sizeof(proof)); } ///- Set _authed to true! @@ -724,7 +668,7 @@ bool AuthSocket::_HandleLogonProof() else { char data[4]= { AUTH_LOGON_PROOF, REALM_AUTH_NO_MATCH, 3, 0}; - SendBuf(data, sizeof(data)); + socket().send(data, sizeof(data)); sLog.outBasic("[AuthChallenge] account %s tried to login with wrong password!",_login.c_str ()); uint32 MaxWrongPassCount = sConfig.GetIntDefault("WrongPass.MaxCount", 0); @@ -753,7 +697,7 @@ bool AuthSocket::_HandleLogonProof() } else { - std::string current_ip = GetRemoteAddress(); + std::string current_ip(socket().get_remote_address().c_str()); loginDatabase.escape_string(current_ip); loginDatabase.PExecute("INSERT INTO ip_banned VALUES ('%s',UNIX_TIMESTAMP(),UNIX_TIMESTAMP()+'%u','Trinity realmd','Failed login autoban')", current_ip.c_str(), WrongPassBanTime); @@ -771,20 +715,20 @@ bool AuthSocket::_HandleLogonProof() bool AuthSocket::_HandleReconnectChallenge() { DEBUG_LOG("Entering _HandleReconnectChallenge"); - if (ibuf.GetLength() < sizeof(sAuthLogonChallenge_C)) + if (socket().recv_len() < sizeof(sAuthLogonChallenge_C)) return false; ///- Read the first 4 bytes (header) to get the length of the remaining of the packet std::vector<uint8> buf; buf.resize(4); - ibuf.Read((char *)&buf[0], 4); + socket().recv((char *)&buf[0], 4); EndianConvert(*((uint16*)(buf[0]))); uint16 remaining = ((sAuthLogonChallenge_C *)&buf[0])->size; DEBUG_LOG("[ReconnectChallenge] got header, body is %#04x bytes", remaining); - if ((remaining < sizeof(sAuthLogonChallenge_C) - buf.size()) || (ibuf.GetLength() < remaining)) + if ((remaining < sizeof(sAuthLogonChallenge_C) - buf.size()) || (socket().recv_len() < remaining)) return false; //No big fear of memory outage (size is int16, i.e. < 65536) @@ -793,7 +737,7 @@ bool AuthSocket::_HandleReconnectChallenge() sAuthLogonChallenge_C *ch = (sAuthLogonChallenge_C*)&buf[0]; ///- Read the remaining of the packet - ibuf.Read((char *)&buf[4], remaining); + socket().recv((char *)&buf[4], remaining); DEBUG_LOG("[ReconnectChallenge] got full packet, %#04x bytes", ch->size); DEBUG_LOG("[ReconnectChallenge] name(%d): '%s'", ch->I_len, ch->I); @@ -806,7 +750,7 @@ bool AuthSocket::_HandleReconnectChallenge() if (!result) { sLog.outError("[ERROR] user %s tried to login and we cannot find his session key in the database.", _login.c_str()); - SetCloseAndDelete(); + socket().shutdown(); return false; } @@ -820,7 +764,7 @@ bool AuthSocket::_HandleReconnectChallenge() _reconnectProof.SetRand(16 * 8); pkt.append(_reconnectProof.AsByteArray(16), 16); // 16 bytes random pkt << (uint64) 0x00 << (uint64) 0x00; // 16 bytes zeros - SendBuf((char const*)pkt.contents(), pkt.size()); + socket().send((char const*)pkt.contents(), pkt.size()); return true; } @@ -829,12 +773,11 @@ bool AuthSocket::_HandleReconnectProof() { DEBUG_LOG("Entering _HandleReconnectProof"); ///- Read the packet - if (ibuf.GetLength() < sizeof(sAuthReconnectProof_C)) + sAuthReconnectProof_C lp; + if(!socket().recv((char *)&lp, sizeof(sAuthReconnectProof_C))) return false; if (_login.empty() || !_reconnectProof.GetNumBytes() || !K.GetNumBytes()) return false; - sAuthReconnectProof_C lp; - ibuf.Read((char *)&lp, sizeof(sAuthReconnectProof_C)); BigNumber t1; t1.SetBinary(lp.R1, 16); @@ -852,7 +795,7 @@ bool AuthSocket::_HandleReconnectProof() pkt << (uint8) AUTH_RECONNECT_PROOF; pkt << (uint8) 0x00; pkt << (uint16) 0x00; // 2 bytes zeros - SendBuf((char const*)pkt.contents(), pkt.size()); + socket().send((char const*)pkt.contents(), pkt.size()); ///- Set _authed to true! _authed = true; @@ -862,7 +805,7 @@ bool AuthSocket::_HandleReconnectProof() else { sLog.outError("[ERROR] user %s tried to login, but session invalid.", _login.c_str()); - SetCloseAndDelete(); + socket().shutdown(); return false; } } @@ -871,10 +814,10 @@ bool AuthSocket::_HandleReconnectProof() bool AuthSocket::_HandleRealmList() { DEBUG_LOG("Entering _HandleRealmList"); - if (ibuf.GetLength() < 5) + if (socket().recv_len() < 5) return false; - ibuf.Remove(5); + socket().recv_skip(5); ///- Get the user id (else close the connection) // No SQL injection (escaped user name) @@ -883,7 +826,7 @@ bool AuthSocket::_HandleRealmList() if (!result) { sLog.outError("[ERROR] user %s tried to login and we cannot find him in the database.",_login.c_str()); - SetCloseAndDelete(); + socket().shutdown(); return false; } @@ -963,7 +906,7 @@ bool AuthSocket::_HandleRealmList() hdr << (uint16)pkt.size(); hdr.append(pkt); - SendBuf((char const*)hdr.contents(), hdr.size()); + socket().send((char const*)hdr.contents(), hdr.size()); return true; } @@ -973,7 +916,7 @@ bool AuthSocket::_HandleXferResume() { DEBUG_LOG("Entering _HandleXferResume"); ///- Check packet length and patch existence - if (ibuf.GetLength() < 9 || !pPatch) + if (socket().recv_len() < 9 || !pPatch) { sLog.outError("Error while resuming patch transfer (wrong packet)"); return false; @@ -981,8 +924,8 @@ bool AuthSocket::_HandleXferResume() ///- Launch a PatcherRunnable thread starting at given patch file offset uint64 start; - ibuf.Remove(1); - ibuf.Read((char*)&start,sizeof(start)); + socket().recv_skip(1); + socket().recv((char*)&start,sizeof(start)); fseek(pPatch, start, 0); ACE_Based::Thread u(new PatcherRunnable(this)); @@ -995,9 +938,9 @@ bool AuthSocket::_HandleXferCancel() DEBUG_LOG("Entering _HandleXferCancel"); ///- Close and delete the socket - ibuf.Remove(1); //clear input buffer + socket().recv_skip(1); //clear input buffer - SetCloseAndDelete(); + socket().shutdown(); return true; } @@ -1015,7 +958,7 @@ bool AuthSocket::_HandleXferAccept() } ///- Launch a PatcherRunnable thread, starting at the beginning of the patch file - ibuf.Remove(1); // clear input buffer + socket().recv_skip(1); // clear input buffer fseek(pPatch, 0, 0); ACE_Based::Thread u(new PatcherRunnable(this)); @@ -1025,7 +968,7 @@ bool AuthSocket::_HandleXferAccept() /// Check if there is lag on the connection to the client bool AuthSocket::IsLag() { - return (TCP_BUFSIZE_READ-GetOutputLength() < 2 * ChunkSize); + } PatcherRunnable::PatcherRunnable(class AuthSocket * as) @@ -1036,22 +979,6 @@ PatcherRunnable::PatcherRunnable(class AuthSocket * as) /// Send content of patch file to the client void PatcherRunnable::run() { - ACE_Guard<ACE_Thread_Mutex> g(mySocket->patcherLock); - - XFER_DATA_STRUCT xfdata; - xfdata.opcode = XFER_DATA; - - while(!feof(mySocket->pPatch) && mySocket->Ready()) - { - ///- Wait until output buffer is reasonably empty - while(mySocket->Ready() && mySocket->IsLag()) - { - ACE_Based::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)); - } } /// Preload MD5 hashes of existing patch files on server diff --git a/src/trinityrealm/AuthSocket.h b/src/trinityrealm/AuthSocket.h index e0f0b39ddea..16a74636820 100644 --- a/src/trinityrealm/AuthSocket.h +++ b/src/trinityrealm/AuthSocket.h @@ -27,24 +27,21 @@ #include "Common.h" #include "Auth/BigNumber.h" -#include "sockets/TcpSocket.h" -#include "sockets/SocketHandler.h" -#include "sockets/ListenSocket.h" -#include "sockets/Utility.h" -#include "sockets/Parse.h" -#include "sockets/Socket.h" + +#include "RealmSocket.h" /// Handle login commands -class AuthSocket: public TcpSocket +class AuthSocket: public RealmSocket::Session { public: const static int s_BYTE_SIZE = 32; - AuthSocket(ISocketHandler& h); - ~AuthSocket(); + AuthSocket(RealmSocket& socket); + virtual ~AuthSocket(void); - void OnAccept(); - void OnRead(); + virtual void OnRead(void); + virtual void OnAccept(void); + virtual void OnClose(void); bool _HandleLogonChallenge(); bool _HandleLogonProof(); @@ -64,6 +61,8 @@ class AuthSocket: public TcpSocket bool IsLag(); private: + RealmSocket& socket_; + RealmSocket& socket(void) { return socket_; } BigNumber N, s, g, v; BigNumber b, B; diff --git a/src/trinityrealm/CMakeLists.txt b/src/trinityrealm/CMakeLists.txt index b0b70a7ee42..b87ba0138a3 100644 --- a/src/trinityrealm/CMakeLists.txt +++ b/src/trinityrealm/CMakeLists.txt @@ -8,6 +8,9 @@ AuthSocket.h Main.cpp RealmList.cpp RealmList.h +RealmSocket.h +RealmSocket.cpp +RealmAcceptor.h ) SET(trinity-realm_LINK_FLAGS "") diff --git a/src/trinityrealm/Main.cpp b/src/trinityrealm/Main.cpp index 68e200969e3..d79881a2351 100644 --- a/src/trinityrealm/Main.cpp +++ b/src/trinityrealm/Main.cpp @@ -25,13 +25,17 @@ #include "Common.h" #include "Database/DatabaseEnv.h" #include "RealmList.h" +#include "RealmAcceptor.h" #include "Config/ConfigEnv.h" #include "Log.h" -#include "sockets/ListenSocket.h" #include "AuthSocket.h" #include "SystemConfig.h" #include "Util.h" + +#include <ace/Dev_Poll_Reactor.h> +#include <ace/ACE.h> + #include <openssl/opensslv.h> #include <openssl/crypto.h> @@ -158,6 +162,12 @@ extern int main(int argc, char **argv) return 1; } +#if defined (ACE_HAS_EVENT_POLL) || defined (ACE_HAS_DEV_POLL) + ACE_Reactor::instance(new ACE_Reactor(new ACE_Dev_Poll_Reactor(ACE::max_handles(), 1), 1), true); +#endif + + sLog.outBasic("Max allowed open files is %d", ACE::max_handles()); + /// realmd PID file creation std::string pidfile = sConfig.GetStringDefault("PidFile", ""); if (!pidfile.empty()) @@ -201,19 +211,19 @@ extern int main(int argc, char **argv) } ///- Launch the listening network socket - port_t rmport = sConfig.GetIntDefault("RealmServerPort", DEFAULT_REALMSERVER_PORT); - std::string bind_ip = sConfig.GetStringDefault("BindIP", "0.0.0.0"); + RealmAcceptor acceptor; - SocketHandler h; - ListenSocket<AuthSocket> authListenSocket(h); - if (authListenSocket.Bind(bind_ip.c_str(),rmport)) + uint16 rmport = sConfig.GetIntDefault("RealmServerPort", DEFAULT_REALMSERVER_PORT); + std::string bind_ip = sConfig.GetStringDefault("BindIP", "0.0.0.0"); + + ACE_INET_Addr bind_addr(rmport, bind_ip.c_str()); + + if(acceptor.open(bind_addr, ACE_Reactor::instance(), ACE_NONBLOCK) == -1) { - sLog.outError("Trinity realm can not bind to %s:%d",bind_ip.c_str(), rmport); + sLog.outError("Trinity realm can not bind to %s:%d", bind_ip.c_str(), rmport); return 1; } - h.Add(&authListenSocket); - ///- Catch termination signals HookSignals(); @@ -281,8 +291,11 @@ extern int main(int argc, char **argv) ///- Wait for termination signal while (!stopEvent) { + // dont move this outside the loop, the reactor will modify it + ACE_Time_Value interval(0, 100000); - h.Select(0, 100000); + if (ACE_Reactor::instance()->run_reactor_event_loop(interval) == -1) + break; if ((++loopCounter) == numLoops) { diff --git a/src/trinityrealm/RealmAcceptor.h b/src/trinityrealm/RealmAcceptor.h new file mode 100644 index 00000000000..14a52134a28 --- /dev/null +++ b/src/trinityrealm/RealmAcceptor.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2005-2010 MaNGOS <http://getmangos.com/> + * + * Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/> + * + * 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 2 of the License, or + * (at your option) 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/** \file + \ingroup realmd + */ + +#ifndef __REALMACCEPTOR_H__ +#define __REALMACCEPTOR_H__ + +#include <ace/Acceptor.h> +#include <ace/SOCK_Acceptor.h> + +#include "RealmSocket.h" +#include "AuthSocket.h" + +class RealmAcceptor : public ACE_Acceptor<RealmSocket, ACE_SOCK_Acceptor> +{ + public: + RealmAcceptor(void) { } + virtual ~RealmAcceptor(void) { } + + protected: + virtual int make_svc_handler(RealmSocket *&sh) + { + if (sh == 0) + ACE_NEW_RETURN(sh, RealmSocket, -1); + + sh->reactor(this->reactor()); + sh->set_session(new AuthSocket(*sh)); + return 0; + } +}; + +#endif /* __REALMACCEPTOR_H__ */ diff --git a/src/trinityrealm/RealmSocket.cpp b/src/trinityrealm/RealmSocket.cpp new file mode 100644 index 00000000000..dbd957ec12e --- /dev/null +++ b/src/trinityrealm/RealmSocket.cpp @@ -0,0 +1,312 @@ +/* + * Copyright (C) 2005-2010 MaNGOS <http://getmangos.com/> + * + * Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/> + * + * 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 2 of the License, or + * (at your option) 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/** \file + \ingroup realmd + */ + +#include "RealmSocket.h" + +#include <ace/OS_NS_string.h> +#include <ace/INET_Addr.h> +#include <ace/SString.h> + +#ifndef MSG_NOSIGNAL +#define MSG_NOSIGNAL 0 +#endif + +RealmSocket::Session::Session(void) +{ +} + +RealmSocket::Session::~Session(void) +{ +} + +RealmSocket::RealmSocket(void): + input_buffer_(4096), + session_(NULL), + remote_address_() +{ + this->reference_counting_policy().value( + ACE_Event_Handler::Reference_Counting_Policy::ENABLED); + + this->msg_queue()->high_water_mark(8*1024*1024); + this->msg_queue()->low_water_mark(8*1024*1024); +} + +/*virtual*/ RealmSocket::~RealmSocket(void) +{ + if(this->session_) + delete this->session_; + + if(this->peer().get_handle() != ACE_INVALID_HANDLE) + this->peer().close(); +} + +/*virtual*/ int RealmSocket::open(void * arg) +{ + if(Base::open(arg) == -1) + return -1; + + ACE_INET_Addr addr; + + if(peer().get_remote_addr(addr) == -1) + return -1; + + char address[1024]; + + addr.get_host_addr(address, 1024); + + this->remote_address_ = address; + + if(this->session_ != NULL) + { + // Prepare for upcall + this->add_reference(); + ACE_Event_Handler_var guard(this); + + this->session_->OnAccept(); + } + + this->remove_reference(); + + return 0; +} + +const ACE_CString& RealmSocket::get_remote_address(void) const +{ + return this->remote_address_; +} + +size_t RealmSocket::recv_len(void) const +{ + return this->input_buffer_.length(); +} + +bool RealmSocket::recv_soft(char *buf, size_t len) +{ + if(this->input_buffer_.length() < len) + return false; + + ACE_OS::memcpy(buf, this->input_buffer_.rd_ptr(), len); + + return true; +} + +bool RealmSocket::recv(char *buf, size_t len) +{ + bool ret = this->recv_soft(buf, len); + + if(ret) + this->recv_skip(len); + + return ret; +} + +void RealmSocket::recv_skip(size_t len) +{ + this->input_buffer_.rd_ptr(len); +} + +ssize_t RealmSocket::noblk_send(ACE_Message_Block &message_block) +{ + const size_t len = message_block.length(); + + if(len == 0) + return -1; + + // Try to send the message directly. + ssize_t n = this->peer().send(message_block.rd_ptr(), len, MSG_NOSIGNAL); + + if(n < 0) + { + if(errno == EWOULDBLOCK) + // Blocking signal + return 0; + else + // Error happened + return -1; + } + else if(n == 0) + { + // Can this happen ? + return -1; + } + + // return bytes transmitted + return n; +} + +bool RealmSocket::send(const char *buf, size_t len) +{ + if(buf == NULL || len == 0) + return true; + + ACE_Data_Block db( + len, + ACE_Message_Block::MB_DATA, + (const char*)buf, + 0, + 0, + ACE_Message_Block::DONT_DELETE, + 0); + + ACE_Message_Block message_block( + &db, + ACE_Message_Block::DONT_DELETE, + 0); + + message_block.wr_ptr(len); + + if(this->msg_queue()->is_empty()) + { + // Try to send it directly. + ssize_t n = this->noblk_send(message_block); + + if(n < 0) + return false; + else if(n == len) + return true; + + // fall down + message_block.rd_ptr((size_t)n); + } + + ACE_Message_Block *mb = message_block.clone(); + + if(this->msg_queue()->enqueue_tail(mb, (ACE_Time_Value *) &ACE_Time_Value::zero) == -1) + { + mb->release(); + return false; + } + + if(this->reactor()->schedule_wakeup(this, ACE_Event_Handler::WRITE_MASK) == -1) + return false; + + return true; +} + +/*virtual*/ int RealmSocket::handle_output(ACE_HANDLE /*= ACE_INVALID_HANDLE*/) +{ + ACE_Message_Block *mb = 0; + + if(this->msg_queue()->is_empty()) + { + this->reactor()->cancel_wakeup(this, ACE_Event_Handler::WRITE_MASK); + return 0; + } + + if(this->msg_queue()->dequeue_head(mb, (ACE_Time_Value *) &ACE_Time_Value::zero) == -1) + return -1; + + ssize_t n = this->noblk_send(*mb); + + if(n < 0) + { + mb->release(); + return -1; + } + else if(n == mb->length()) + { + mb->release(); + return 1; + } + else + { + mb->rd_ptr(n); + + if(this->msg_queue()->enqueue_head(mb, (ACE_Time_Value *) &ACE_Time_Value::zero) == -1) + { + mb->release(); + return -1; + } + + return 0; + } + + ACE_NOTREACHED(return -1); +} + +/*virtual*/ int RealmSocket::handle_input(ACE_HANDLE /*= ACE_INVALID_HANDLE*/) +{ + const ssize_t space = this->input_buffer_.space(); + + ssize_t n = this->peer().recv(this->input_buffer_.wr_ptr(), space); + + if(n < 0) + { + return errno == EWOULDBLOCK ? 0 : -1; + } + else if(n == 0) + { + // EOF + return -1; + } + + this->input_buffer_.wr_ptr((size_t)n); + + if(this->session_ != NULL) + { + // Prepare for upcall + this->add_reference(); + ACE_Event_Handler_var guard(this); + + this->session_->OnRead(); + + this->input_buffer_.crunch(); + } + + // return 1 in case there is more data to read from OS + return n == space ? 1 : 0; +} + +/*virtual*/ int RealmSocket::handle_close(ACE_HANDLE h, ACE_Reactor_Mask m) +{ + if(this->session_ != NULL) + { + // Prepare for upcall + this->add_reference(); + ACE_Event_Handler_var guard(this); + + this->session_->OnClose(); + } + + this->shutdown(); + + return 0; +} + +void RealmSocket::set_session(Session* session) +{ + if(this->session_ != NULL) + delete this->session_; + + this->session_ = session; +} + +int RealmSocket::close(int) +{ + this->shutdown(); + + this->remove_reference(); + + return 0; +} diff --git a/src/trinityrealm/RealmSocket.h b/src/trinityrealm/RealmSocket.h new file mode 100644 index 00000000000..2ac021d5cc3 --- /dev/null +++ b/src/trinityrealm/RealmSocket.h @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2005-2010 MaNGOS <http://getmangos.com/> + * + * Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/> + * + * 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 2 of the License, or + * (at your option) 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/** \file + \ingroup realmd + */ + +#ifndef __REALMSOCKET_H__ +#define __REALMSOCKET_H__ + +#include <ace/Basic_Types.h> +#include <ace/Synch_Traits.h> +#include <ace/Svc_Handler.h> +#include <ace/SOCK_Stream.h> +#include <ace/Message_Block.h> +#include <ace/Basic_Types.h> + +class RealmSocket : public ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_NULL_SYNCH> +{ + private: + typedef ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_NULL_SYNCH> Base; + + public: + class Session + { + public: + Session(void); + virtual ~Session(void); + + virtual void OnRead(void) = 0; + virtual void OnAccept(void) = 0; + virtual void OnClose(void) = 0; + }; + + RealmSocket(void); + virtual ~RealmSocket(void); + + size_t recv_len(void) const; + bool recv_soft(char *buf, size_t len); + bool recv(char *buf, size_t len); + void recv_skip(size_t len); + + bool send(const char *buf, size_t len); + + const ACE_CString& get_remote_address(void) const; + + virtual int open(void *); + + virtual int handle_input(ACE_HANDLE = ACE_INVALID_HANDLE); + virtual int handle_output(ACE_HANDLE = ACE_INVALID_HANDLE); + + virtual int handle_close(ACE_HANDLE = ACE_INVALID_HANDLE, + ACE_Reactor_Mask = ACE_Event_Handler::ALL_EVENTS_MASK); + + void set_session(Session* session); + + int close(int); + private: + ssize_t noblk_send(ACE_Message_Block &message_block); + + private: + ACE_Message_Block input_buffer_; + Session* session_; + ACE_CString remote_address_; +}; + +#endif /* __REALMSOCKET_H__ */ |