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
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"
29 #include "WorldSocketMgr.h"
30 #include "NameTables.h"
31 #include "Policies/SingletonImp.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)
45 struct ClientPktHeader
51 struct ServerPktHeader
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)
64 WorldSocket::WorldSocket(SocketHandler
&sh
): TcpSocket(sh
), _cmd(0), _remaining(0), _session(NULL
)
69 WorldSocket::~WorldSocket()
73 while(!_sendQueue
.empty())
75 packet
= _sendQueue
.next();
80 uint32
WorldSocket::_GetSeed()
85 void WorldSocket::SendPacket(WorldPacket
* packet
)
87 WorldPacket
*pck
= new WorldPacket(*packet
);
93 void WorldSocket::OnAccept()
97 sWorldSocketMgr
.AddSocket(this);
99 packet
.Initialize( SMSG_AUTH_CHALLENGE
);
105 void WorldSocket::OnRead()
113 if (ibuf
.GetLength() < 6)
118 ibuf
.Read((char *)&hdr
, 6);
119 _crypt
.DecryptRecv((uint8
*)&hdr
, 6);
121 _remaining
= ntohs(hdr
.size
) - 4;
125 if (ibuf
.GetLength() < _remaining
)
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",
139 LookupName(packet
.GetOpcode(), g_worldOpcodeNames
),
143 while (p
< packet
.size())
145 for (uint32 j
= 0; j
< 16 && p
< packet
.size(); j
++)
146 sWorldLog
.Log("%.2X ", packet
[p
++]);
151 sWorldLog
.Log("\n\n");
163 case CMSG_AUTH_SESSION
:
165 _HandleAuthSession(packet
);
171 _session
->QueuePacket(packet
);
173 sLog
.outDetail("Received out of place packet with cmdid 0x%.4X", _cmd
);
179 void WorldSocket::OnDelete()
183 _session
->SetSocket(0);
187 sWorldSocketMgr
.RemoveSocket(this);
190 void WorldSocket::_HandleAuthSession(WorldPacket
& recvPacket
)
195 uint32 BuiltNumberClient
;
200 BigNumber v
, s
, g
, N
, x
;
201 std::string password
;
202 WorldPacket packet
, SendAddonPacked
;
208 recvPacket
>> BuiltNumberClient
; // for now no use
210 recvPacket
>> account
;
211 recvPacket
>> clientSeed
;
212 recvPacket
.read(digest
, 20);
214 catch(ByteBuffer::error
&)
216 sLog
.outError("WorldSocket::_HandleAuthSession Get Incomplete packet");
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());
227 packet
.Initialize( SMSG_AUTH_RESPONSE
);
228 packet
<< uint8( AUTH_UNKNOWN_ACCOUNT
);
229 SendPacket( &packet
);
231 sLog
.outDetail( "SOCKET: Sent Auth Response (unknown account)." );
235 N
.SetHexStr("894B645E89E1535BBDAD5B8B290650530801B18EBFBF5E8FAB3C82872A3E9BB7");
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
;
244 sha1
.UpdateData(s
.AsByteArray(), s
.GetNumBytes());
245 sha1
.UpdateData(I
.GetDigest(), 20);
247 x
.SetBinary(sha1
.GetDigest(), sha1
.GetLength());
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.");
261 id
= (*result
)[0].GetUInt32();
262 security
= (*result
)[1].GetUInt16();
263 K
.SetHexStr((*result
)[2].GetString());
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)." );
279 WorldSession
*session
= sWorld
.FindSession( id
);
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);
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
);
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)." );
319 _crypt
.SetKey(K
.AsByteArray(), 40);
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 );
334 _session
= new WorldSession(id
, this);
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 ;) )
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
);
364 void WorldSocket::_HandlePing(WorldPacket
& recvPacket
)
373 catch(ByteBuffer::error
&)
375 sLog
.outDetail("Incomplete packet");
379 packet
.Initialize( SMSG_PONG
);
386 void WorldSocket::Update(time_t diff
)
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",
403 LookupName(packet
->GetOpcode(), g_worldOpcodeNames
),
404 packet
->GetOpcode());
407 while (p
< packet
->size())
409 for (uint32 j
= 0; j
< 16 && p
< packet
->size(); j
++)
410 sWorldLog
.Log("%.2X ", (*packet
)[p
++]);
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());
427 void WorldSocket::SendAuthWaitQue(uint32 PlayersInQue
)
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