28#include <boost/asio/buffer.hpp>
29#include <boost/asio/error.hpp>
48 uint32 data = (size << 13) | (cmd & MAX_OPCODE);
49 memcpy(&header[0], &data, 4);
50 _authCrypt->EncryptSend((uint8*)&header[0], getHeaderLength());
55 memcpy(&header[0], &size, 2);
56 memcpy(&header[2], &cmd, 2);
89bool IsHushedUnhandledClientOpcode(
uint16 opcode)
192 std::vector<char> serialized;
193 serialized.reserve(packetSize);
194 serialized.insert(serialized.end(),
reinterpret_cast<char*
>(header.
header),
197 serialized.insert(serialized.end(),
reinterpret_cast<char const*
>(pkt->
contents()),
198 reinterpret_cast<char const*
>(pkt->
contents()) + pkt->
size());
238 packet << std::string(
"RLD OF WARCRAFT CONNECTION - SERVER TO CLIENT");
285 [
this](boost::system::error_code
const& error,
size_t transferredBytes)
302 [
this](boost::system::error_code
const& error,
size_t transferredBytes)
313 if (error != boost::asio::error::operation_aborted && error != boost::asio::error::eof)
314 SF_LOG_DEBUG(
"network",
"WorldSocket::HandleAsyncRead: peer error closing connection error = %d", error.value());
321 if (transferredBytes == 0)
323 SF_LOG_DEBUG(
"network",
"WorldSocket::HandleAsyncRead: Peer has closed connection");
331 if (result == -1 && errno != EWOULDBLOCK && errno != EAGAIN)
333 SF_LOG_DEBUG(
"network",
"WorldSocket::HandleAsyncRead: packet processing error, errno = %d", errno);
350 (void)transferredBytes;
354 if (error != boost::asio::error::operation_aborted)
355 SF_LOG_DEBUG(
"network",
"WorldSocket::HandleAsyncWrite: peer error closing connection error = %d", error.value());
408 header.
cmd = value & 0x1FFF;
409 header.
size = ((value & ~(
uint32)0x1FFF) >> 13);
411 if (header.
size > 10236)
416 SF_LOG_ERROR(
"network",
"WorldSocket::handle_input_header(): client (account: %u, char [GUID: %u, name: %s]) sent malformed packet (size: %d, cmd: %d)",
419 _player ? _player->
GetName().c_str() :
"<none>",
447 if ((header.
size < 4) || (header.
size > 10240))
452 SF_LOG_ERROR(
"network",
"WorldSocket::handle_input_header(): client (account: %u, char [GUID: %u, name: %s]) sent malformed packet (size: %d, cmd: %d)",
455 _player ? _player->
GetName().c_str() :
"<none>",
529 while (readPos < length)
537 const size_t available = length - readPos;
538 const size_t to_header = std::min(available, needed);
541 readPos += to_header;
546 ASSERT(readPos == length);
554 ASSERT((errno != EWOULDBLOCK) && (errno != EAGAIN));
565 const size_t available = length - readPos;
566 const size_t to_header = std::min(available, needed);
569 readPos += to_header;
574 ASSERT(readPos == length);
582 ASSERT((errno != EWOULDBLOCK) && (errno != EAGAIN));
593 SF_LOG_ERROR(
"network",
"Forcing close on input m_RecvWPct = NULL");
603 const size_t available = length - readPos;
604 const size_t to_data = std::min(available, needed);
612 ASSERT(readPos == length);
621 ASSERT((errno != EWOULDBLOCK) && (errno != EAGAIN));
626 return length == 4096 ? 1 : 2;
634 std::unique_ptr<WorldPacket> aptr(new_pct);
663 SF_LOG_ERROR(
"network",
"WorldSocket::ProcessIncoming: received duplicate CMSG_AUTH_SESSION from %s",
685 if (str !=
"D OF WARCRAFT CONNECTION - CLIENT TO SERVER")
705 SF_LOG_ERROR(
"network.opcode",
"ProcessIncoming: Client not authed opcode = %u",
uint32(opcode));
747 SF_LOG_ERROR(
"network",
"WorldSocket::ProcessIncoming ByteBufferException occured while parsing an instant handled packet %s from client %s, accountid=%i. Disconnected client.",
778 std::array<uint8, 4> clientSeed;
784 recvPacket >> digest[18];
785 recvPacket >> digest[14];
786 recvPacket >> digest[3];
787 recvPacket >> digest[4];
788 recvPacket >> digest[0];
789 recvPacket >> VirtualRealmID;
790 recvPacket >> digest[11];
791 recvPacket.
read(clientSeed);
792 recvPacket >> digest[19];
795 recvPacket >> digest[2];
796 recvPacket >> digest[9];
797 recvPacket >> digest[12];
800 recvPacket >> digest[16];
801 recvPacket >> digest[5];
802 recvPacket >> digest[6];
803 recvPacket >> digest[8];
804 recvPacket >> clientBuild;
805 recvPacket >> digest[17];
806 recvPacket >> digest[7];
807 recvPacket >> digest[13];
808 recvPacket >> digest[15];
809 recvPacket >> digest[1];
810 recvPacket >> digest[10];
811 recvPacket >> addonSize;
813 addonsData.
resize(addonSize);
819 account = recvPacket.
ReadString(accountNameLength);
841 SF_LOG_ERROR(
"network",
"WorldSocket::HandleAuthSession: Sent Auth Response (unknown account).");
845 Field* fields = result->Fetch();
849 if (expansion > world_expansion)
850 expansion = world_expansion;
853 if (fields[3].GetUInt8() == 1)
858 SF_LOG_DEBUG(
"network",
"WorldSocket::HandleAuthSession: Sent Auth Response (Account IP differs).");
871 mutetime = time(NULL) +
llabs(mutetime);
887 bool hasBoost = fields[9].
GetBool();
893 SF_LOG_ERROR(
"network",
"WorldSocket::HandleAuthSession: Client %s attempted to log in using invalid client OS (%s).",
GetRemoteAddress().c_str(), os.c_str());
909 fields = result->Fetch();
924 SF_LOG_ERROR(
"network",
"WorldSocket::HandleAuthSession: Sent Auth Response (Account banned).");
930 SF_LOG_DEBUG(
"network",
"Allowed Level: %u Player Level %u",
uint8(allowedAccountType), security);
934 SF_LOG_INFO(
"network",
"WorldSocket::HandleAuthSession: User tries to login but his security level is not enough");
939 uint8 t[4] = { 0x00, 0x00, 0x00, 0x00 };
954 SF_LOG_ERROR(
"network",
"WorldSocket::HandleAuthSession: Authentication failed for account: %u ('%s') address: %s",
id, account.c_str(), address.c_str());
958 SF_LOG_DEBUG(
"network",
"WorldSocket::HandleAuthSession: Client '%s' authenticated successfully from %s.",
969 bool isRecruiter =
false;
1010 sWorld->AddSession(session);
1020 recvPacket >> latency;
1030 std::chrono::steady_clock::time_point cur_time = std::chrono::steady_clock::now();
1034 if (diff_time < std::chrono::seconds(27))
1047 SF_LOG_ERROR(
"network",
"WorldSocket::HandlePing: %s kicked for over-speed pings (address: %s)",
1053 if (kickForOverspeed)
1071 SF_LOG_ERROR(
"network",
"WorldSocket::HandlePing: peer sent CMSG_PING, "
1072 "but is not authenticated or got recently kicked, "
1078 if (!updatedSession)
1093 packet <<
uint8(code);
constexpr size_t SESSION_KEY_LENGTH
std::array< uint8, SESSION_KEY_LENGTH > SessionKey
const uint8 TOTAL_LOCALES
#define SF_LOG_DEBUG(filterType__,...)
#define SF_LOG_ERROR(filterType__,...)
#define SF_LOG_TRACE(filterType__,...)
#define SF_LOG_INFO(filterType__,...)
@ LOGIN_UPD_MUTE_TIME_LOGIN
@ LOGIN_GET_GMLEVEL_BY_REALMID
@ LOGIN_SEL_ACCOUNT_RECRUITER
@ LOGIN_SEL_ACCOUNT_INFO_BY_NAME
Skyfire::AutoPtr< PreparedResultSet, Skyfire::Mutex > PreparedQueryResult
bool IsInitialized() const
bool WriteBit(uint32 bit)
uint32 ReadBits(size_t bits)
void resize(size_t newsize)
std::string ReadString(size_t length)
std::string GetString() const
std::vector< uint8 > GetBinary() const
uint32 GetGUIDLow() const
static uint16 DropHighBytes(uint16 opcode)
void setString(const uint8 index, const std::string &value)
void setInt64(const uint8 index, const int64 value)
void setUInt32(const uint8 index, const uint32 value)
void setInt32(const uint8 index, const int32 value)
Digest const & GetDigest() const
void UpdateData(uint8 const *data, size_t len)
std::array< uint8, DIGEST_LENGTH > Digest
std::string const & GetName() const
uint16 GetReceivedOpcode()
Opcodes GetOpcode() const
Player session in the World.
void ReadAddonsInfo(WorldPacket &data)
void QueuePacket(WorldPacket *new_packet)
Add an incoming packet to the queue.
std::string GetPlayerInfo() const
Player * GetPlayer() const
void SetVirtualRealmID(uint32 VRealmID)
uint32 GetVirtualRealmID() const
bool HasPermission(uint32 permissionId)
uint32 GetAccountId() const
int32 HandleEnableNagleAlgorithm()
void InitWarden(SessionKey const &, std::string const &os)
void SetLatency(uint32 latency)
void LoadGlobalAccountData()
void ResetClientTimeDelay()
size_t m_OutBufferSize
Configured output buffer size retained for network option compatibility.
bool IsClosed(void) const
Check if socket is closed.
WorldSocket(std::unique_ptr< WorldSocketHandle > socket, std::string remoteAddress)
void HandleAsyncWrite(boost::system::error_code const &error, size_t transferredBytes)
long RemoveReference(void)
Remove reference to this object.
std::unique_ptr< WorldSocketHandle > m_Socket
std::atomic< bool > m_CloseNotified
std::vector< uint8 > m_WorldHeader
void SendAuthResponseError(ResponseCodes code)
WorldPacket * m_RecvWPct
here are stored the fragments of the received data
std::atomic< long > m_ReferenceCount
WorldSocketSessionState m_SessionState
Session to which received packets are routed.
long AddReference(void)
Add reference to this object.
std::chrono::steady_clock::time_point m_LastPingTime
Time in which the last ping was received.
int ProcessIncoming(WorldPacket *new_pct)
AuthCrypt m_Crypt
Class used for managing encryption of the headers.
std::unique_ptr< Skyfire::Net::BoostAsioWriteQueue< WorldSocketHandle > > m_WriteQueue
int HandleSendAuthSession()
Called by MSG_VERIFY_CONNECTIVITY_RESPONSE.
uint32 m_OverSpeedPings
Keep track of over-speed pings, to prevent ping flood.
LockType m_SendLock
Mutex for protecting packet serialization and pre-start output.
void RefreshPacketLogSessionInfo()
Refreshes packet log metadata after a session gains character context.
int handle_input_header(void)
Helper functions for processing incoming data.
bool HasPendingOutput(void) const
Returns true when outgoing data is waiting to be flushed.
void Start(std::function< void(WorldSocket *)> closeHandler)
Starts asynchronous socket processing.
int HandleAuthSession(WorldPacket &recvPacket)
Called by ProcessIncoming() on CMSG_AUTH_SESSION.
void CloseSocket(void)
Close the socket.
void HandleAsyncRead(boost::system::error_code const &error, size_t transferredBytes)
void DetachSession(WorldSession *session)
Detaches the owning world session when the session is being removed.
int handle_input_payload(void)
std::atomic< bool > m_Closed
std::vector< uint8 > m_Header
std::unique_lock< LockType > GuardType
int Initialize(void)
Called after socket accept and manager setup.
const std::string & GetRemoteAddress(void) const
Get address of connected peer.
int HandlePing(WorldPacket &recvPacket)
Called by ProcessIncoming() on CMSG_PING.
Skyfire::PacketLogServerSessionInfo BuildPacketLogSessionInfo() const
bool IsValidSocket(void) const
void LogPacketMarker(std::string const &marker)
Writes a readable marker into the per-session packet log.
std::function< void(WorldSocket *)> m_CloseHandler
std::array< uint8, 4 > m_Seed
std::deque< std::vector< char > > m_PendingOutput
Queue used before the socket manager starts asynchronous processing.
std::array< char, 4096 > m_ReadBuffer
void QueueSerializedPacket(std::vector< char > data)
std::string m_Address
Address of the remote peer.
int SendPacket(const WorldPacket &pct)
int handle_input_missing_data(char const *data, size_t length)
std::string GetOpcodeNameForLogging(Opcodes id, bool isServerOpcode, uint16 opcodeNumber=0)
Lookup opcode name for human understandable logging.
OpcodeTable clientOpcodeTable
boost::asio::ip::tcp::socket WorldSocketHandle
OpcodeTable serverOpcodeTable
@ MSG_VERIFY_CONNECTIVITY
@ CONFIG_MAX_OVERSPEED_PINGS
@ CONFIG_SESSION_ADD_DELAY
void GetRandomBytes(uint8 *buf, size_t len)
SkyFire::Impl::GenericHash< EVP_sha1, Constants::SHA1_DIGEST_LENGTH_BYTES > SHA1
std::array< uint8, S > GetRandomBytes()
void CloseTcpSocket(boost::asio::ip::tcp::socket &socket)
void SleepForMicroseconds(uint32 microseconds)
@ RBAC_PERM_SKIP_CHECK_OVERSPEED_PING
LoginDatabaseWorkerPool LoginDatabase
std::string CharacterName
std::string RemoteAddress