PageRenderTime 41ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/src/arcemu-logonserver/LogonCommServer.cpp

http://wowtbc.googlecode.com/
C++ | 533 lines | 378 code | 100 blank | 55 comment | 59 complexity | 8da0dc4281fecc8cf628d963184e3344 MD5 | raw file
Possible License(s): AGPL-3.0
  1. /*
  2. * ArcEmu MMORPG Server
  3. * Copyright (C) 2008 <http://www.ArcEmu.org/>
  4. *
  5. * This program is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU Affero General Public License as published by
  7. * the Free Software Foundation, either version 3 of the License, or
  8. * any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU Affero General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU Affero General Public License
  16. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. *
  18. */
  19. #include "LogonStdAfx.h"
  20. #pragma pack(push, 1)
  21. typedef struct
  22. {
  23. uint16 opcode;
  24. uint32 size;
  25. }logonpacket;
  26. #pragma pack(pop)
  27. ARCEMU_INLINE static void swap32(uint32* p) { *p = ((*p >> 24 & 0xff)) | ((*p >> 8) & 0xff00) | ((*p << 8) & 0xff0000) | (*p << 24); }
  28. LogonCommServerSocket::LogonCommServerSocket(SOCKET fd) : Socket(fd, 65536, 524288)
  29. {
  30. // do nothing
  31. last_ping = (uint32)UNIXTIME;
  32. remaining = opcode = 0;
  33. removed = true;
  34. use_crypto = false;
  35. authenticated = 0;
  36. }
  37. LogonCommServerSocket::~LogonCommServerSocket()
  38. {
  39. }
  40. void LogonCommServerSocket::OnDisconnect()
  41. {
  42. // if we're registered -> Set offline
  43. if(!removed)
  44. {
  45. set<uint32>::iterator itr = server_ids.begin();
  46. for(; itr != server_ids.end(); ++itr)
  47. //sInfoCore.RemoveRealm((*itr));
  48. sInfoCore.UpdateRealmStatus((*itr), 2);
  49. sInfoCore.RemoveServerSocket(this);
  50. }
  51. }
  52. void LogonCommServerSocket::OnConnect()
  53. {
  54. if( !IsServerAllowed(GetRemoteAddress().s_addr) )
  55. {
  56. printf("Server connection from %s:%u DENIED, not an allowed IP.\n", GetRemoteIP().c_str(), GetRemotePort());
  57. Disconnect();
  58. return;
  59. }
  60. sInfoCore.AddServerSocket(this);
  61. removed = false;
  62. }
  63. void LogonCommServerSocket::OnRead()
  64. {
  65. while(true)
  66. {
  67. if(!remaining)
  68. {
  69. if(GetReadBuffer().GetSize() < 6)
  70. return; // no header
  71. // read header
  72. GetReadBuffer().Read((uint8*)&opcode, 2);
  73. GetReadBuffer().Read((uint8*)&remaining, 4);
  74. if(use_crypto)
  75. {
  76. // decrypt the packet
  77. recvCrypto.Process((unsigned char*)&opcode, (unsigned char*)&opcode, 2);
  78. recvCrypto.Process((unsigned char*)&remaining, (unsigned char*)&remaining, 4);
  79. }
  80. #ifdef USING_BIG_ENDIAN
  81. opcode = swap16(opcode);
  82. #else
  83. /* reverse byte order */
  84. swap32(&remaining);
  85. #endif
  86. }
  87. // do we have a full packet?
  88. if(GetReadBuffer().GetSize() < remaining)
  89. return;
  90. // create the buffer
  91. WorldPacket buff(opcode, remaining);
  92. if(remaining)
  93. {
  94. buff.resize(remaining);
  95. //Read(remaining, (uint8*)buff.contents());
  96. GetReadBuffer().Read((uint8*)buff.contents(), remaining);
  97. }
  98. if(use_crypto && remaining)
  99. recvCrypto.Process((unsigned char*)buff.contents(), (unsigned char*)buff.contents(), remaining);
  100. // handle the packet
  101. HandlePacket(buff);
  102. remaining = 0;
  103. opcode = 0;
  104. }
  105. }
  106. void LogonCommServerSocket::HandlePacket(WorldPacket & recvData)
  107. {
  108. if(authenticated == 0 && recvData.GetOpcode() != RCMSG_AUTH_CHALLENGE)
  109. {
  110. // invalid
  111. Disconnect();
  112. return;
  113. }
  114. static logonpacket_handler Handlers[RMSG_COUNT] = {
  115. NULL, // RMSG_NULL
  116. &LogonCommServerSocket::HandleRegister, // RCMSG_REGISTER_REALM
  117. NULL, // RSMSG_REALM_REGISTERED
  118. &LogonCommServerSocket::HandleSessionRequest, // RCMSG_REQUEST_SESSION
  119. NULL, // RSMSG_SESSION_RESULT
  120. &LogonCommServerSocket::HandlePing, // RCMSG_PING
  121. NULL, // RSMSG_PONG
  122. &LogonCommServerSocket::HandleSQLExecute, // RCMSG_SQL_EXECUTE
  123. &LogonCommServerSocket::HandleReloadAccounts, // RCMSG_RELOAD_ACCOUNTS
  124. &LogonCommServerSocket::HandleAuthChallenge, // RCMSG_AUTH_CHALLENGE
  125. NULL, // RSMSG_AUTH_RESPONSE
  126. NULL, // RSMSG_REQUEST_ACCOUNT_CHARACTER_MAPPING
  127. &LogonCommServerSocket::HandleMappingReply, // RCMSG_ACCOUNT_CHARACTER_MAPPING_REPLY
  128. &LogonCommServerSocket::HandleUpdateMapping, // RCMSG_UPDATE_CHARACTER_MAPPING_COUNT
  129. NULL, // RSMSG_DISCONNECT_ACCOUNT
  130. &LogonCommServerSocket::HandleTestConsoleLogin, // RCMSG_TEST_CONSOLE_LOGIN
  131. NULL, // RSMSG_CONSOLE_LOGIN_RESULT
  132. &LogonCommServerSocket::HandleDatabaseModify, // RCMSG_MODIFY_DATABASE
  133. };
  134. if(recvData.GetOpcode() >= RMSG_COUNT || Handlers[recvData.GetOpcode()] == 0)
  135. {
  136. printf("Got unknwon packet from logoncomm: %u\n", recvData.GetOpcode());
  137. return;
  138. }
  139. (this->*(Handlers[recvData.GetOpcode()]))(recvData);
  140. }
  141. void LogonCommServerSocket::HandleRegister(WorldPacket & recvData)
  142. {
  143. string Name;
  144. int32 my_id;
  145. recvData >> Name;
  146. my_id = sInfoCore.GetRealmIdByName(Name);
  147. if (my_id == -1)
  148. {
  149. my_id = sInfoCore.GenerateRealmID();
  150. sLog.outString("Registering realm `%s` under ID %u.", Name.c_str(), my_id);
  151. }
  152. else
  153. {
  154. sInfoCore.RemoveRealm(my_id);
  155. int new_my_id = sInfoCore.GenerateRealmID(); //socket timout will DC old id after a while, make sure it's not the one we restarted
  156. sLog.outString("Updating realm `%s` with ID %u to new ID %u.", Name.c_str(), my_id, new_my_id );
  157. my_id = new_my_id;
  158. }
  159. Realm * realm = new Realm;
  160. // recvData >> realm->Name >> realm->Address;
  161. // recvData >> realm->Colour >> realm->Icon >> realm->TimeZone >> realm->Population;
  162. realm->Name = Name;
  163. realm->Colour = 0;
  164. recvData >> realm->Address >> realm->Icon >> realm->TimeZone >> realm->Population >> realm->Lock;
  165. // uint32 my_id = sInfoCore.GenerateRealmID();
  166. // sLog.outString("Registering realm `%s` under ID %u.", realm->Name.c_str(), my_id);
  167. // Add to the main realm list
  168. sInfoCore.AddRealm(my_id, realm);
  169. // Send back response packet.
  170. WorldPacket data(RSMSG_REALM_REGISTERED, 4);
  171. data << uint32(0); // Error
  172. data << my_id; // Realm ID
  173. data << realm->Name;
  174. SendPacket(&data);
  175. server_ids.insert(my_id);
  176. /* request character mapping for this realm */
  177. data.Initialize(RSMSG_REQUEST_ACCOUNT_CHARACTER_MAPPING);
  178. data << my_id;
  179. SendPacket(&data);
  180. }
  181. void LogonCommServerSocket::HandleSessionRequest(WorldPacket & recvData)
  182. {
  183. uint32 request_id;
  184. string account_name;
  185. recvData >> request_id;
  186. recvData >> account_name;
  187. // get sessionkey!
  188. uint32 error = 0;
  189. Account * acct = sAccountMgr.GetAccount(account_name);
  190. if(acct == NULL || acct->SessionKey == NULL)
  191. error = 1; // Unauthorized user.
  192. // build response packet
  193. WorldPacket data(RSMSG_SESSION_RESULT, 150);
  194. data << request_id;
  195. data << error;
  196. if(!error)
  197. {
  198. // Append account information.
  199. data << acct->AccountId;
  200. data << acct->UsernamePtr->c_str();
  201. if(!acct->GMFlags)
  202. data << uint8(0);
  203. else
  204. data << acct->GMFlags;
  205. data << acct->AccountFlags;
  206. data.append(acct->SessionKey, 40);
  207. data.append(acct->Locale, 4);
  208. data << acct->Muted;
  209. }
  210. SendPacket(&data);
  211. }
  212. void LogonCommServerSocket::HandlePing(WorldPacket & recvData)
  213. {
  214. WorldPacket data(RSMSG_PONG, 4);
  215. SendPacket(&data);
  216. last_ping = (uint32)time(NULL);
  217. }
  218. void LogonCommServerSocket::SendPacket(WorldPacket * data)
  219. {
  220. bool rv;
  221. BurstBegin();
  222. logonpacket header;
  223. #ifndef USING_BIG_ENDIAN
  224. header.opcode = data->GetOpcode();
  225. //header.size = ntohl((u_long)data->size());
  226. header.size = (uint32)data->size();
  227. swap32(&header.size);
  228. #else
  229. header.opcode = swap16(uint16(data->GetOpcode()));
  230. header.size = data->size();
  231. #endif
  232. if(use_crypto)
  233. sendCrypto.Process((unsigned char*)&header, (unsigned char*)&header, 6);
  234. rv=BurstSend((uint8*)&header, 6);
  235. if(data->size() > 0 && rv)
  236. {
  237. if(use_crypto)
  238. sendCrypto.Process((unsigned char*)data->contents(), (unsigned char*)data->contents(), (uint32)data->size());
  239. rv=BurstSend(data->contents(), (uint32)data->size());
  240. }
  241. if(rv) BurstPush();
  242. BurstEnd();
  243. }
  244. void LogonCommServerSocket::HandleSQLExecute(WorldPacket & recvData)
  245. {
  246. /*string Query;
  247. recvData >> Query;
  248. sLogonSQL->Execute(Query.c_str());*/
  249. printf("!! WORLD SERVER IS REQUESTING US TO EXECUTE SQL. THIS IS DEPRECATED AND IS BEING IGNORED. THE SERVER WAS: %s, PLEASE UPDATE IT.\n", GetRemoteIP().c_str());
  250. }
  251. void LogonCommServerSocket::HandleReloadAccounts(WorldPacket & recvData)
  252. {
  253. printf("!! WORLD SERVER IS REQUESTING US TO RELOAD ACCOUNTS. THIS IS DEPRECATED AND IS BEING IGNORED. THE SERVER WAS: %s, PLEASE UPDATE IT.\n", GetRemoteIP().c_str());
  254. //sAccountMgr.ReloadAccounts(true);
  255. }
  256. void LogonCommServerSocket::HandleAuthChallenge(WorldPacket & recvData)
  257. {
  258. unsigned char key[20];
  259. uint32 result = 1;
  260. recvData.read(key, 20);
  261. // check if we have the correct password
  262. if(memcmp(key, LogonServer::getSingleton().sql_hash, 20))
  263. result = 0;
  264. sLog.outString("Authentication request from %s, result %s.", GetRemoteIP().c_str(), result ? "OK" : "FAIL");
  265. printf("Key: ");
  266. for(int i = 0; i < 20; ++i)
  267. printf("%.2X", key[i]);
  268. printf("\n");
  269. recvCrypto.Setup(key, 20);
  270. sendCrypto.Setup(key, 20);
  271. /* packets are encrypted from now on */
  272. use_crypto = true;
  273. /* send the response packet */
  274. WorldPacket data(RSMSG_AUTH_RESPONSE, 1);
  275. data << result;
  276. SendPacket(&data);
  277. /* set our general var */
  278. authenticated = result;
  279. }
  280. void LogonCommServerSocket::HandleMappingReply(WorldPacket & recvData)
  281. {
  282. /* this packet is gzipped, whee! :D */
  283. uint32 real_size;
  284. recvData >> real_size;
  285. uLongf rsize = real_size;
  286. ByteBuffer buf(real_size);
  287. buf.clear();
  288. buf.resize(real_size);
  289. if(uncompress((uint8*)buf.contents(), &rsize, recvData.contents() + 4, (u_long)recvData.size() - 4) != Z_OK)
  290. {
  291. printf("Uncompress of mapping failed.\n");
  292. return;
  293. }
  294. uint32 account_id;
  295. uint8 number_of_characters;
  296. uint32 count;
  297. uint32 realm_id;
  298. buf >> realm_id;
  299. Realm * realm = sInfoCore.GetRealm(realm_id);
  300. if(!realm)
  301. return;
  302. sInfoCore.getRealmLock().Acquire();
  303. HM_NAMESPACE::hash_map<uint32, uint8>::iterator itr;
  304. buf >> count;
  305. printf("Got mapping packet for realm %u, total of %u entries.\n", (unsigned int)realm_id, (unsigned int)count);
  306. for(uint32 i = 0; i < count; ++i)
  307. {
  308. buf >> account_id >> number_of_characters;
  309. itr = realm->CharacterMap.find(account_id);
  310. if(itr != realm->CharacterMap.end())
  311. itr->second = number_of_characters;
  312. else
  313. realm->CharacterMap.insert( make_pair( account_id, number_of_characters ) );
  314. }
  315. sInfoCore.getRealmLock().Release();
  316. }
  317. void LogonCommServerSocket::HandleUpdateMapping(WorldPacket & recvData)
  318. {
  319. uint32 realm_id;
  320. uint32 account_id;
  321. uint8 chars_to_add;
  322. recvData >> realm_id;
  323. Realm * realm = sInfoCore.GetRealm(realm_id);
  324. if(!realm)
  325. return;
  326. sInfoCore.getRealmLock().Acquire();
  327. recvData >> account_id >> chars_to_add;
  328. HM_NAMESPACE::hash_map<uint32, uint8>::iterator itr = realm->CharacterMap.find(account_id);
  329. if(itr != realm->CharacterMap.end())
  330. itr->second += chars_to_add;
  331. else
  332. realm->CharacterMap.insert( make_pair( account_id, chars_to_add ) );
  333. sInfoCore.getRealmLock().Release();
  334. }
  335. void LogonCommServerSocket::HandleTestConsoleLogin(WorldPacket & recvData)
  336. {
  337. WorldPacket data(RSMSG_CONSOLE_LOGIN_RESULT, 8);
  338. uint32 request;
  339. string accountname;
  340. uint8 key[20];
  341. recvData >> request;
  342. recvData >> accountname;
  343. recvData.read(key, 20);
  344. data << request;
  345. Account * pAccount = sAccountMgr.GetAccount(accountname);
  346. if(pAccount == NULL)
  347. {
  348. data << uint32(0);
  349. SendPacket(&data);
  350. return;
  351. }
  352. if(pAccount->GMFlags == NULL || strchr(pAccount->GMFlags, 'z') == NULL)
  353. {
  354. data << uint32(0);
  355. SendPacket(&data);
  356. return;
  357. }
  358. if(memcmp(pAccount->SrpHash, key, 20) != 0)
  359. {
  360. data << uint32(0);
  361. SendPacket(&data);
  362. return;
  363. }
  364. data << uint32(1);
  365. SendPacket(&data);
  366. }
  367. void LogonCommServerSocket::HandleDatabaseModify(WorldPacket& recvData)
  368. {
  369. uint32 method;
  370. recvData >> method;
  371. switch(method)
  372. {
  373. case 1: // set account ban
  374. {
  375. string account;
  376. string banreason;
  377. uint32 duration;
  378. recvData >> account >> duration >> banreason;
  379. // remember we expect this in uppercase
  380. arcemu_TOUPPER(account);
  381. Account * pAccount = sAccountMgr.GetAccount(account);
  382. if( pAccount == NULL )
  383. return;
  384. pAccount->Banned = duration;
  385. // update it in the sql (duh)
  386. sLogonSQL->Execute("UPDATE accounts SET banned = %u, banreason = '%s' WHERE login = \"%s\"", duration, sLogonSQL->EscapeString( banreason ).c_str(), sLogonSQL->EscapeString(account).c_str());
  387. }break;
  388. case 2: // set gm
  389. {
  390. string account;
  391. string gm;
  392. recvData >> account >> gm;
  393. // remember we expect this in uppercase
  394. arcemu_TOUPPER(account);
  395. Account * pAccount = sAccountMgr.GetAccount(account);
  396. if( pAccount == NULL )
  397. return;
  398. pAccount->SetGMFlags( account.c_str() );
  399. // update it in the sql (duh)
  400. sLogonSQL->Execute("UPDATE accounts SET gm = \"%s\" WHERE login = \"%s\"", sLogonSQL->EscapeString(gm).c_str(), sLogonSQL->EscapeString(account).c_str());
  401. }break;
  402. case 3: // set mute
  403. {
  404. string account;
  405. uint32 duration;
  406. recvData >> account >> duration;
  407. // remember we expect this in uppercase
  408. arcemu_TOUPPER(account);
  409. Account * pAccount = sAccountMgr.GetAccount(account);
  410. if( pAccount == NULL )
  411. return;
  412. pAccount->Muted = duration;
  413. // update it in the sql (duh)
  414. sLogonSQL->Execute("UPDATE accounts SET muted = %u WHERE login = \"%s\"", duration, sLogonSQL->EscapeString(account).c_str());
  415. }break;
  416. case 4: // ip ban add
  417. {
  418. string ip;
  419. string banreason;
  420. uint32 duration;
  421. recvData >> ip >> duration >> banreason;
  422. if( sIPBanner.Add( ip.c_str(), duration ) )
  423. sLogonSQL->Execute("INSERT INTO ipbans VALUES(\"%s\", %u, \"%s\")", sLogonSQL->EscapeString(ip).c_str(), duration, sLogonSQL->EscapeString(banreason).c_str() );
  424. }break;
  425. case 5: // ip ban reomve
  426. {
  427. string ip;
  428. recvData >> ip;
  429. if( sIPBanner.Remove( ip.c_str() ) )
  430. sLogonSQL->Execute("DELETE FROM ipbans WHERE ip = \"%s\"", sLogonSQL->EscapeString(ip).c_str());
  431. }break;
  432. }
  433. }