- Timestamp:
- 11/19/08 13:44:02 (17 years ago)
- Location:
- trunk/src
- Files:
-
- 5 modified
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/framework/Utilities/ByteConverter.h
r102 r181 11 11 * This program is distributed in the hope that it will be useful, 12 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 14 * GNU General Public License for more details. 15 15 * 16 16 * You should have received a copy of the GNU General Public License 17 17 * along with this program; if not, write to the Free Software 18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307USA18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 19 */ 20 20 … … 49 49 #if TRINITY_ENDIAN == TRINITY_BIGENDIAN 50 50 template<typename T> inline void EndianConvert(T& val) { ByteConverter::apply<T>(&val); } 51 template<typename T> inline void EndianConvertReverse(T&) { } 51 52 #else 52 53 template<typename T> inline void EndianConvert(T&) { } 54 template<typename T> inline void EndianConvertReverse(T& val) { ByteConverter::apply<T>(&val); } 53 55 #endif 54 56 55 template<typename T> inline void EndianConvert(T*) { } 57 template<typename T> void EndianConvert(T*); // will generate link error 58 template<typename T> void EndianConvertReverse(T*); // will generate link error 59 56 60 inline void EndianConvert(uint8&) { } 57 61 inline void EndianConvert( int8&) { } 62 inline void EndianConvertReverse(uint8&) { } 63 inline void EndianConvertReverse( int8&) { } 58 64 59 65 #endif -
trunk/src/game/World.cpp
r168 r181 129 129 130 130 if(m_resultQueue) delete m_resultQueue; 131 131 132 132 //TODO free addSessQueue 133 133 } … … 183 183 void World::AddSession(WorldSession* s) 184 184 { 185 addSessQueue.add(s);185 addSessQueue.add(s); 186 186 } 187 187 … … 189 189 World::AddSession_ (WorldSession* s) 190 190 { 191 ASSERT (s);192 193 //NOTE - Still there is race condition in WorldSession* being used in the Sockets194 195 ///- kick already loaded player with same account (if any) and remove session196 ///- if player is in loading and want to load again, return197 if (!RemoveSession (s->GetAccountId ()))198 { 199 s->KickPlayer ();200 m_kicked_sessions.insert (s);201 return;202 } 203 204 WorldSession* old = m_sessions[s->GetAccountId ()];205 m_sessions[s->GetAccountId ()] = s;206 207 // if session already exist, prepare to it deleting at next world update208 // NOTE - KickPlayer() should be called on "old" in RemoveSession()209 if (old)210 m_kicked_sessions.insert (old);211 212 uint32 Sessions = GetActiveAndQueuedSessionCount ();213 uint32 pLimit = GetPlayerAmountLimit ();214 uint32 QueueSize = GetQueueSize (); //number of players in the queue215 bool inQueue = false;216 //so we don't count the user trying to217 //login as a session and queue the socket that we are using218 --Sessions;219 220 if (pLimit > 0 && Sessions >= pLimit && s->GetSecurity () == SEC_PLAYER )221 { 222 AddQueuedPlayer (s);223 UpdateMaxSessionCounters ();224 sLog.outDetail ("PlayerQueue: Account id %u is in Queue Position (%u).", s->GetAccountId (), ++QueueSize);225 return;226 } 227 228 WorldPacket packet(SMSG_AUTH_RESPONSE, 1 + 4 + 1 + 4 + 1);229 packet << uint8 (AUTH_OK);230 packet << uint32 (0); // unknown random value...231 packet << uint8 (0);232 packet << uint32 (0);233 packet << uint8 (s->Expansion () ? 1 : 0); // 0 - normal, 1 - TBC, must be set in database manually for each account234 s->SendPacket (&packet);235 236 UpdateMaxSessionCounters ();237 238 // Updates the population239 if (pLimit > 0)240 { 241 float popu = GetActiveSessionCount (); //updated number of users on the server242 popu /= pLimit;243 popu *= 2;244 loginDatabase.PExecute ("UPDATE realmlist SET population = '%f' WHERE id = '%d'", popu, realmID);245 sLog.outDetail ("Server Population (%f).", popu);191 ASSERT (s); 192 193 //NOTE - Still there is race condition in WorldSession* being used in the Sockets 194 195 ///- kick already loaded player with same account (if any) and remove session 196 ///- if player is in loading and want to load again, return 197 if (!RemoveSession (s->GetAccountId ())) 198 { 199 s->KickPlayer (); 200 m_kicked_sessions.insert (s); 201 return; 202 } 203 204 WorldSession* old = m_sessions[s->GetAccountId ()]; 205 m_sessions[s->GetAccountId ()] = s; 206 207 // if session already exist, prepare to it deleting at next world update 208 // NOTE - KickPlayer() should be called on "old" in RemoveSession() 209 if (old) 210 m_kicked_sessions.insert (old); 211 212 uint32 Sessions = GetActiveAndQueuedSessionCount (); 213 uint32 pLimit = GetPlayerAmountLimit (); 214 uint32 QueueSize = GetQueueSize (); //number of players in the queue 215 bool inQueue = false; 216 //so we don't count the user trying to 217 //login as a session and queue the socket that we are using 218 --Sessions; 219 220 if (pLimit > 0 && Sessions >= pLimit && s->GetSecurity () == SEC_PLAYER ) 221 { 222 AddQueuedPlayer (s); 223 UpdateMaxSessionCounters (); 224 sLog.outDetail ("PlayerQueue: Account id %u is in Queue Position (%u).", s->GetAccountId (), ++QueueSize); 225 return; 226 } 227 228 WorldPacket packet(SMSG_AUTH_RESPONSE, 1 + 4 + 1 + 4 + 1); 229 packet << uint8 (AUTH_OK); 230 packet << uint32 (0); // unknown random value... 231 packet << uint8 (0); 232 packet << uint32 (0); 233 packet << uint8 (s->Expansion()); // 0 - normal, 1 - TBC, must be set in database manually for each account 234 s->SendPacket (&packet); 235 236 UpdateMaxSessionCounters (); 237 238 // Updates the population 239 if (pLimit > 0) 240 { 241 float popu = GetActiveSessionCount (); //updated number of users on the server 242 popu /= pLimit; 243 popu *= 2; 244 loginDatabase.PExecute ("UPDATE realmlist SET population = '%f' WHERE id = '%d'", popu, realmID); 245 sLog.outDetail ("Server Population (%f).", popu); 246 246 } 247 247 } … … 261 261 { 262 262 m_QueuedPlayer.push_back (sess); 263 263 264 264 // The 1st SMSG_AUTH_RESPONSE needs to contain other info too. 265 265 WorldPacket packet (SMSG_AUTH_RESPONSE, 1 + 4 + 1 + 4 + 1); … … 271 271 packet << uint32(GetQueuePos (sess)); 272 272 sess->SendPacket (&packet); 273 273 274 274 //sess->SendAuthWaitQue (GetQueuePos (sess)); 275 275 } … … 2283 2283 2284 2284 ///- Update the database with ban information 2285 2285 switch(mode) 2286 2286 { 2287 2287 case BAN_IP: 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 } 2303 2304 2305 2306 2307 return BAN_SUCCESS; 2308 2309 2310 2288 //No SQL injection as strings are escaped 2289 resultAccounts = loginDatabase.PQuery("SELECT id FROM account WHERE last_ip = '%s'",nameOrIP.c_str()); 2290 loginDatabase.PExecute("INSERT INTO ip_banned VALUES ('%s',UNIX_TIMESTAMP(),UNIX_TIMESTAMP()+%u,'%s','%s')",nameOrIP.c_str(),duration_secs,safe_author.c_str(),reason.c_str()); 2291 break; 2292 case BAN_ACCOUNT: 2293 //No SQL injection as string is escaped 2294 resultAccounts = loginDatabase.PQuery("SELECT id FROM account WHERE username = '%s'",nameOrIP.c_str()); 2295 break; 2296 case BAN_CHARACTER: 2297 //No SQL injection as string is escaped 2298 resultAccounts = CharacterDatabase.PQuery("SELECT account FROM characters WHERE name = '%s'",nameOrIP.c_str()); 2299 break; 2300 default: 2301 return BAN_SYNTAX_ERROR; 2302 } 2303 2304 if(!resultAccounts) 2305 { 2306 if(mode==BAN_IP) 2307 return BAN_SUCCESS; // ip correctly banned but nobody affected (yet) 2308 else 2309 return BAN_NOTFOUND; // Nobody to ban 2310 } 2311 2311 2312 2312 ///- Disconnect all affected players (for IP it can be several) … … 2317 2317 2318 2318 if(mode!=BAN_IP) 2319 2319 { 2320 2320 //No SQL injection as strings are escaped 2321 2321 loginDatabase.PExecute("INSERT INTO account_banned VALUES ('%u', UNIX_TIMESTAMP(), UNIX_TIMESTAMP()+%u, '%s', '%s', '1')", 2322 2322 account,duration_secs,safe_author.c_str(),reason.c_str()); 2323 2323 } 2324 2324 2325 2325 if (WorldSession* sess = FindSession(account)) … … 2343 2343 else 2344 2344 { 2345 uint32 account =0;2345 uint32 account = 0; 2346 2346 if (mode == BAN_ACCOUNT) 2347 2347 account = accmgr.GetId (nameOrIP); … … 2349 2349 account = objmgr.GetPlayerAccountIdByPlayerName (nameOrIP); 2350 2350 2351 if (!account)2351 if (!account) 2352 2352 return false; 2353 2353 2354 2354 //NO SQL injection as account is uint32 2355 2355 loginDatabase.PExecute("UPDATE account_banned SET active = '0' WHERE id = '%u'",account); … … 2434 2434 2435 2435 SendServerMessage(msgid,str.c_str(),player); 2436 outstring_log("Server will %s in %s", (m_ShutdownMask & SHUTDOWN_MASK_RESTART ? "restart" : "shutdown"),str.c_str());2436 DEBUG_LOG("Server is %s in %s",(m_ShutdownMask & SHUTDOWN_MASK_RESTART ? "restart" : "shuttingdown"),str.c_str()); 2437 2437 } 2438 2438 } … … 2474 2474 AddSession_ (sess); 2475 2475 } 2476 2476 2477 2477 ///- Delete kicked sessions at add new session 2478 2478 for (std::set<WorldSession*>::iterator itr = m_kicked_sessions.begin(); itr != m_kicked_sessions.end(); ++itr) 2479 { 2479 { 2480 2480 RemoveQueuedPlayer (*itr); 2481 2481 delete *itr; … … 2505 2505 { 2506 2506 if (cliCmdQueue.empty()) 2507 2507 return; 2508 2508 2509 2509 CliCommandHolder::Print* zprint; 2510 2510 2511 while (!cliCmdQueue.empty()) 2511 2512 { … … 2513 2514 CliCommandHolder *command = cliCmdQueue.next(); 2514 2515 2515 2516 2517 2516 zprint = command->m_print; 2517 2518 CliHandler(zprint).ParseCommands(command->m_command); 2518 2519 2519 2520 delete command; … … 2623 2624 void World::LoadDBVersion() 2624 2625 { 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 } 2626 QueryResult* result = WorldDatabase.Query("SELECT version FROM db_version LIMIT 1"); 2627 if(result) 2628 { 2629 Field* fields = result->Fetch(); 2630 2631 m_DBVersion = fields[0].GetString(); 2632 delete result; 2633 } 2634 else 2635 m_DBVersion = "unknown world database"; 2636 } -
trunk/src/game/WorldSession.cpp
r174 r181 11 11 * This program is distributed in the hope that it will be useful, 12 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 14 * GNU General Public License for more details. 15 15 * 16 16 * You should have received a copy of the GNU General Public License 17 17 * along with this program; if not, write to the Free Software 18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307USA18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 19 */ 20 20 … … 51 51 _logoutTime(0), m_playerLoading(false), m_playerLogout(false), m_playerRecentlyLogout(false), m_latency(0) 52 52 { 53 if (sock)54 {55 56 57 }53 if (sock) 54 { 55 m_Address = sock->GetRemoteAddress (); 56 sock->AddReference (); 57 } 58 58 } 59 59 … … 62 62 { 63 63 ///- unload player if not unloaded 64 if (_player)65 LogoutPlayer (true);64 if (_player) 65 LogoutPlayer (true); 66 66 67 67 /// - If have unclosed socket, close it 68 if (m_Socket)69 { 70 m_Socket->CloseSocket ();71 m_Socket->RemoveReference ();72 m_Socket = NULL;68 if (m_Socket) 69 { 70 m_Socket->CloseSocket (); 71 m_Socket->RemoveReference (); 72 m_Socket = NULL; 73 73 } 74 74 … … 76 76 while(!_recvQueue.empty()) 77 77 { 78 WorldPacket *packet = _recvQueue.next ();78 WorldPacket *packet = _recvQueue.next (); 79 79 delete packet; 80 80 } 81 82 81 } 83 82 … … 134 133 } 135 134 136 #endif // !TRINITY_DEBUG137 138 139 135 #endif // !MANGOS_DEBUG 136 137 if (m_Socket->SendPacket (*packet) == -1) 138 m_Socket->CloseSocket (); 140 139 } 141 140 … … 158 157 bool WorldSession::Update(uint32 /*diff*/) 159 158 { 160 if (m_Socket && m_Socket->IsClosed ())161 {159 if (m_Socket && m_Socket->IsClosed ()) 160 { 162 161 m_Socket->RemoveReference (); 163 162 m_Socket = NULL; 164 }165 163 } 164 166 165 WorldPacket *packet; 167 166 … … 248 247 if (uint64 lguid = GetPlayer()->GetLootGUID()) 249 248 DoLootRelease(lguid); 250 249 251 250 ///- If the player just died before logging out, make him appear as a ghost 252 251 //FIXME: logout must be delayed in case lost connection with client in time of combat … … 285 284 // give honor to all attackers from set like group case 286 285 for(std::set<Player*>::const_iterator itr = aset.begin(); itr != aset.end(); ++itr) 287 (*itr)->RewardHonor(_player, aset.size(), -1, true);286 (*itr)->RewardHonor(_player,aset.size()); 288 287 289 288 // give bg rewards and update counters like kill by first from attackers … … 403 402 //No SQL injection as AccountId is uint32 404 403 CharacterDatabase.PExecute("UPDATE characters SET online = 0 WHERE account = '%u'", 405 404 GetAccountId()); 406 405 sLog.outDebug( "SESSION: Sent SMSG_LOGOUT_COMPLETE Message" ); 407 406 } … … 415 414 void WorldSession::KickPlayer() 416 415 { 417 418 416 if (m_Socket) 417 m_Socket->CloseSocket (); 419 418 } 420 419 … … 522 521 } 523 522 } 524 525 526 527 -
trunk/src/game/WorldSocket.cpp
r149 r181 1 1 /* 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 2 * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/> 3 * 4 * Copyright (C) 2008 Trinity <http://www.trinitycore.org/> 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License, or 9 * (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, write to the Free Software 18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 */ 20 20 21 21 #include <ace/Message_Block.h> … … 55 55 struct ServerPktHeader 56 56 { 57 ACE_UINT16 size;58 ACE_UINT16 cmd;57 uint16 size; 58 uint16 cmd; 59 59 }; 60 60 61 61 struct ClientPktHeader 62 62 { 63 ACE_UINT16 size;64 ACE_UINT32 cmd;63 uint16 size; 64 uint32 cmd; 65 65 }; 66 66 … … 84 84 m_LastPingTime (ACE_Time_Value::zero) 85 85 { 86 this->reference_counting_policy ().value (ACE_Event_Handler::Reference_Counting_Policy::ENABLED);86 reference_counting_policy ().value (ACE_Event_Handler::Reference_Counting_Policy::ENABLED); 87 87 } 88 88 89 89 WorldSocket::~WorldSocket (void) 90 90 { 91 if (m_RecvWPct) 92 delete m_RecvWPct; 93 94 if (m_OutBuffer) 95 m_OutBuffer->release (); 96 97 this->closing_ = true; 98 99 this->peer ().close (); 100 101 WorldPacket* pct; 102 while (m_PacketQueue.dequeue_head (pct) == 0) 103 delete pct; 104 } 105 106 bool 107 WorldSocket::IsClosed (void) const 108 { 109 return this->closing_; 110 } 111 112 void 113 WorldSocket::CloseSocket (void) 114 { 115 { 116 ACE_GUARD (LockType, Guard, m_OutBufferLock); 117 118 if (this->closing_) 119 return; 120 121 this->closing_ = true; 122 123 this->peer ().close_writer (); 124 } 125 126 { 127 ACE_GUARD (LockType, Guard, m_SessionLock); 128 129 m_Session = NULL; 130 } 131 132 } 133 134 const std::string& 135 WorldSocket::GetRemoteAddress (void) const 136 { 137 return m_Address; 138 } 139 140 int 141 WorldSocket::SendPacket (const WorldPacket& pct) 142 { 143 ACE_GUARD_RETURN (LockType, Guard, m_OutBufferLock, -1); 144 145 if (this->closing_) 146 return -1; 147 148 // Dump outgoing packet. 149 if (sWorldLog.LogWorld ()) 150 { 151 sWorldLog.Log ("SERVER:\nSOCKET: %u\nLENGTH: %u\nOPCODE: %s (0x%.4X)\nDATA:\n", 91 if (m_RecvWPct) 92 delete m_RecvWPct; 93 94 if (m_OutBuffer) 95 m_OutBuffer->release (); 96 97 closing_ = true; 98 99 peer ().close (); 100 101 WorldPacket* pct; 102 while (m_PacketQueue.dequeue_head (pct) == 0) 103 delete pct; 104 } 105 106 bool WorldSocket::IsClosed (void) const 107 { 108 return closing_; 109 } 110 111 void WorldSocket::CloseSocket (void) 112 { 113 { 114 ACE_GUARD (LockType, Guard, m_OutBufferLock); 115 116 if (closing_) 117 return; 118 119 closing_ = true; 120 121 peer ().close_writer (); 122 } 123 124 { 125 ACE_GUARD (LockType, Guard, m_SessionLock); 126 127 m_Session = NULL; 128 } 129 } 130 131 const std::string& WorldSocket::GetRemoteAddress (void) const 132 { 133 return m_Address; 134 } 135 136 int WorldSocket::SendPacket (const WorldPacket& pct) 137 { 138 ACE_GUARD_RETURN (LockType, Guard, m_OutBufferLock, -1); 139 140 if (closing_) 141 return -1; 142 143 // Dump outgoing packet. 144 if (sWorldLog.LogWorld ()) 145 { 146 sWorldLog.Log ("SERVER:\nSOCKET: %u\nLENGTH: %u\nOPCODE: %s (0x%.4X)\nDATA:\n", 152 147 (uint32) get_handle (), 153 148 pct.size (), … … 155 150 pct.GetOpcode ()); 156 151 157 uint32 p = 0; 158 while (p < pct.size ()) 159 { 160 for (uint32 j = 0; j < 16 && p < pct.size (); j++) 161 sWorldLog.Log ("%.2X ", const_cast<WorldPacket&> (pct)[p++]); 162 163 sWorldLog.Log ("\n"); 164 } 165 166 sWorldLog.Log ("\n\n"); 167 } 168 169 if (iSendPacket (pct) == -1) 170 { 171 WorldPacket* npct; 172 173 ACE_NEW_RETURN (npct, WorldPacket (pct), -1); 174 175 // NOTE maybe check of the size of the queue can be good ? 176 // to make it bounded instead of unbounded 177 if (m_PacketQueue.enqueue_tail (npct) == -1) 178 { 179 delete npct; 180 sLog.outError ("WorldSocket::SendPacket: m_PacketQueue.enqueue_tail failed"); 181 return -1; 182 } 183 } 184 185 return 0; 186 } 187 188 long 189 WorldSocket::AddReference (void) 190 { 191 return static_cast<long> (this->add_reference ()); 192 } 193 194 long 195 WorldSocket::RemoveReference (void) 196 { 197 return static_cast<long> (this->remove_reference ()); 198 } 199 200 int 201 WorldSocket::open (void *a) 202 { 203 ACE_UNUSED_ARG (a); 204 205 // Prevent double call to this func. 206 if (m_OutBuffer) 207 return -1; 208 209 // This will also prevent the socket from being Updated 210 // while we are initializing it. 211 m_OutActive = true; 212 213 // Hook for the manager. 214 if (sWorldSocketMgr->OnSocketOpen (this) == -1) 215 return -1; 216 217 // Allocate the buffer. 218 ACE_NEW_RETURN (m_OutBuffer, ACE_Message_Block (m_OutBufferSize), -1); 219 220 // Store peer address. 221 ACE_INET_Addr remote_addr; 222 223 if (this->peer ().get_remote_addr (remote_addr) == -1) 224 { 225 sLog.outError ("WorldSocket::open: peer ().get_remote_addr errno = %s", ACE_OS::strerror (errno)); 226 return -1; 227 } 228 229 m_Address = remote_addr.get_host_addr (); 230 231 // Send startup packet. 232 WorldPacket packet (SMSG_AUTH_CHALLENGE, 4); 233 packet << m_Seed; 234 235 if (SendPacket (packet) == -1) 236 return -1; 237 238 // Register with ACE Reactor 239 if (this->reactor ()->register_handler 240 (this, 241 ACE_Event_Handler::READ_MASK | ACE_Event_Handler::WRITE_MASK) == -1) 242 { 243 sLog.outError ("WorldSocket::open: unable to register client handler errno = %s", ACE_OS::strerror (errno)); 244 return -1; 245 } 246 247 // reactor takes care of the socket from now on 248 this->remove_reference (); 249 250 return 0; 251 } 252 253 int 254 WorldSocket::close (int) 255 { 256 this->shutdown (); 257 258 this->closing_ = true; 259 260 this->remove_reference (); 261 262 return 0; 263 } 264 265 int 266 WorldSocket::handle_input (ACE_HANDLE) 267 { 268 if (this->closing_) 269 return -1; 270 271 switch (this->handle_input_missing_data ()) 272 { 273 case -1 : 274 { 275 if ((errno == EWOULDBLOCK) || 276 (errno == EAGAIN)) 277 { 278 //return 0; 279 return this->Update (); // interesting line ,isnt it ? 280 } 281 282 DEBUG_LOG ("WorldSocket::handle_input: Peer error closing connection errno = %s", ACE_OS::strerror (errno)); 283 284 return -1; 285 } 286 case 0: 287 { 288 DEBUG_LOG ("WorldSocket::handle_input: Peer has closed connection\n"); 289 290 errno = ECONNRESET; 291 292 return -1; 293 } 294 case 1: 295 return 1; 296 } 297 298 //return 0; 299 return this->Update (); // another interesting line ;) 300 } 301 302 int 303 WorldSocket::handle_output (ACE_HANDLE) 304 { 305 ACE_GUARD_RETURN (LockType, Guard, m_OutBufferLock, -1); 306 307 if (this->closing_) 308 return -1; 309 310 const size_t send_len = m_OutBuffer->length (); 311 312 if (send_len == 0) 313 return this->cancel_wakeup_output (Guard); 314 315 // TODO SO_NOSIGPIPE on platforms that support it 152 uint32 p = 0; 153 while (p < pct.size ()) 154 { 155 for (uint32 j = 0; j < 16 && p < pct.size (); j++) 156 sWorldLog.Log ("%.2X ", const_cast<WorldPacket&>(pct)[p++]); 157 158 sWorldLog.Log ("\n"); 159 } 160 161 sWorldLog.Log ("\n\n"); 162 } 163 164 if (iSendPacket (pct) == -1) 165 { 166 WorldPacket* npct; 167 168 ACE_NEW_RETURN (npct, WorldPacket (pct), -1); 169 170 // NOTE maybe check of the size of the queue can be good ? 171 // to make it bounded instead of unbounded 172 if (m_PacketQueue.enqueue_tail (npct) == -1) 173 { 174 delete npct; 175 sLog.outError ("WorldSocket::SendPacket: m_PacketQueue.enqueue_tail failed"); 176 return -1; 177 } 178 } 179 180 return 0; 181 } 182 183 long WorldSocket::AddReference (void) 184 { 185 return static_cast<long> (add_reference ()); 186 } 187 188 long WorldSocket::RemoveReference (void) 189 { 190 return static_cast<long> (remove_reference ()); 191 } 192 193 int WorldSocket::open (void *a) 194 { 195 ACE_UNUSED_ARG (a); 196 197 // Prevent double call to this func. 198 if (m_OutBuffer) 199 return -1; 200 201 // This will also prevent the socket from being Updated 202 // while we are initializing it. 203 m_OutActive = true; 204 205 // Hook for the manager. 206 if (sWorldSocketMgr->OnSocketOpen (this) == -1) 207 return -1; 208 209 // Allocate the buffer. 210 ACE_NEW_RETURN (m_OutBuffer, ACE_Message_Block (m_OutBufferSize), -1); 211 212 // Store peer address. 213 ACE_INET_Addr remote_addr; 214 215 if (peer ().get_remote_addr (remote_addr) == -1) 216 { 217 sLog.outError ("WorldSocket::open: peer ().get_remote_addr errno = %s", ACE_OS::strerror (errno)); 218 return -1; 219 } 220 221 m_Address = remote_addr.get_host_addr (); 222 223 // Send startup packet. 224 WorldPacket packet (SMSG_AUTH_CHALLENGE, 4); 225 packet << m_Seed; 226 227 if (SendPacket (packet) == -1) 228 return -1; 229 230 // Register with ACE Reactor 231 if (reactor ()->register_handler(this, ACE_Event_Handler::READ_MASK | ACE_Event_Handler::WRITE_MASK) == -1) 232 { 233 sLog.outError ("WorldSocket::open: unable to register client handler errno = %s", ACE_OS::strerror (errno)); 234 return -1; 235 } 236 237 // reactor takes care of the socket from now on 238 remove_reference (); 239 240 return 0; 241 } 242 243 int WorldSocket::close (int) 244 { 245 shutdown (); 246 247 closing_ = true; 248 249 remove_reference (); 250 251 return 0; 252 } 253 254 int WorldSocket::handle_input (ACE_HANDLE) 255 { 256 if (closing_) 257 return -1; 258 259 switch (handle_input_missing_data ()) 260 { 261 case -1 : 262 { 263 if ((errno == EWOULDBLOCK) || 264 (errno == EAGAIN)) 265 { 266 return Update (); // interesting line ,isnt it ? 267 } 268 269 DEBUG_LOG ("WorldSocket::handle_input: Peer error closing connection errno = %s", ACE_OS::strerror (errno)); 270 271 errno = ECONNRESET; 272 return -1; 273 } 274 case 0: 275 { 276 DEBUG_LOG ("WorldSocket::handle_input: Peer has closed connection\n"); 277 278 errno = ECONNRESET; 279 return -1; 280 } 281 case 1: 282 return 1; 283 default: 284 return Update (); // another interesting line ;) 285 } 286 287 ACE_NOTREACHED(return -1); 288 } 289 290 int WorldSocket::handle_output (ACE_HANDLE) 291 { 292 ACE_GUARD_RETURN (LockType, Guard, m_OutBufferLock, -1); 293 294 if (closing_) 295 return -1; 296 297 const size_t send_len = m_OutBuffer->length (); 298 299 if (send_len == 0) 300 return cancel_wakeup_output (Guard); 301 316 302 #ifdef MSG_NOSIGNAL 317 ssize_t n = this->peer ().send (m_OutBuffer->rd_ptr (), send_len, MSG_NOSIGNAL);303 ssize_t n = peer ().send (m_OutBuffer->rd_ptr (), send_len, MSG_NOSIGNAL); 318 304 #else 319 ssize_t n = this->peer ().send (m_OutBuffer->rd_ptr (), send_len);305 ssize_t n = peer ().send (m_OutBuffer->rd_ptr (), send_len); 320 306 #endif // MSG_NOSIGNAL 321 307 322 if (n == 0) 323 return -1; 324 else if (n == -1) 325 { 326 if (errno == EWOULDBLOCK || errno == EAGAIN) 327 return this->schedule_wakeup_output (Guard); 328 329 return -1; 330 } 331 else if (n < send_len) //now n > 0 332 { 333 m_OutBuffer->rd_ptr (static_cast<size_t> (n)); 334 335 // move the data to the base of the buffer 336 m_OutBuffer->crunch (); 337 338 return this->schedule_wakeup_output (Guard); 339 } 340 else //now n == send_len 341 { 342 m_OutBuffer->reset (); 343 344 if (!iFlushPacketQueue ()) 345 return this->cancel_wakeup_output (Guard); 346 else 347 return this->schedule_wakeup_output (Guard); 348 } 349 350 ACE_NOTREACHED (return 0); 351 } 352 353 int 354 WorldSocket::handle_close (ACE_HANDLE h, ACE_Reactor_Mask) 355 { 356 // Critical section 357 { 358 ACE_GUARD_RETURN (LockType, Guard, m_OutBufferLock, -1); 359 360 this->closing_ = true; 361 362 if (h == ACE_INVALID_HANDLE) 363 this->peer ().close_writer (); 364 } 365 366 // Critical section 367 { 368 ACE_GUARD_RETURN (LockType, Guard, m_SessionLock, -1); 369 370 m_Session = NULL; 371 } 372 373 return 0; 374 } 375 376 int 377 WorldSocket::Update (void) 378 { 379 if (this->closing_) 380 return -1; 381 382 if (m_OutActive || m_OutBuffer->length () == 0) 308 if (n == 0) 309 return -1; 310 else if (n == -1) 311 { 312 if (errno == EWOULDBLOCK || errno == EAGAIN) 313 return schedule_wakeup_output (Guard); 314 315 return -1; 316 } 317 else if (n < send_len) //now n > 0 318 { 319 m_OutBuffer->rd_ptr (static_cast<size_t> (n)); 320 321 // move the data to the base of the buffer 322 m_OutBuffer->crunch (); 323 324 return schedule_wakeup_output (Guard); 325 } 326 else //now n == send_len 327 { 328 m_OutBuffer->reset (); 329 330 if (!iFlushPacketQueue ()) 331 return cancel_wakeup_output (Guard); 332 else 333 return schedule_wakeup_output (Guard); 334 } 335 336 ACE_NOTREACHED (return 0); 337 } 338 339 int WorldSocket::handle_close (ACE_HANDLE h, ACE_Reactor_Mask) 340 { 341 // Critical section 342 { 343 ACE_GUARD_RETURN (LockType, Guard, m_OutBufferLock, -1); 344 345 closing_ = true; 346 347 if (h == ACE_INVALID_HANDLE) 348 peer ().close_writer (); 349 } 350 351 // Critical section 352 { 353 ACE_GUARD_RETURN (LockType, Guard, m_SessionLock, -1); 354 355 m_Session = NULL; 356 } 357 383 358 return 0; 384 385 return this->handle_output (this->get_handle ()); 386 } 387 388 int 389 WorldSocket::handle_input_header (void) 390 { 391 ACE_ASSERT (m_RecvWPct == NULL); 392 393 if (m_Header.length () != sizeof (ClientPktHeader)) 394 { 395 sLog.outError ("WorldSocket::handle_input_header: internal error: invalid header"); 396 errno = EINVAL; 397 return -1; 398 } 399 400 m_Crypt.DecryptRecv ((ACE_UINT8*) m_Header.rd_ptr (), sizeof (ClientPktHeader)); 401 402 ClientPktHeader& header = *((ClientPktHeader*) m_Header.rd_ptr ()); 403 404 header.size = ACE_NTOHS (header.size); 405 406 #if ACE_BYTE_ORDER == ACE_BIG_ENDIAN 407 header.cmd = ACE_SWAP_LONG (header.cmd) 408 #endif // ACE_BIG_ENDIAN 409 410 if ((header.size < 4) || 411 (header.size > 10240) || 412 (header.cmd <= 0) || 413 (header.cmd > 10240) 414 ) 415 { 416 sLog.outError ("WorldSocket::handle_input_header: client sent mailformed packet size = %d , cmd = %d", 417 header.size, 418 header.cmd); 419 420 errno = EINVAL; 421 return -1; 422 } 423 424 header.size -= 4; 425 426 ACE_NEW_RETURN (m_RecvWPct, WorldPacket ((uint16) header.cmd, header.size), -1); 427 428 if (header.size > 0) 429 { 430 m_RecvWPct->resize (header.size); 431 m_RecvPct.base ((char*) m_RecvWPct->contents (), m_RecvWPct->size ()); 432 } 433 else 434 { 435 ACE_ASSERT (m_RecvPct.space () == 0); 436 } 437 438 439 return 0; 440 } 441 442 int 443 WorldSocket::handle_input_payload (void) 444 { 445 // set errno properly here on error !!! 446 // now have a header and payload 447 448 ACE_ASSERT (m_RecvPct.space () == 0); 449 ACE_ASSERT (m_Header.space () == 0); 450 ACE_ASSERT (m_RecvWPct != NULL); 451 452 const int ret = this->ProcessIncoming (m_RecvWPct); 453 454 m_RecvPct.base (NULL, 0); 455 m_RecvPct.reset (); 456 m_RecvWPct = NULL; 457 458 m_Header.reset (); 459 460 if (ret == -1) 461 errno = EINVAL; 462 463 return ret; 464 } 465 466 int 467 WorldSocket::handle_input_missing_data (void) 468 { 469 char buf [1024]; 470 471 ACE_Data_Block db (sizeof (buf), 472 ACE_Message_Block::MB_DATA, 473 buf, 474 0, 475 0, 476 ACE_Message_Block::DONT_DELETE, 477 0); 478 479 ACE_Message_Block message_block (&db, 480 ACE_Message_Block::DONT_DELETE, 481 0); 482 483 const size_t recv_size = message_block.space (); 484 485 const ssize_t n = this->peer ().recv (message_block.wr_ptr (), 486 recv_size); 487 488 if (n <= 0) 489 return n; 490 491 message_block.wr_ptr (n); 492 493 while (message_block.length () > 0) 494 { 495 if (m_Header.space () > 0) 496 { 497 //need to recieve the header 498 const size_t to_header = (message_block.length () > m_Header.space () ? m_Header.space () : message_block.length ()); 499 m_Header.copy (message_block.rd_ptr (), to_header); 500 message_block.rd_ptr (to_header); 501 502 if (m_Header.space () > 0) 359 } 360 361 int WorldSocket::Update (void) 362 { 363 if (closing_) 364 return -1; 365 366 if (m_OutActive || m_OutBuffer->length () == 0) 367 return 0; 368 369 return handle_output (get_handle ()); 370 } 371 372 int WorldSocket::handle_input_header (void) 373 { 374 ACE_ASSERT (m_RecvWPct == NULL); 375 376 ACE_ASSERT (m_Header.length () == sizeof (ClientPktHeader)); 377 378 m_Crypt.DecryptRecv ((ACE_UINT8*) m_Header.rd_ptr (), sizeof (ClientPktHeader)); 379 380 ClientPktHeader& header = *((ClientPktHeader*) m_Header.rd_ptr ()); 381 382 EndianConvertReverse(header.size); 383 EndianConvert(header.cmd); 384 385 if ((header.size < 4) || (header.size > 10240) || 386 (header.cmd < 0) || (header.cmd > 10240) ) 387 { 388 sLog.outError ("WorldSocket::handle_input_header: client sent mailformed packet size = %d , cmd = %d", 389 header.size, header.cmd); 390 391 errno = EINVAL; 392 return -1; 393 } 394 395 header.size -= 4; 396 397 ACE_NEW_RETURN (m_RecvWPct, WorldPacket ((uint16) header.cmd, header.size), -1); 398 399 if(header.size > 0) 400 { 401 m_RecvWPct->resize (header.size); 402 m_RecvPct.base ((char*) m_RecvWPct->contents (), m_RecvWPct->size ()); 403 } 404 else 405 { 406 ACE_ASSERT(m_RecvPct.space() == 0); 407 } 408 409 return 0; 410 } 411 412 int WorldSocket::handle_input_payload (void) 413 { 414 // set errno properly here on error !!! 415 // now have a header and payload 416 417 ACE_ASSERT (m_RecvPct.space () == 0); 418 ACE_ASSERT (m_Header.space () == 0); 419 ACE_ASSERT (m_RecvWPct != NULL); 420 421 const int ret = ProcessIncoming (m_RecvWPct); 422 423 m_RecvPct.base (NULL, 0); 424 m_RecvPct.reset (); 425 m_RecvWPct = NULL; 426 427 m_Header.reset (); 428 429 if (ret == -1) 430 errno = EINVAL; 431 432 return ret; 433 } 434 435 int WorldSocket::handle_input_missing_data (void) 436 { 437 char buf [1024]; 438 439 ACE_Data_Block db ( sizeof (buf), 440 ACE_Message_Block::MB_DATA, 441 buf, 442 0, 443 0, 444 ACE_Message_Block::DONT_DELETE, 445 0); 446 447 ACE_Message_Block message_block(&db, 448 ACE_Message_Block::DONT_DELETE, 449 0); 450 451 const size_t recv_size = message_block.space (); 452 453 const ssize_t n = peer ().recv (message_block.wr_ptr (), 454 recv_size); 455 456 if (n <= 0) 457 return n; 458 459 message_block.wr_ptr (n); 460 461 while (message_block.length () > 0) 462 { 463 if (m_Header.space () > 0) 464 { 465 //need to recieve the header 466 const size_t to_header = (message_block.length () > m_Header.space () ? m_Header.space () : message_block.length ()); 467 m_Header.copy (message_block.rd_ptr (), to_header); 468 message_block.rd_ptr (to_header); 469 470 if (m_Header.space () > 0) 503 471 { 504 //couldnt recieve the whole header this time505 ACE_ASSERT (message_block.length () == 0);506 errno = EWOULDBLOCK;507 return -1;472 //couldnt recieve the whole header this time 473 ACE_ASSERT (message_block.length () == 0); 474 errno = EWOULDBLOCK; 475 return -1; 508 476 } 509 477 510 478 //we just recieved nice new header 511 if (this->handle_input_header () == -1)479 if (handle_input_header () == -1) 512 480 { 513 ACE_ASSERT ((errno != EWOULDBLOCK) && (errno != EAGAIN));514 return -1;481 ACE_ASSERT ((errno != EWOULDBLOCK) && (errno != EAGAIN)); 482 return -1; 515 483 } 516 484 } 517 485 518 // Its possible on some error situations that this happens519 // for example on closing when epoll recieves more chunked data and stuff520 // hope this is not hack ,as proper m_RecvWPct is asserted around521 if (!m_RecvWPct)522 { 523 sLog.outError ("Forsing close on input m_RecvWPct = NULL");524 errno = EINVAL;525 return -1;526 } 527 528 // We have full readed header, now check the data payload529 if (m_RecvPct.space () > 0)530 { 531 //need more data in the payload532 const size_t to_data = (message_block.length () > m_RecvPct.space () ? m_RecvPct.space () : message_block.length ());533 m_RecvPct.copy (message_block.rd_ptr (), to_data);534 message_block.rd_ptr (to_data);535 536 if (m_RecvPct.space () > 0)486 // Its possible on some error situations that this happens 487 // for example on closing when epoll recieves more chunked data and stuff 488 // hope this is not hack ,as proper m_RecvWPct is asserted around 489 if (!m_RecvWPct) 490 { 491 sLog.outError ("Forsing close on input m_RecvWPct = NULL"); 492 errno = EINVAL; 493 return -1; 494 } 495 496 // We have full readed header, now check the data payload 497 if (m_RecvPct.space () > 0) 498 { 499 //need more data in the payload 500 const size_t to_data = (message_block.length () > m_RecvPct.space () ? m_RecvPct.space () : message_block.length ()); 501 m_RecvPct.copy (message_block.rd_ptr (), to_data); 502 message_block.rd_ptr (to_data); 503 504 if (m_RecvPct.space () > 0) 537 505 { 538 //couldnt recieve the whole data this time539 ACE_ASSERT (message_block.length () == 0);540 errno = EWOULDBLOCK;541 return -1;506 //couldnt recieve the whole data this time 507 ACE_ASSERT (message_block.length () == 0); 508 errno = EWOULDBLOCK; 509 return -1; 542 510 } 543 511 } 544 512 545 //just recieved fresh new payload 546 if (this->handle_input_payload () == -1) 547 { 548 ACE_ASSERT ((errno != EWOULDBLOCK) && (errno != EAGAIN)); 549 return -1; 550 } 551 } 552 553 return n == recv_size ? 1 : 2; 554 } 555 556 int 557 WorldSocket::cancel_wakeup_output (GuardType& g) 558 { 559 if (!m_OutActive) 513 //just recieved fresh new payload 514 if (handle_input_payload () == -1) 515 { 516 ACE_ASSERT ((errno != EWOULDBLOCK) && (errno != EAGAIN)); 517 return -1; 518 } 519 } 520 521 return n == recv_size ? 1 : 2; 522 } 523 524 int WorldSocket::cancel_wakeup_output (GuardType& g) 525 { 526 if (!m_OutActive) 527 return 0; 528 529 m_OutActive = false; 530 531 g.release (); 532 533 if (reactor ()->cancel_wakeup 534 (this, ACE_Event_Handler::WRITE_MASK) == -1) 535 { 536 // would be good to store errno from reactor with errno guard 537 sLog.outError ("WorldSocket::cancel_wakeup_output"); 538 return -1; 539 } 540 560 541 return 0; 561 562 m_OutActive = false; 563 564 g.release (); 565 566 if (this->reactor ()->cancel_wakeup 567 (this, ACE_Event_Handler::WRITE_MASK) == -1) 568 { 569 // would be good to store errno from reactor with errno guard 570 sLog.outError ("WorldSocket::cancel_wakeup_output"); 571 return -1; 572 } 573 574 return 0; 575 } 576 577 int 578 WorldSocket::schedule_wakeup_output (GuardType& g) 579 { 580 if (m_OutActive) 542 } 543 544 int WorldSocket::schedule_wakeup_output (GuardType& g) 545 { 546 if (m_OutActive) 547 return 0; 548 549 m_OutActive = true; 550 551 g.release (); 552 553 if (reactor ()->schedule_wakeup 554 (this, ACE_Event_Handler::WRITE_MASK) == -1) 555 { 556 sLog.outError ("WorldSocket::schedule_wakeup_output"); 557 return -1; 558 } 559 581 560 return 0; 582 583 m_OutActive = true; 584 585 g.release (); 586 587 if (this->reactor ()->schedule_wakeup 588 (this, ACE_Event_Handler::WRITE_MASK) == -1) 589 { 590 sLog.outError ("WorldSocket::schedule_wakeup_output"); 591 return -1; 592 } 593 594 return 0; 595 } 596 597 int 598 WorldSocket::ProcessIncoming (WorldPacket* new_pct) 599 { 600 ACE_ASSERT (new_pct); 601 602 // manage memory ;) 603 ACE_Auto_Ptr<WorldPacket> aptr (new_pct); 604 605 const ACE_UINT16 opcode = new_pct->GetOpcode (); 606 607 if (this->closing_) 608 return -1; 609 610 // dump recieved packet 611 if (sWorldLog.LogWorld ()) 612 { 613 sWorldLog.Log ("CLIENT:\nSOCKET: %u\nLENGTH: %u\nOPCODE: %s (0x%.4X)\nDATA:\n", 561 } 562 563 int WorldSocket::ProcessIncoming (WorldPacket* new_pct) 564 { 565 ACE_ASSERT (new_pct); 566 567 // manage memory ;) 568 ACE_Auto_Ptr<WorldPacket> aptr (new_pct); 569 570 const ACE_UINT16 opcode = new_pct->GetOpcode (); 571 572 if (closing_) 573 return -1; 574 575 // dump recieved packet 576 if (sWorldLog.LogWorld ()) 577 { 578 sWorldLog.Log ("CLIENT:\nSOCKET: %u\nLENGTH: %u\nOPCODE: %s (0x%.4X)\nDATA:\n", 614 579 (uint32) get_handle (), 615 580 new_pct->size (), … … 617 582 new_pct->GetOpcode ()); 618 583 619 uint32 p = 0;620 while (p < new_pct->size ())621 { 622 for (uint32 j = 0; j < 16 && p < new_pct->size (); j++)623 sWorldLog.Log ("%.2X ", (*new_pct)[p++]);624 sWorldLog.Log ("\n");625 } 626 sWorldLog.Log ("\n\n");627 } 628 629 // like one switch ;)630 if (opcode == CMSG_PING)631 { 632 return HandlePing (*new_pct);633 } 634 else if (opcode == CMSG_AUTH_SESSION)635 { 636 if (m_Session)637 { 638 sLog.outError ("WorldSocket::ProcessIncoming: Player send CMSG_AUTH_SESSION again");639 return -1;640 } 641 642 return HandleAuthSession (*new_pct);643 } 644 else if (opcode == CMSG_KEEP_ALIVE)645 { 646 DEBUG_LOG ("CMSG_KEEP_ALIVE ,size: %d", new_pct->size ());647 648 return 0;649 } 650 else651 { 652 ACE_GUARD_RETURN (LockType, Guard, m_SessionLock, -1);653 654 if (m_Session != NULL)655 { 656 // OK ,give the packet to WorldSession657 aptr.release ();658 // WARNINIG here we call it with locks held.659 // Its possible to cause deadlock if QueuePacket calls back660 m_Session->QueuePacket (new_pct);661 return 0;662 } 663 else664 { 665 sLog.outError ("WorldSocket::ProcessIncoming: Client not authed opcode = ", opcode);666 return -1;667 } 668 } 669 670 ACE_NOTREACHED (return 0);671 } 672 673 int 674 WorldSocket::HandleAuthSession (WorldPacket& recvPacket) 675 { 676 uint8 digest[20];677 uint32 clientSeed;678 uint32 unk2;679 uint32 BuiltNumberClient;680 uint32 id, security;681 //uint8 expansion = 0;682 LocaleConstant locale;683 std::string account;684 Sha1Hash sha1;685 BigNumber v, s, g, N, x, I;686 WorldPacket packet, SendAddonPacked;687 688 BigNumber K;689 690 if (recvPacket.size () < (4 + 4 + 1 + 4 + 20))691 { 692 sLog.outError ("WorldSocket::HandleAuthSession: wrong packet size");693 return -1;694 } 695 696 // Read the content of the packet697 recvPacket >> BuiltNumberClient;// for now no use698 recvPacket >> unk2;699 recvPacket >> account;700 701 if (recvPacket.size () < (4 + 4 + (account.size () + 1) + 4 + 20))702 { 703 sLog.outError ("WorldSocket::HandleAuthSession: wrong packet size second check");704 return -1;705 } 706 707 recvPacket >> clientSeed;708 recvPacket.read (digest, 20);709 710 DEBUG_LOG ("WorldSocket::HandleAuthSession: client %u, unk2 %u, account %s, clientseed %u",711 BuiltNumberClient,712 unk2,713 account.c_str (),714 clientSeed);715 716 // Get the account information from the realmd database717 std::string safe_account = account; // Duplicate, else will screw the SHA hash verification below718 loginDatabase.escape_string (safe_account);719 // No SQL injection, username escaped.720 721 QueryResult *result =584 uint32 p = 0; 585 while (p < new_pct->size ()) 586 { 587 for (uint32 j = 0; j < 16 && p < new_pct->size (); j++) 588 sWorldLog.Log ("%.2X ", (*new_pct)[p++]); 589 sWorldLog.Log ("\n"); 590 } 591 sWorldLog.Log ("\n\n"); 592 } 593 594 // like one switch ;) 595 if (opcode == CMSG_PING) 596 { 597 return HandlePing (*new_pct); 598 } 599 else if (opcode == CMSG_AUTH_SESSION) 600 { 601 if (m_Session) 602 { 603 sLog.outError ("WorldSocket::ProcessIncoming: Player send CMSG_AUTH_SESSION again"); 604 return -1; 605 } 606 607 return HandleAuthSession (*new_pct); 608 } 609 else if (opcode == CMSG_KEEP_ALIVE) 610 { 611 DEBUG_LOG ("CMSG_KEEP_ALIVE ,size: %d", new_pct->size ()); 612 613 return 0; 614 } 615 else 616 { 617 ACE_GUARD_RETURN (LockType, Guard, m_SessionLock, -1); 618 619 if (m_Session != NULL) 620 { 621 // OK ,give the packet to WorldSession 622 aptr.release (); 623 // WARNINIG here we call it with locks held. 624 // Its possible to cause deadlock if QueuePacket calls back 625 m_Session->QueuePacket (new_pct); 626 return 0; 627 } 628 else 629 { 630 sLog.outError ("WorldSocket::ProcessIncoming: Client not authed opcode = ", opcode); 631 return -1; 632 } 633 } 634 635 ACE_NOTREACHED (return 0); 636 } 637 638 int WorldSocket::HandleAuthSession (WorldPacket& recvPacket) 639 { 640 // NOTE: ATM the socket is singlethreaded, have this in mind ... 641 uint8 digest[20]; 642 uint32 clientSeed; 643 uint32 unk2; 644 uint32 BuiltNumberClient; 645 uint32 id, security; 646 //uint8 expansion = 0; 647 LocaleConstant locale; 648 std::string account; 649 Sha1Hash sha1; 650 BigNumber v, s, g, N, x, I; 651 WorldPacket packet, SendAddonPacked; 652 653 BigNumber K; 654 655 if (recvPacket.size () < (4 + 4 + 1 + 4 + 20)) 656 { 657 sLog.outError ("WorldSocket::HandleAuthSession: wrong packet size"); 658 return -1; 659 } 660 661 // Read the content of the packet 662 recvPacket >> BuiltNumberClient; // for now no use 663 recvPacket >> unk2; 664 recvPacket >> account; 665 666 if (recvPacket.size () < (4 + 4 + (account.size () + 1) + 4 + 20)) 667 { 668 sLog.outError ("WorldSocket::HandleAuthSession: wrong packet size second check"); 669 return -1; 670 } 671 672 recvPacket >> clientSeed; 673 recvPacket.read (digest, 20); 674 675 DEBUG_LOG ("WorldSocket::HandleAuthSession: client %u, unk2 %u, account %s, clientseed %u", 676 BuiltNumberClient, 677 unk2, 678 account.c_str (), 679 clientSeed); 680 681 // Get the account information from the realmd database 682 std::string safe_account = account; // Duplicate, else will screw the SHA hash verification below 683 loginDatabase.escape_string (safe_account); 684 // No SQL injection, username escaped. 685 686 QueryResult *result = 722 687 loginDatabase.PQuery ("SELECT " 723 688 "id, " //0 … … 736 701 safe_account.c_str ()); 737 702 738 // Stop if the account is not found739 if (!result)740 { 741 packet.Initialize (SMSG_AUTH_RESPONSE, 1);742 packet << uint8 (AUTH_UNKNOWN_ACCOUNT);743 744 SendPacket (packet);745 746 sLog.outError ("WorldSocket::HandleAuthSession: Sent Auth Response (unknown account).");747 return -1;748 } 749 750 Field* fields = result->Fetch ();703 // Stop if the account is not found 704 if (!result) 705 { 706 packet.Initialize (SMSG_AUTH_RESPONSE, 1); 707 packet << uint8 (AUTH_UNKNOWN_ACCOUNT); 708 709 SendPacket (packet); 710 711 sLog.outError ("WorldSocket::HandleAuthSession: Sent Auth Response (unknown account)."); 712 return -1; 713 } 714 715 Field* fields = result->Fetch (); 751 716 752 717 uint8 expansion = fields[8].GetUInt8(); … … 755 720 expansion = world_expansion; 756 721 757 N.SetHexStr ("894B645E89E1535BBDAD5B8B290650530801B18EBFBF5E8FAB3C82872A3E9BB7"); 758 g.SetDword (7); 759 I.SetHexStr (fields[5].GetString ()); 760 761 //In case of leading zeros in the I hash, restore them 762 uint8 mDigest[SHA_DIGEST_LENGTH]; 763 memset (mDigest, 0, SHA_DIGEST_LENGTH); 764 765 if (I.GetNumBytes () <= SHA_DIGEST_LENGTH) 766 memcpy (mDigest, I.AsByteArray (), I.GetNumBytes ()); 767 768 std::reverse (mDigest, mDigest + SHA_DIGEST_LENGTH); 769 770 s.SetHexStr (fields[7].GetString ()); 771 sha1.UpdateData (s.AsByteArray (), s.GetNumBytes ()); 772 sha1.UpdateData (mDigest, SHA_DIGEST_LENGTH); 773 sha1.Finalize (); 774 x.SetBinary (sha1.GetDigest (), sha1.GetLength ()); 775 v = g.ModExp (x, N); 776 777 const char* sStr = s.AsHexStr (); //Must be freed by OPENSSL_free() 778 const char* vStr = v.AsHexStr (); //Must be freed by OPENSSL_free() 779 const char* vold = fields[6].GetString (); 780 781 DEBUG_LOG ("WorldSocket::HandleAuthSession: " 782 "(s,v) check s: %s v_old: %s v_new: %s", 783 sStr, 784 vold, 785 vStr); 786 787 loginDatabase.PExecute ("UPDATE account " 788 "SET " 789 "v = '0', " 790 "s = '0' " 791 "WHERE username = '%s'", 792 safe_account.c_str ()); 793 794 if (!vold || strcmp (vStr, vold)) 795 { 796 packet.Initialize (SMSG_AUTH_RESPONSE, 1); 797 packet << uint8 (AUTH_UNKNOWN_ACCOUNT); 798 SendPacket (packet); 799 delete result; 800 OPENSSL_free ((void*) sStr); 801 OPENSSL_free ((void*) vStr); 802 803 sLog.outBasic ("WorldSocket::HandleAuthSession: User not logged."); 804 return -1; 805 } 806 807 OPENSSL_free ((void*) sStr); 808 OPENSSL_free ((void*) vStr); 809 810 ///- Re-check ip locking (same check as in realmd). 811 if (fields[4].GetUInt8 () == 1) // if ip is locked 812 { 813 if (strcmp (fields[3].GetString (), GetRemoteAddress ().c_str ())) 814 { 815 packet.Initialize (SMSG_AUTH_RESPONSE, 1); 816 packet << uint8 (AUTH_FAILED); 817 SendPacket (packet); 818 819 delete result; 820 sLog.outBasic ("WorldSocket::HandleAuthSession: Sent Auth Response (Account IP differs)."); 821 return -1; 822 } 823 } 824 825 id = fields[0].GetUInt32 (); 826 security = fields[1].GetUInt16 (); 827 K.SetHexStr (fields[2].GetString ()); 828 829 time_t mutetime = time_t (fields[9].GetUInt64 ()); 830 831 locale = LocaleConstant (fields[10].GetUInt8 ()); 832 if (locale >= MAX_LOCALE) 833 locale = LOCALE_enUS; 834 835 delete result; 836 837 // Re-check account ban (same check as in realmd) 838 QueryResult *banresult = 722 N.SetHexStr ("894B645E89E1535BBDAD5B8B290650530801B18EBFBF5E8FAB3C82872A3E9BB7"); 723 g.SetDword (7); 724 I.SetHexStr (fields[5].GetString ()); 725 726 //In case of leading zeros in the I hash, restore them 727 uint8 mDigest[SHA_DIGEST_LENGTH]; 728 memset (mDigest, 0, SHA_DIGEST_LENGTH); 729 730 if (I.GetNumBytes () <= SHA_DIGEST_LENGTH) 731 memcpy (mDigest, I.AsByteArray (), I.GetNumBytes ()); 732 733 std::reverse (mDigest, mDigest + SHA_DIGEST_LENGTH); 734 735 s.SetHexStr (fields[7].GetString ()); 736 sha1.UpdateData (s.AsByteArray (), s.GetNumBytes ()); 737 sha1.UpdateData (mDigest, SHA_DIGEST_LENGTH); 738 sha1.Finalize (); 739 x.SetBinary (sha1.GetDigest (), sha1.GetLength ()); 740 v = g.ModExp (x, N); 741 742 const char* sStr = s.AsHexStr (); //Must be freed by OPENSSL_free() 743 const char* vStr = v.AsHexStr (); //Must be freed by OPENSSL_free() 744 const char* vold = fields[6].GetString (); 745 746 DEBUG_LOG ("WorldSocket::HandleAuthSession: (s,v) check s: %s v_old: %s v_new: %s", 747 sStr, 748 vold, 749 vStr); 750 751 loginDatabase.PExecute ("UPDATE account " 752 "SET " 753 "v = '0', " 754 "s = '0' " 755 "WHERE username = '%s'", 756 safe_account.c_str ()); 757 758 if (!vold || strcmp (vStr, vold)) 759 { 760 packet.Initialize (SMSG_AUTH_RESPONSE, 1); 761 packet << uint8 (AUTH_UNKNOWN_ACCOUNT); 762 SendPacket (packet); 763 delete result; 764 OPENSSL_free ((void*) sStr); 765 OPENSSL_free ((void*) vStr); 766 767 sLog.outBasic ("WorldSocket::HandleAuthSession: User not logged."); 768 return -1; 769 } 770 771 OPENSSL_free ((void*) sStr); 772 OPENSSL_free ((void*) vStr); 773 774 ///- Re-check ip locking (same check as in realmd). 775 if (fields[4].GetUInt8 () == 1) // if ip is locked 776 { 777 if (strcmp (fields[3].GetString (), GetRemoteAddress ().c_str ())) 778 { 779 packet.Initialize (SMSG_AUTH_RESPONSE, 1); 780 packet << uint8 (AUTH_FAILED); 781 SendPacket (packet); 782 783 delete result; 784 sLog.outBasic ("WorldSocket::HandleAuthSession: Sent Auth Response (Account IP differs)."); 785 return -1; 786 } 787 } 788 789 id = fields[0].GetUInt32 (); 790 security = fields[1].GetUInt16 (); 791 K.SetHexStr (fields[2].GetString ()); 792 793 time_t mutetime = time_t (fields[9].GetUInt64 ()); 794 795 locale = LocaleConstant (fields[10].GetUInt8 ()); 796 if (locale >= MAX_LOCALE) 797 locale = LOCALE_enUS; 798 799 delete result; 800 801 // Re-check account ban (same check as in realmd) 802 QueryResult *banresult = 839 803 loginDatabase.PQuery ("SELECT " 840 804 "bandate, " … … 845 809 id); 846 810 847 if (banresult) // if account banned 848 { 849 packet.Initialize (SMSG_AUTH_RESPONSE, 1); 850 packet << uint8 (AUTH_BANNED); 851 SendPacket (packet); 852 853 delete banresult; 854 855 sLog.outBasic ("WorldSocket::HandleAuthSession: Sent Auth Response (Account banned)."); 856 return -1; 857 } 858 859 // Check locked state for server 860 AccountTypes allowedAccountType = sWorld.GetPlayerSecurityLimit (); 861 862 if (allowedAccountType > SEC_PLAYER && security < allowedAccountType) 863 { 864 WorldPacket Packet (SMSG_AUTH_RESPONSE, 1); 865 Packet << uint8 (AUTH_UNAVAILABLE); 866 867 SendPacket (packet); 868 869 sLog.outBasic ("WorldSocket::HandleAuthSession: User tryes to login but his security level is not enough"); 870 return -1; 871 } 872 873 // Check that Key and account name are the same on client and server 874 Sha1Hash sha; 875 876 uint32 t = 0; 877 uint32 seed = m_Seed; 878 879 sha.UpdateData (account); 880 sha.UpdateData ((uint8 *) & t, 4); 881 sha.UpdateData ((uint8 *) & clientSeed, 4); 882 sha.UpdateData ((uint8 *) & seed, 4); 883 sha.UpdateBigNumbers (&K, NULL); 884 sha.Finalize (); 885 886 if (memcmp (sha.GetDigest (), digest, 20)) 887 { 888 packet.Initialize (SMSG_AUTH_RESPONSE, 1); 889 packet << uint8 (AUTH_FAILED); 890 891 SendPacket (packet); 892 893 sLog.outBasic ("WorldSocket::HandleAuthSession: Sent Auth Response (authentification failed)."); 894 return -1; 895 } 896 897 std::string address = this->GetRemoteAddress (); 898 899 DEBUG_LOG ("WorldSocket::HandleAuthSession: Client '%s' authenticated successfully from %s.", 900 account.c_str (), 901 address.c_str ()); 902 903 // Update the last_ip in the database 904 // No SQL injection, username escaped. 905 loginDatabase.escape_string (address); 906 907 loginDatabase.PExecute ("UPDATE account " 908 "SET last_ip = '%s' " 909 "WHERE username = '%s'", 910 address.c_str (), 911 safe_account.c_str ()); 912 913 // TODO protect here probably ? 914 // Althought atm the socket is singlethreaded 915 ACE_NEW_RETURN (m_Session, WorldSession (id, this, security, expansion, mutetime, locale), -1); 916 917 m_Crypt.SetKey (&K); 918 m_Crypt.Init (); 919 920 // In case needed sometime the second arg is in microseconds 1 000 000 = 1 sec 921 ACE_OS::sleep (ACE_Time_Value (0, 10000)); 922 923 // TODO error handling 924 sWorld.AddSession (this->m_Session); 925 926 // Create and send the Addon packet 927 if (sAddOnHandler.BuildAddonPacket (&recvPacket, &SendAddonPacked)) 928 SendPacket (SendAddonPacked); 929 930 return 0; 931 } 932 933 int 934 WorldSocket::HandlePing (WorldPacket& recvPacket) 935 { 936 uint32 ping; 937 uint32 latency; 938 939 if (recvPacket.size () < 8) 940 { 941 sLog.outError ("WorldSocket::_HandlePing wrong packet size"); 942 return -1; 943 } 944 945 // Get the ping packet content 946 recvPacket >> ping; 947 recvPacket >> latency; 948 949 if (m_LastPingTime == ACE_Time_Value::zero) 950 m_LastPingTime = ACE_OS::gettimeofday (); // for 1st ping 951 else 952 { 953 ACE_Time_Value cur_time = ACE_OS::gettimeofday (); 954 ACE_Time_Value diff_time (cur_time); 955 diff_time -= m_LastPingTime; 956 m_LastPingTime = cur_time; 957 958 if (diff_time < ACE_Time_Value (27)) 959 { 960 ++m_OverSpeedPings; 961 962 uint32 max_count = sWorld.getConfig (CONFIG_MAX_OVERSPEED_PINGS); 963 964 if (max_count && m_OverSpeedPings > max_count) 811 if (banresult) // if account banned 812 { 813 packet.Initialize (SMSG_AUTH_RESPONSE, 1); 814 packet << uint8 (AUTH_BANNED); 815 SendPacket (packet); 816 817 delete banresult; 818 819 sLog.outError ("WorldSocket::HandleAuthSession: Sent Auth Response (Account banned)."); 820 return -1; 821 } 822 823 // Check locked state for server 824 AccountTypes allowedAccountType = sWorld.GetPlayerSecurityLimit (); 825 826 if (allowedAccountType > SEC_PLAYER && security < allowedAccountType) 827 { 828 WorldPacket Packet (SMSG_AUTH_RESPONSE, 1); 829 Packet << uint8 (AUTH_UNAVAILABLE); 830 831 SendPacket (packet); 832 833 sLog.outBasic ("WorldSocket::HandleAuthSession: User tryes to login but his security level is not enough"); 834 return -1; 835 } 836 837 // Check that Key and account name are the same on client and server 838 Sha1Hash sha; 839 840 uint32 t = 0; 841 uint32 seed = m_Seed; 842 843 sha.UpdateData (account); 844 sha.UpdateData ((uint8 *) & t, 4); 845 sha.UpdateData ((uint8 *) & clientSeed, 4); 846 sha.UpdateData ((uint8 *) & seed, 4); 847 sha.UpdateBigNumbers (&K, NULL); 848 sha.Finalize (); 849 850 if (memcmp (sha.GetDigest (), digest, 20)) 851 { 852 packet.Initialize (SMSG_AUTH_RESPONSE, 1); 853 packet << uint8 (AUTH_FAILED); 854 855 SendPacket (packet); 856 857 sLog.outError ("WorldSocket::HandleAuthSession: Sent Auth Response (authentification failed)."); 858 return -1; 859 } 860 861 std::string address = GetRemoteAddress (); 862 863 DEBUG_LOG ("WorldSocket::HandleAuthSession: Client '%s' authenticated successfully from %s.", 864 account.c_str (), 865 address.c_str ()); 866 867 // Update the last_ip in the database 868 // No SQL injection, username escaped. 869 loginDatabase.escape_string (address); 870 871 loginDatabase.PExecute ("UPDATE account " 872 "SET last_ip = '%s' " 873 "WHERE username = '%s'", 874 address.c_str (), 875 safe_account.c_str ()); 876 877 // NOTE ATM the socket is singlethreaded, have this in mind ... 878 ACE_NEW_RETURN (m_Session, WorldSession (id, this, security, expansion, mutetime, locale), -1); 879 880 m_Crypt.SetKey (&K); 881 m_Crypt.Init (); 882 883 // In case needed sometime the second arg is in microseconds 1 000 000 = 1 sec 884 ACE_OS::sleep (ACE_Time_Value (0, 10000)); 885 886 sWorld.AddSession (m_Session); 887 888 // Create and send the Addon packet 889 if (sAddOnHandler.BuildAddonPacket (&recvPacket, &SendAddonPacked)) 890 SendPacket (SendAddonPacked); 891 892 return 0; 893 } 894 895 int WorldSocket::HandlePing (WorldPacket& recvPacket) 896 { 897 uint32 ping; 898 uint32 latency; 899 900 if (recvPacket.size () < 8) 901 { 902 sLog.outError ("WorldSocket::_HandlePing wrong packet size"); 903 return -1; 904 } 905 906 // Get the ping packet content 907 recvPacket >> ping; 908 recvPacket >> latency; 909 910 if (m_LastPingTime == ACE_Time_Value::zero) 911 m_LastPingTime = ACE_OS::gettimeofday (); // for 1st ping 912 else 913 { 914 ACE_Time_Value cur_time = ACE_OS::gettimeofday (); 915 ACE_Time_Value diff_time (cur_time); 916 diff_time -= m_LastPingTime; 917 m_LastPingTime = cur_time; 918 919 if (diff_time < ACE_Time_Value (27)) 920 { 921 ++m_OverSpeedPings; 922 923 uint32 max_count = sWorld.getConfig (CONFIG_MAX_OVERSPEED_PINGS); 924 925 if (max_count && m_OverSpeedPings > max_count) 965 926 { 966 ACE_GUARD_RETURN (LockType, Guard, m_SessionLock, -1);967 968 if (m_Session && m_Session->GetSecurity () == SEC_PLAYER)927 ACE_GUARD_RETURN (LockType, Guard, m_SessionLock, -1); 928 929 if (m_Session && m_Session->GetSecurity () == SEC_PLAYER) 969 930 { 970 sLog.outError("WorldSocket::HandlePing: Player kicked for "971 "overspeeded pings adress = %s",972 GetRemoteAddress ().c_str ());973 974 return -1;931 sLog.outError ("WorldSocket::HandlePing: Player kicked for " 932 "overspeeded pings adress = %s", 933 GetRemoteAddress ().c_str ()); 934 935 return -1; 975 936 } 976 937 } 977 938 } 978 else 979 m_OverSpeedPings = 0; 980 } 981 982 // critical section 983 { 984 ACE_GUARD_RETURN (LockType, Guard, m_SessionLock, -1); 985 986 if (m_Session) 987 m_Session->SetLatency (latency); 988 else 989 { 990 sLog.outError ("WorldSocket::HandlePing: peer sent CMSG_PING, " 991 "but is not authenticated or got recently kicked," 992 " adress = %s", 993 this->GetRemoteAddress ().c_str ()); 994 return -1; 995 } 996 } 997 998 WorldPacket packet (SMSG_PONG, 4); 999 packet << ping; 1000 return this->SendPacket (packet); 1001 } 1002 1003 int 1004 WorldSocket::iSendPacket (const WorldPacket& pct) 1005 { 1006 if (m_OutBuffer->space () < pct.size () + sizeof (ServerPktHeader)) 1007 { 1008 errno = ENOBUFS; 1009 return -1; 1010 } 1011 1012 ServerPktHeader header; 1013 1014 header.cmd = pct.GetOpcode (); 1015 1016 #if ACE_BYTE_ORDER == ACE_BIG_ENDIAN 1017 header.cmd = ACE_SWAP_WORD (header.cmd) 1018 #endif 1019 1020 header.size = (uint16) pct.size () + 2; 1021 header.size = ACE_HTONS (header.size); 1022 1023 m_Crypt.EncryptSend ((uint8*) & header, sizeof (header)); 1024 1025 if (m_OutBuffer->copy ((char*) & header, sizeof (header)) == -1) 1026 ACE_ASSERT (false); 1027 1028 if (!pct.empty ()) 1029 if (m_OutBuffer->copy ((char*) pct.contents (), pct.size ()) == -1) 1030 ACE_ASSERT (false); 1031 1032 return 0; 1033 } 1034 1035 bool 1036 WorldSocket::iFlushPacketQueue () 1037 { 1038 WorldPacket *pct; 1039 bool haveone = false; 1040 1041 while (m_PacketQueue.dequeue_head (pct) == 0) 1042 { 1043 if (iSendPacket (*pct) == -1) 1044 { 1045 if (m_PacketQueue.enqueue_head (pct) == -1) 939 else 940 m_OverSpeedPings = 0; 941 } 942 943 // critical section 944 { 945 ACE_GUARD_RETURN (LockType, Guard, m_SessionLock, -1); 946 947 if (m_Session) 948 m_Session->SetLatency (latency); 949 else 950 { 951 sLog.outError ("WorldSocket::HandlePing: peer sent CMSG_PING, " 952 "but is not authenticated or got recently kicked," 953 " adress = %s", 954 GetRemoteAddress ().c_str ()); 955 return -1; 956 } 957 } 958 959 WorldPacket packet (SMSG_PONG, 4); 960 packet << ping; 961 return SendPacket (packet); 962 } 963 964 int WorldSocket::iSendPacket (const WorldPacket& pct) 965 { 966 if (m_OutBuffer->space () < pct.size () + sizeof (ServerPktHeader)) 967 { 968 errno = ENOBUFS; 969 return -1; 970 } 971 972 ServerPktHeader header; 973 974 header.cmd = pct.GetOpcode (); 975 EndianConvert(header.cmd); 976 977 header.size = (uint16) pct.size () + 2; 978 EndianConvertReverse(header.size); 979 980 m_Crypt.EncryptSend ((uint8*) & header, sizeof (header)); 981 982 if (m_OutBuffer->copy ((char*) & header, sizeof (header)) == -1) 983 ACE_ASSERT (false); 984 985 if (!pct.empty ()) 986 if (m_OutBuffer->copy ((char*) pct.contents (), pct.size ()) == -1) 987 ACE_ASSERT (false); 988 989 return 0; 990 } 991 992 bool WorldSocket::iFlushPacketQueue () 993 { 994 WorldPacket *pct; 995 bool haveone = false; 996 997 while (m_PacketQueue.dequeue_head (pct) == 0) 998 { 999 if (iSendPacket (*pct) == -1) 1000 { 1001 if (m_PacketQueue.enqueue_head (pct) == -1) 1046 1002 { 1047 delete pct;1048 sLog.outError ("WorldSocket::iFlushPacketQueue m_PacketQueue->enqueue_head");1049 return false;1003 delete pct; 1004 sLog.outError ("WorldSocket::iFlushPacketQueue m_PacketQueue->enqueue_head"); 1005 return false; 1050 1006 } 1051 1007 1052 break;1053 } 1054 else1055 { 1056 haveone = true;1057 delete pct;1058 } 1059 } 1060 1061 return haveone;1062 } 1008 break; 1009 } 1010 else 1011 { 1012 haveone = true; 1013 delete pct; 1014 } 1015 } 1016 1017 return haveone; 1018 } -
trunk/src/game/WorldSocket.h
r102 r181 11 11 * This program is distributed in the hope that it will be useful, 12 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 14 * GNU General Public License for more details. 15 15 * 16 16 * You should have received a copy of the GNU General Public License 17 17 * along with this program; if not, write to the Free Software 18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307USA18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 19 */ 20 20 … … 26 26 27 27 #ifndef _WORLDSOCKET_H 28 #define 28 #define _WORLDSOCKET_H 29 29 30 30 #include <ace/Basic_Types.h> … … 44 44 45 45 #include "Common.h" 46 #include "Auth/AuthCrypt.h" 46 #include "Auth/AuthCrypt.h" 47 47 48 48 class ACE_Message_Block; … … 55 55 /** 56 56 * WorldSocket. 57 * 58 * This class is responsible for the comunication with 57 * 58 * This class is responsible for the comunication with 59 59 * remote clients. 60 * Most methods return -1 on failure. 60 * Most methods return -1 on failure. 61 61 * The class uses refferece counting. 62 62 * 63 * For output the class uses one buffer (64K usually) and 64 * a queue where it stores packet if there is no place on 65 * the queue. The reason this is done, is because the server 66 * does realy a lot of small-size writes to it, and it doesn't 67 * scale well to allocate memory for every. When something is 68 * writen to the output buffer the socket is not immideately 69 * activated for output (again for the same reason), there 70 * is 10ms celling (thats why there is Update() method). 71 * This concept is simmilar to TCP_CORK, but TCP_CORK 72 * usses 200ms celling. As result overhead generated by 73 * sending packets from "producer" threads is minimal, 63 * For output the class uses one buffer (64K usually) and 64 * a queue where it stores packet if there is no place on 65 * the queue. The reason this is done, is because the server 66 * does realy a lot of small-size writes to it, and it doesn't 67 * scale well to allocate memory for every. When something is 68 * writen to the output buffer the socket is not immideately 69 * activated for output (again for the same reason), there 70 * is 10ms celling (thats why there is Update() method). 71 * This concept is simmilar to TCP_CORK, but TCP_CORK 72 * usses 200ms celling. As result overhead generated by 73 * sending packets from "producer" threads is minimal, 74 74 * and doing a lot of writes with small size is tollerated. 75 * 75 * 76 76 * The calls to Upate () method are managed by WorldSocketMgr 77 77 * and ReactorRunnable. 78 * 79 * For input ,the class uses one 1024 bytes buffer on stack 80 * to which it does recv() calls. And then recieved data is 81 * distributed where its needed. 1024 matches pritey well the 78 * 79 * For input ,the class uses one 1024 bytes buffer on stack 80 * to which it does recv() calls. And then recieved data is 81 * distributed where its needed. 1024 matches pritey well the 82 82 * traffic generated by client for now. 83 * 84 * The input/output do speculative reads/writes (AKA it tryes 85 * to read all data avaible in the kernel buffer or tryes to 86 * write everything avaible in userspace buffer), 87 * which is ok for using with Level and Edge Trigered IO 83 * 84 * The input/output do speculative reads/writes (AKA it tryes 85 * to read all data avaible in the kernel buffer or tryes to 86 * write everything avaible in userspace buffer), 87 * which is ok for using with Level and Edge Trigered IO 88 88 * notification. 89 * 89 * 90 90 */ 91 91 class WorldSocket : protected WorldHandler 92 92 { 93 public:94 /// Declare some friends95 friend class ACE_Acceptor< WorldSocket, ACE_SOCK_ACCEPTOR >;96 friend class WorldSocketMgr;97 friend class ReactorRunnable;98 99 /// Declare the acceptor for this class100 typedef ACE_Acceptor< WorldSocket, ACE_SOCK_ACCEPTOR > Acceptor;101 102 /// Mutex type used for various syncronizations.103 typedef ACE_Thread_Mutex LockType;104 typedef ACE_Guard<LockType> GuardType;105 106 /// Queue for storing packets for which there is no space.107 typedef ACE_Unbounded_Queue< WorldPacket* > PacketQueueT;108 109 /// Check if socket is closed.110 bool IsClosed (void) const;111 112 /// Close the socket.113 void CloseSocket (void);114 115 /// Get address of connected peer.116 const std::string& GetRemoteAddress (void) const;117 118 /// Send A packet on the socket, this function is reentrant.119 /// @param pct packet to send120 /// @return -1 of failure121 int SendPacket (const WorldPacket& pct);122 123 /// Add refference to this object.124 long AddReference (void);125 126 /// Remove refference to this object.127 long RemoveReference (void);128 129 protected:130 /// things called by ACE framework.131 WorldSocket (void);132 virtual ~WorldSocket (void);133 134 /// Called on open ,the void* is the acceptor.135 virtual int open (void *);136 137 /// Called on failures inside of the acceptor, don't call from your code.138 virtual int close (int);139 140 /// Called when we can read from the socket.141 virtual int handle_input (ACE_HANDLE = ACE_INVALID_HANDLE);142 143 /// Called when the socket can write.144 virtual int handle_output (ACE_HANDLE = ACE_INVALID_HANDLE);145 146 /// Called when connection is closed or error happens.147 virtual int handle_close (ACE_HANDLE = ACE_INVALID_HANDLE,148 149 150 /// Called by WorldSocketMgr/ReactorRunnable.151 int Update (void);152 153 private:154 /// Helper functions for processing incoming data.155 int handle_input_header (void);156 int handle_input_payload (void);157 int handle_input_missing_data (void);158 159 /// Help functions to mark/unmark the socket for output.160 /// @param g the guard is for m_OutBufferLock, the function will release it161 int cancel_wakeup_output (GuardType& g);162 int schedule_wakeup_output (GuardType& g);163 164 /// process one incoming packet.165 /// @param new_pct received packet ,note that you need to delete it.166 int ProcessIncoming (WorldPacket* new_pct);167 168 /// Called by ProcessIncoming() on CMSG_AUTH_SESSION.169 int HandleAuthSession (WorldPacket& recvPacket);170 171 /// Called by ProcessIncoming() on CMSG_PING.172 int HandlePing (WorldPacket& recvPacket);173 174 /// Try to write WorldPacket to m_OutBuffer ,return -1 if no space175 /// Need to be called with m_OutBufferLock lock held176 int iSendPacket (const WorldPacket& pct);177 178 /// Flush m_PacketQueue if there are packets in it179 /// Need to be called with m_OutBufferLock lock held180 /// @return true if it wrote to the buffer ( AKA you need181 /// to mark the socket for output ).182 bool iFlushPacketQueue ();183 184 private:185 /// Time in which the last ping was received186 ACE_Time_Value m_LastPingTime;187 188 /// Keep track of overspeed pings ,to prevent ping flood.189 uint32 m_OverSpeedPings;190 191 /// Address of the remote peer192 std::string m_Address;193 194 /// Class used for managing encryption of the headers195 AuthCrypt m_Crypt;196 197 /// Mutex lock to protect m_Session198 LockType m_SessionLock;199 200 /// Session to which recieved packets are routed201 WorldSession* m_Session;202 203 /// here are stored the fragmens of the recieved data204 WorldPacket* m_RecvWPct;205 206 /// This block actually refers to m_RecvWPct contents,207 /// which alows easy and safe writing to it.208 /// It wont free memory when its deleted. m_RecvWPct takes care of freeing.209 ACE_Message_Block m_RecvPct;210 211 /// Fragment of the recieved header.212 ACE_Message_Block m_Header;213 214 /// Mutex for protecting otuput related data.215 LockType m_OutBufferLock;216 217 /// Buffer used for writing output.218 ACE_Message_Block *m_OutBuffer;219 220 /// Size of the m_OutBuffer.221 size_t m_OutBufferSize;222 223 /// Here are stored packets for which there was no space on m_OutBuffer,224 /// this alows not-to kick player if its buffer is overflowed.225 PacketQueueT m_PacketQueue;226 227 /// True if the socket is registered with the reactor for output228 bool m_OutActive;229 230 uint32 m_Seed;93 public: 94 /// Declare some friends 95 friend class ACE_Acceptor< WorldSocket, ACE_SOCK_ACCEPTOR >; 96 friend class WorldSocketMgr; 97 friend class ReactorRunnable; 98 99 /// Declare the acceptor for this class 100 typedef ACE_Acceptor< WorldSocket, ACE_SOCK_ACCEPTOR > Acceptor; 101 102 /// Mutex type used for various syncronizations. 103 typedef ACE_Thread_Mutex LockType; 104 typedef ACE_Guard<LockType> GuardType; 105 106 /// Queue for storing packets for which there is no space. 107 typedef ACE_Unbounded_Queue< WorldPacket* > PacketQueueT; 108 109 /// Check if socket is closed. 110 bool IsClosed (void) const; 111 112 /// Close the socket. 113 void CloseSocket (void); 114 115 /// Get address of connected peer. 116 const std::string& GetRemoteAddress (void) const; 117 118 /// Send A packet on the socket, this function is reentrant. 119 /// @param pct packet to send 120 /// @return -1 of failure 121 int SendPacket (const WorldPacket& pct); 122 123 /// Add refference to this object. 124 long AddReference (void); 125 126 /// Remove refference to this object. 127 long RemoveReference (void); 128 129 protected: 130 /// things called by ACE framework. 131 WorldSocket (void); 132 virtual ~WorldSocket (void); 133 134 /// Called on open ,the void* is the acceptor. 135 virtual int open (void *); 136 137 /// Called on failures inside of the acceptor, don't call from your code. 138 virtual int close (int); 139 140 /// Called when we can read from the socket. 141 virtual int handle_input (ACE_HANDLE = ACE_INVALID_HANDLE); 142 143 /// Called when the socket can write. 144 virtual int handle_output (ACE_HANDLE = ACE_INVALID_HANDLE); 145 146 /// Called when connection is closed or error happens. 147 virtual int handle_close (ACE_HANDLE = ACE_INVALID_HANDLE, 148 ACE_Reactor_Mask = ACE_Event_Handler::ALL_EVENTS_MASK); 149 150 /// Called by WorldSocketMgr/ReactorRunnable. 151 int Update (void); 152 153 private: 154 /// Helper functions for processing incoming data. 155 int handle_input_header (void); 156 int handle_input_payload (void); 157 int handle_input_missing_data (void); 158 159 /// Help functions to mark/unmark the socket for output. 160 /// @param g the guard is for m_OutBufferLock, the function will release it 161 int cancel_wakeup_output (GuardType& g); 162 int schedule_wakeup_output (GuardType& g); 163 164 /// process one incoming packet. 165 /// @param new_pct received packet ,note that you need to delete it. 166 int ProcessIncoming (WorldPacket* new_pct); 167 168 /// Called by ProcessIncoming() on CMSG_AUTH_SESSION. 169 int HandleAuthSession (WorldPacket& recvPacket); 170 171 /// Called by ProcessIncoming() on CMSG_PING. 172 int HandlePing (WorldPacket& recvPacket); 173 174 /// Try to write WorldPacket to m_OutBuffer ,return -1 if no space 175 /// Need to be called with m_OutBufferLock lock held 176 int iSendPacket (const WorldPacket& pct); 177 178 /// Flush m_PacketQueue if there are packets in it 179 /// Need to be called with m_OutBufferLock lock held 180 /// @return true if it wrote to the buffer ( AKA you need 181 /// to mark the socket for output ). 182 bool iFlushPacketQueue (); 183 184 private: 185 /// Time in which the last ping was received 186 ACE_Time_Value m_LastPingTime; 187 188 /// Keep track of overspeed pings ,to prevent ping flood. 189 uint32 m_OverSpeedPings; 190 191 /// Address of the remote peer 192 std::string m_Address; 193 194 /// Class used for managing encryption of the headers 195 AuthCrypt m_Crypt; 196 197 /// Mutex lock to protect m_Session 198 LockType m_SessionLock; 199 200 /// Session to which recieved packets are routed 201 WorldSession* m_Session; 202 203 /// here are stored the fragmens of the recieved data 204 WorldPacket* m_RecvWPct; 205 206 /// This block actually refers to m_RecvWPct contents, 207 /// which alows easy and safe writing to it. 208 /// It wont free memory when its deleted. m_RecvWPct takes care of freeing. 209 ACE_Message_Block m_RecvPct; 210 211 /// Fragment of the recieved header. 212 ACE_Message_Block m_Header; 213 214 /// Mutex for protecting otuput related data. 215 LockType m_OutBufferLock; 216 217 /// Buffer used for writing output. 218 ACE_Message_Block *m_OutBuffer; 219 220 /// Size of the m_OutBuffer. 221 size_t m_OutBufferSize; 222 223 /// Here are stored packets for which there was no space on m_OutBuffer, 224 /// this alows not-to kick player if its buffer is overflowed. 225 PacketQueueT m_PacketQueue; 226 227 /// True if the socket is registered with the reactor for output 228 bool m_OutActive; 229 230 uint32 m_Seed; 231 231 }; 232 232 233 #endif 233 #endif /* _WORLDSOCKET_H */ 234 234 235 235 /// @}