[2612] Applied MaNGOS coding style (see trunk/bcpp.cfg).
[mangos-git.git] / src / game / WorldSocket.cpp
blob19a600c7e0d03e065783a939e9de4f629f0cab04
1 /*
2 * Copyright (C) 2005,2006 MaNGOS <http://www.mangosproject.org/>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 #include "Common.h"
20 #include "Log.h"
21 #include "Opcodes.h"
22 #include "Config/ConfigEnv.h"
23 #include "Database/DatabaseEnv.h"
24 #include "Auth/Sha1.h"
25 #include "WorldPacket.h"
26 #include "WorldSocket.h"
27 #include "WorldSession.h"
28 #include "World.h"
29 #include "WorldSocketMgr.h"
30 #include "NameTables.h"
31 #include "Policies/SingletonImp.h"
32 #include "WorldLog.h"
33 #include "AddonHandler.h"
34 #include "zlib/zlib.h"
35 #include "../realmd/AuthCodes.h"
36 #include <cwctype> // needs for towupper
38 // Only GCC 4.1.0 and later support #pragma pack(push,1) syntax
39 #if __GNUC__ && (GCC_MAJOR < 4 || GCC_MAJOR == 4 && GCC_MINOR < 1)
40 #pragma pack(1)
41 #else
42 #pragma pack(push,1)
43 #endif
45 struct ClientPktHeader
47 uint16 size;
48 uint32 cmd;
51 struct ServerPktHeader
53 uint16 size;
54 uint16 cmd;
57 // Only GCC 4.1.0 and later support #pragma pack(pop) syntax
58 #if __GNUC__ && (GCC_MAJOR < 4 || GCC_MAJOR == 4 && GCC_MINOR < 1)
59 #pragma pack()
60 #else
61 #pragma pack(pop)
62 #endif
64 WorldSocket::WorldSocket(SocketHandler &sh): TcpSocket(sh), _cmd(0), _remaining(0), _session(NULL)
66 _seed = _GetSeed();
69 WorldSocket::~WorldSocket()
71 WorldPacket *packet;
73 while(!_sendQueue.empty())
75 packet = _sendQueue.next();
76 delete packet;
80 uint32 WorldSocket::_GetSeed()
82 return 0xDEADBABE;
85 void WorldSocket::SendPacket(WorldPacket* packet)
87 WorldPacket *pck = new WorldPacket(*packet);
88 ASSERT(pck);
90 _sendQueue.add(pck);
93 void WorldSocket::OnAccept()
95 WorldPacket packet;
97 sWorldSocketMgr.AddSocket(this);
99 packet.Initialize( SMSG_AUTH_CHALLENGE );
100 packet << _seed;
102 SendPacket(&packet);
105 void WorldSocket::OnRead()
107 TcpSocket::OnRead();
109 while(1)
111 if (!_remaining)
113 if (ibuf.GetLength() < 6)
114 break;
116 ClientPktHeader hdr;
118 ibuf.Read((char *)&hdr, 6);
119 _crypt.DecryptRecv((uint8 *)&hdr, 6);
121 _remaining = ntohs(hdr.size) - 4;
122 _cmd = hdr.cmd;
125 if (ibuf.GetLength() < _remaining)
126 break;
128 WorldPacket packet;
130 packet.resize(_remaining);
131 packet.SetOpcode((uint16)_cmd);
132 if(_remaining) ibuf.Read((char*)packet.contents(), _remaining);
134 if( sWorldLog.LogWorld() )
136 sWorldLog.Log("CLIENT:\nSOCKET: %u\nLENGTH: %u\nOPCODE: %s (0x%.4X)\nDATA:\n",
137 (uint32)GetSocket(),
138 _remaining,
139 LookupName(packet.GetOpcode(), g_worldOpcodeNames),
140 packet.GetOpcode());
142 uint32 p = 0;
143 while (p < packet.size())
145 for (uint32 j = 0; j < 16 && p < packet.size(); j++)
146 sWorldLog.Log("%.2X ", packet[p++]);
148 sWorldLog.Log("\n");
151 sWorldLog.Log("\n\n");
154 _remaining = 0;
156 switch (_cmd)
158 case CMSG_PING:
160 _HandlePing(packet);
161 break;
163 case CMSG_AUTH_SESSION:
165 _HandleAuthSession(packet);
166 break;
168 default:
170 if (_session)
171 _session->QueuePacket(packet);
172 else
173 sLog.outDetail("Received out of place packet with cmdid 0x%.4X", _cmd);
179 void WorldSocket::OnDelete()
181 if (_session)
183 _session->SetSocket(0);
184 _session = 0;
187 sWorldSocketMgr.RemoveSocket(this);
190 void WorldSocket::_HandleAuthSession(WorldPacket& recvPacket)
192 uint8 digest[20];
193 uint32 clientSeed;
194 uint32 unk2;
195 uint32 BuiltNumberClient;
196 uint32 id, security;
197 std::string account;
198 Sha1Hash I;
199 Sha1Hash sha1;
200 BigNumber v, s, g, N, x;
201 std::string password;
202 WorldPacket packet, SendAddonPacked;
204 BigNumber K;
208 recvPacket >> BuiltNumberClient; // for now no use
209 recvPacket >> unk2;
210 recvPacket >> account;
211 recvPacket >> clientSeed;
212 recvPacket.read(digest, 20);
214 catch(ByteBuffer::error &)
216 sLog.outError("WorldSocket::_HandleAuthSession Get Incomplete packet");
217 return;
220 loginDatabase.escape_string(account);
222 QueryResult *result = loginDatabase.PQuery("SELECT `id`,`gmlevel`,`sessionkey`,`last_ip`,`locked`, `password`, `v`, `s` FROM `account` WHERE `username` = '%s'", account.c_str());
224 if ( !result )
227 packet.Initialize( SMSG_AUTH_RESPONSE );
228 packet << uint8( AUTH_UNKNOWN_ACCOUNT );
229 SendPacket( &packet );
231 sLog.outDetail( "SOCKET: Sent Auth Response (unknown account)." );
232 return;
235 N.SetHexStr("894B645E89E1535BBDAD5B8B290650530801B18EBFBF5E8FAB3C82872A3E9BB7");
236 g.SetDword(7);
237 password = (*result)[5].GetString();
238 std::transform(password.begin(), password.end(), password.begin(), std::towupper);
240 s.SetHexStr((*result)[7].GetString());
241 std::string sI = account + ":" + password;
242 I.UpdateData(sI);
243 I.Finalize();
244 sha1.UpdateData(s.AsByteArray(), s.GetNumBytes());
245 sha1.UpdateData(I.GetDigest(), 20);
246 sha1.Finalize();
247 x.SetBinary(sha1.GetDigest(), sha1.GetLength());
248 v = g.ModExp(x, N);
250 sLog.outDebug("SOCKET: (s,v) check s: %s v_old: %s v_new: %s", s.AsHexStr(), (*result)[6].GetString(), v.AsHexStr() );
251 if ( strcmp(v.AsHexStr(),(*result)[6].GetString() ) )
253 packet.Initialize( SMSG_AUTH_RESPONSE );
254 packet << uint8( AUTH_UNKNOWN_ACCOUNT );
255 SendPacket( &packet );
256 sLog.outDetail( "SOCKET: User not logged.");
257 delete result;
258 return;
261 id = (*result)[0].GetUInt32();
262 security = (*result)[1].GetUInt16();
263 K.SetHexStr((*result)[2].GetString());
265 delete result;
267 uint32 num = sWorld.GetSessionCount();
268 if (sWorld.GetPlayerLimit() > 0 && num > sWorld.GetPlayerLimit() && security == 0)
271 packet.Initialize( SMSG_AUTH_RESPONSE );
272 //packet << uint8( 21 );
273 packet << uint8( CSTATUS_FULL);
274 SendPacket( &packet );
275 sLog.outBasic( "SOCKET: Sent Auth Response (server full)." );
276 return;
279 WorldSession *session = sWorld.FindSession( id );
280 if( session )
282 packet.Initialize( SMSG_AUTH_RESPONSE );
283 //packet << uint8( 13 );
284 packet << uint8( AUTH_ALREADY_ONLINE );
285 SendPacket( &packet );
287 sLog.outDetail( "SOCKET: Sent Auth Response (already connected)." );
289 session->LogoutPlayer(false);
291 return;
294 Sha1Hash sha;
296 uint32 t = 0;
297 uint32 seed = _seed;
299 sha.UpdateData(account);
300 sha.UpdateData((uint8 *)&t, 4);
301 sha.UpdateData((uint8 *)&clientSeed, 4);
302 sha.UpdateData((uint8 *)&seed, 4);
303 sha.UpdateBigNumbers(&K, NULL);
304 sha.Finalize();
306 if (memcmp(sha.GetDigest(), digest, 20))
309 packet.Initialize( SMSG_AUTH_RESPONSE );
310 //packet << uint8( 21 );
311 packet << uint8( AUTH_FAILED );
313 SendPacket( &packet );
315 sLog.outDetail( "SOCKET: Sent Auth Response (authentification failed)." );
316 return;
319 _crypt.SetKey(K.AsByteArray(), 40);
320 _crypt.Init();
322 //Send Auth is okey
323 packet.Initialize( SMSG_AUTH_RESPONSE );
324 packet << uint8( AUTH_OK ); //0x0C
325 //packet << uint8( 0xB0 ); - redundent
326 //packet << uint8( 0x09 );
327 //packet << uint8( 0x02 );
328 //packet << uint8( 0x00 );
329 //packet << uint8( 0x02 );
330 //packet << uint32( 0x0 );
332 SendPacket(&packet);
334 _session = new WorldSession(id, this);
336 ASSERT(_session);
337 _session->SetSecurity(security);
338 sWorld.AddSession(_session);
340 sLog.outBasic( "SOCKET: Client '%s' authed successfully.", account.c_str() );
341 sLog.outString( "Account: '%s' Login.", account.c_str() );
343 // do small delay (10ms) at accepting successful authed connection to prevent droping packets by client
344 // don't must harm anyone (let login ~100 accounts in 1 sec ;) )
345 #ifdef WIN32
346 Sleep(10);
347 #endif
348 //! Handled Addons
350 //Create Addon Packet
351 //sAddOnHandler.BuildAddonPacket(&recvPacket, &SendAddonPacked, recvPacket.rpos());
352 SendAddonPacked.Initialize(SMSG_ADDON_INFO); // fix banned addon
353 SendAddonPacked << uint8( 0x41 ); // fix banned addon
354 SendAddonPacked << uint8( 0x64 ); // fix banned addon
355 SendAddonPacked << uint8( 0x64 ); // fix banned addon
356 SendAddonPacked << uint8( 0x6f ); // fix banned addon
357 SendAddonPacked << uint8( 0x6e ); // fix banned addon
358 SendAddonPacked << uint8( 0x00 ); // fix banned addon
359 SendPacket(&SendAddonPacked);
361 return;
364 void WorldSocket::_HandlePing(WorldPacket& recvPacket)
366 WorldPacket packet;
367 uint32 ping;
371 recvPacket >> ping;
373 catch(ByteBuffer::error &)
375 sLog.outDetail("Incomplete packet");
376 return;
379 packet.Initialize( SMSG_PONG );
380 packet << ping;
381 SendPacket(&packet);
383 return;
386 void WorldSocket::Update(time_t diff)
388 WorldPacket *packet;
389 ServerPktHeader hdr;
391 while(!_sendQueue.empty())
393 packet = _sendQueue.next();
395 hdr.size = ntohs((uint16)packet->size() + 2);
396 hdr.cmd = packet->GetOpcode();
398 if( sWorldLog.LogWorld() )
400 sWorldLog.Log("SERVER:\nSOCKET: %u\nLENGTH: %u\nOPCODE: %s (0x%.4X)\nDATA:\n",
401 (uint32)GetSocket(),
402 packet->size(),
403 LookupName(packet->GetOpcode(), g_worldOpcodeNames),
404 packet->GetOpcode());
406 uint32 p = 0;
407 while (p < packet->size())
409 for (uint32 j = 0; j < 16 && p < packet->size(); j++)
410 sWorldLog.Log("%.2X ", (*packet)[p++]);
412 sWorldLog.Log("\n");
415 sWorldLog.Log("\n\n");
418 _crypt.EncryptSend((uint8*)&hdr, 4);
420 TcpSocket::SendBuf((char*)&hdr, 4);
421 if(packet->size()) TcpSocket::SendBuf((char*)packet->contents(), packet->size());
423 delete packet;
427 void WorldSocket::SendAuthWaitQue(uint32 PlayersInQue)
429 WorldPacket packet;
430 packet.Initialize( SMSG_AUTH_RESPONSE );
431 packet << uint8( AUTH_WAIT_QUEUE );
432 packet << uint32 (0x00); //unknown
433 packet << uint32 (0x00); //unknown
434 packet << uint8 (0x00); //unknown
435 packet << uint32 (PlayersInQue); //amount of players in que
436 SendPacket(&packet);