mirror of
https://github.com/TrinityCore/TrinityCore.git
synced 2026-01-16 07:30:42 +01:00
Core/NetworkIO: Allow receiving packets bigger than buffer size and properly handle situations where not entire packet was read in one go
Core/Authserver: Restored authenticator functionality
This commit is contained in:
@@ -21,6 +21,7 @@
|
||||
#include "AuthCodes.h"
|
||||
#include "Database/DatabaseEnv.h"
|
||||
#include "SHA1.h"
|
||||
#include "TOTP.h"
|
||||
#include "openssl/crypto.h"
|
||||
#include "Configuration/Config.h"
|
||||
#include "RealmList.h"
|
||||
@@ -52,7 +53,6 @@ enum eStatus
|
||||
|
||||
typedef struct AUTH_LOGON_CHALLENGE_C
|
||||
{
|
||||
uint8 cmd;
|
||||
uint8 error;
|
||||
uint16 size;
|
||||
uint8 gamename[4];
|
||||
@@ -71,7 +71,6 @@ typedef struct AUTH_LOGON_CHALLENGE_C
|
||||
|
||||
typedef struct AUTH_LOGON_PROOF_C
|
||||
{
|
||||
uint8 cmd;
|
||||
uint8 A[32];
|
||||
uint8 M1[20];
|
||||
uint8 crc_hash[20];
|
||||
@@ -99,7 +98,6 @@ typedef struct AUTH_LOGON_PROOF_S_OLD
|
||||
|
||||
typedef struct AUTH_RECONNECT_PROOF_C
|
||||
{
|
||||
uint8 cmd;
|
||||
uint8 R1[16];
|
||||
uint8 R2[20];
|
||||
uint8 R3[20];
|
||||
@@ -114,10 +112,10 @@ enum class BufferSizes : uint32
|
||||
SRP_6_S = 0x20,
|
||||
};
|
||||
|
||||
#define REALM_LIST_PACKET_SIZE 5
|
||||
#define XFER_ACCEPT_SIZE 1
|
||||
#define XFER_RESUME_SIZE 9
|
||||
#define XFER_CANCEL_SIZE 1
|
||||
#define REALM_LIST_PACKET_SIZE 4
|
||||
#define XFER_ACCEPT_SIZE 0
|
||||
#define XFER_RESUME_SIZE 8
|
||||
#define XFER_CANCEL_SIZE 0
|
||||
|
||||
std::unordered_map<uint8, AuthHandler> AuthSession::InitHandlers()
|
||||
{
|
||||
@@ -137,44 +135,36 @@ std::unordered_map<uint8, AuthHandler> AuthSession::InitHandlers()
|
||||
|
||||
std::unordered_map<uint8, AuthHandler> const Handlers = AuthSession::InitHandlers();
|
||||
|
||||
void AuthSession::ReadHeaderHandler(boost::system::error_code error, size_t transferedBytes)
|
||||
void AuthSession::ReadHeaderHandler()
|
||||
{
|
||||
if (!error && transferedBytes == 1)
|
||||
uint8 cmd = GetHeaderBuffer()[0];
|
||||
auto itr = Handlers.find(cmd);
|
||||
if (itr != Handlers.end())
|
||||
{
|
||||
uint8 cmd = GetReadBuffer()[0];
|
||||
auto itr = Handlers.find(cmd);
|
||||
if (itr != Handlers.end())
|
||||
// Handle dynamic size packet
|
||||
if (cmd == AUTH_LOGON_CHALLENGE || cmd == AUTH_RECONNECT_CHALLENGE)
|
||||
{
|
||||
// Handle dynamic size packet
|
||||
if (cmd == AUTH_LOGON_CHALLENGE || cmd == AUTH_RECONNECT_CHALLENGE)
|
||||
{
|
||||
ReadData(sizeof(uint8) + sizeof(uint16), sizeof(cmd)); //error + size
|
||||
sAuthLogonChallenge_C* challenge = reinterpret_cast<sAuthLogonChallenge_C*>(GetReadBuffer());
|
||||
ReadData(sizeof(uint8) + sizeof(uint16)); //error + size
|
||||
sAuthLogonChallenge_C* challenge = reinterpret_cast<sAuthLogonChallenge_C*>(GetDataBuffer());
|
||||
|
||||
AsyncReadData(challenge->size, sizeof(uint8) + sizeof(uint8) + sizeof(uint16)); // cmd + error + size
|
||||
}
|
||||
else
|
||||
AsyncReadData(itr->second.packetSize, sizeof(uint8));
|
||||
AsyncReadData(challenge->size);
|
||||
}
|
||||
else
|
||||
AsyncReadData(itr->second.packetSize);
|
||||
}
|
||||
else
|
||||
CloseSocket();
|
||||
}
|
||||
|
||||
void AuthSession::ReadDataHandler(boost::system::error_code error, size_t transferedBytes)
|
||||
void AuthSession::ReadDataHandler()
|
||||
{
|
||||
if (!error && transferedBytes > 0)
|
||||
if (!(*this.*Handlers.at(GetHeaderBuffer()[0]).handler)())
|
||||
{
|
||||
if (!(*this.*Handlers.at(GetReadBuffer()[0]).handler)())
|
||||
{
|
||||
CloseSocket();
|
||||
return;
|
||||
}
|
||||
|
||||
AsyncReadHeader();
|
||||
}
|
||||
else
|
||||
CloseSocket();
|
||||
return;
|
||||
}
|
||||
|
||||
AsyncReadHeader();
|
||||
}
|
||||
|
||||
void AuthSession::AsyncWrite(ByteBuffer& packet)
|
||||
@@ -191,7 +181,7 @@ void AuthSession::AsyncWrite(ByteBuffer& packet)
|
||||
|
||||
bool AuthSession::HandleLogonChallenge()
|
||||
{
|
||||
sAuthLogonChallenge_C* challenge = reinterpret_cast<sAuthLogonChallenge_C*>(GetReadBuffer());
|
||||
sAuthLogonChallenge_C* challenge = reinterpret_cast<sAuthLogonChallenge_C*>(GetDataBuffer());
|
||||
|
||||
//TC_LOG_DEBUG("server.authserver", "[AuthChallenge] got full packet, %#04x bytes", challenge->size);
|
||||
TC_LOG_DEBUG("server.authserver", "[AuthChallenge] name(%d): '%s'", challenge->I_len, challenge->I);
|
||||
@@ -410,7 +400,7 @@ bool AuthSession::HandleLogonProof()
|
||||
|
||||
TC_LOG_DEBUG("server.authserver", "Entering _HandleLogonProof");
|
||||
// Read the packet
|
||||
sAuthLogonProof_C *logonProof = reinterpret_cast<sAuthLogonProof_C*>(GetReadBuffer());
|
||||
sAuthLogonProof_C *logonProof = reinterpret_cast<sAuthLogonProof_C*>(GetDataBuffer());
|
||||
|
||||
// If the client has no valid version
|
||||
if (_expversion == NO_VALID_EXP_FLAG)
|
||||
@@ -522,17 +512,13 @@ bool AuthSession::HandleLogonProof()
|
||||
// Check auth token
|
||||
if ((logonProof->securityFlags & 0x04) || !_tokenKey.empty())
|
||||
{
|
||||
// TODO To be fixed
|
||||
|
||||
/*
|
||||
uint8 size;
|
||||
socket().recv((char*)&size, 1);
|
||||
char* token = new char[size + 1];
|
||||
ReadData(1);
|
||||
uint8 size = *(GetDataBuffer() + sizeof(sAuthLogonProof_C));
|
||||
ReadData(size);
|
||||
char* token = reinterpret_cast<char*>(GetDataBuffer() + sizeof(sAuthLogonProof_C) + sizeof(size));
|
||||
token[size] = '\0';
|
||||
socket().recv(token, size);
|
||||
unsigned int validToken = TOTP::GenerateToken(_tokenKey.c_str());
|
||||
unsigned int incomingToken = atoi(token);
|
||||
delete[] token;
|
||||
if (validToken != incomingToken)
|
||||
{
|
||||
ByteBuffer packet;
|
||||
@@ -542,7 +528,7 @@ bool AuthSession::HandleLogonProof()
|
||||
packet << uint8(0);
|
||||
AsyncWrite(packet);
|
||||
return false;
|
||||
}*/
|
||||
}
|
||||
}
|
||||
|
||||
ByteBuffer packet;
|
||||
@@ -650,7 +636,7 @@ bool AuthSession::HandleLogonProof()
|
||||
bool AuthSession::HandleReconnectChallenge()
|
||||
{
|
||||
TC_LOG_DEBUG("server.authserver", "Entering _HandleReconnectChallenge");
|
||||
sAuthLogonChallenge_C* challenge = reinterpret_cast<sAuthLogonChallenge_C*>(GetReadBuffer());
|
||||
sAuthLogonChallenge_C* challenge = reinterpret_cast<sAuthLogonChallenge_C*>(GetDataBuffer());
|
||||
|
||||
//TC_LOG_DEBUG("server.authserver", "[AuthChallenge] got full packet, %#04x bytes", challenge->size);
|
||||
TC_LOG_DEBUG("server.authserver", "[AuthChallenge] name(%d): '%s'", challenge->I_len, challenge->I);
|
||||
@@ -701,7 +687,7 @@ bool AuthSession::HandleReconnectChallenge()
|
||||
bool AuthSession::HandleReconnectProof()
|
||||
{
|
||||
TC_LOG_DEBUG("server.authserver", "Entering _HandleReconnectProof");
|
||||
sAuthReconnectProof_C *reconnectProof = reinterpret_cast<sAuthReconnectProof_C*>(GetReadBuffer());
|
||||
sAuthReconnectProof_C *reconnectProof = reinterpret_cast<sAuthReconnectProof_C*>(GetDataBuffer());
|
||||
|
||||
if (_login.empty() || !_reconnectProof.GetNumBytes() || !K.GetNumBytes())
|
||||
return false;
|
||||
|
||||
@@ -53,8 +53,8 @@ public:
|
||||
void AsyncWrite(ByteBuffer& packet);
|
||||
|
||||
protected:
|
||||
void ReadHeaderHandler(boost::system::error_code error, size_t transferedBytes) override;
|
||||
void ReadDataHandler(boost::system::error_code error, size_t transferedBytes) override;
|
||||
void ReadHeaderHandler() override;
|
||||
void ReadDataHandler() override;
|
||||
|
||||
private:
|
||||
bool HandleLogonChallenge();
|
||||
|
||||
@@ -54,89 +54,72 @@ void WorldSocket::HandleSendAuthSession()
|
||||
AsyncWrite(packet);
|
||||
}
|
||||
|
||||
void WorldSocket::ReadHeaderHandler(boost::system::error_code error, size_t transferedBytes)
|
||||
void WorldSocket::ReadHeaderHandler()
|
||||
{
|
||||
if (!error && transferedBytes == sizeof(ClientPktHeader))
|
||||
{
|
||||
_authCrypt.DecryptRecv(GetReadBuffer(), sizeof(ClientPktHeader));
|
||||
_authCrypt.DecryptRecv(GetHeaderBuffer(), sizeof(ClientPktHeader));
|
||||
|
||||
ClientPktHeader* header = reinterpret_cast<ClientPktHeader*>(GetReadBuffer());
|
||||
EndianConvertReverse(header->size);
|
||||
EndianConvert(header->cmd);
|
||||
ClientPktHeader* header = reinterpret_cast<ClientPktHeader*>(GetHeaderBuffer());
|
||||
EndianConvertReverse(header->size);
|
||||
EndianConvert(header->cmd);
|
||||
|
||||
AsyncReadData(header->size - sizeof(header->cmd), sizeof(ClientPktHeader));
|
||||
}
|
||||
else
|
||||
CloseSocket();
|
||||
AsyncReadData(header->size - sizeof(header->cmd));
|
||||
}
|
||||
|
||||
void WorldSocket::ReadDataHandler(boost::system::error_code error, size_t transferedBytes)
|
||||
void WorldSocket::ReadDataHandler()
|
||||
{
|
||||
ClientPktHeader* header = reinterpret_cast<ClientPktHeader*>(GetReadBuffer());
|
||||
ClientPktHeader* header = reinterpret_cast<ClientPktHeader*>(GetHeaderBuffer());
|
||||
|
||||
if (!error && transferedBytes == (header->size - sizeof(header->cmd)))
|
||||
header->size -= sizeof(header->cmd);
|
||||
|
||||
uint16 opcode = uint16(header->cmd);
|
||||
|
||||
std::string opcodeName = GetOpcodeNameForLogging(opcode);
|
||||
|
||||
WorldPacket packet(opcode, MoveData());
|
||||
|
||||
if (sPacketLog->CanLogPacket())
|
||||
sPacketLog->LogPacket(packet, CLIENT_TO_SERVER, GetRemoteIpAddress(), GetRemotePort());
|
||||
|
||||
TC_LOG_TRACE("network.opcode", "C->S: %s %s", (_worldSession ? _worldSession->GetPlayerInfo() : GetRemoteIpAddress().to_string()).c_str(), opcodeName.c_str());
|
||||
|
||||
switch (opcode)
|
||||
{
|
||||
header->size -= sizeof(header->cmd);
|
||||
|
||||
uint16 opcode = uint16(header->cmd);
|
||||
|
||||
std::string opcodeName = GetOpcodeNameForLogging(opcode);
|
||||
|
||||
WorldPacket packet(opcode, header->size);
|
||||
|
||||
if (header->size > 0)
|
||||
{
|
||||
packet.resize(header->size);
|
||||
|
||||
std::memcpy(packet.contents(), &(GetReadBuffer()[sizeof(ClientPktHeader)]), header->size);
|
||||
}
|
||||
|
||||
if (sPacketLog->CanLogPacket())
|
||||
sPacketLog->LogPacket(packet, CLIENT_TO_SERVER, GetRemoteIpAddress(), GetRemotePort());
|
||||
|
||||
TC_LOG_TRACE("network.opcode", "C->S: %s %s", (_worldSession ? _worldSession->GetPlayerInfo() : GetRemoteIpAddress().to_string()).c_str(), GetOpcodeNameForLogging(opcode).c_str());
|
||||
|
||||
switch (opcode)
|
||||
{
|
||||
case CMSG_PING:
|
||||
HandlePing(packet);
|
||||
break;
|
||||
case CMSG_AUTH_SESSION:
|
||||
if (_worldSession)
|
||||
{
|
||||
TC_LOG_ERROR("network", "WorldSocket::ProcessIncoming: received duplicate CMSG_AUTH_SESSION from %s", _worldSession->GetPlayerInfo().c_str());
|
||||
break;
|
||||
}
|
||||
|
||||
sScriptMgr->OnPacketReceive(shared_from_this(), packet);
|
||||
HandleAuthSession(packet);
|
||||
break;
|
||||
case CMSG_KEEP_ALIVE:
|
||||
TC_LOG_DEBUG("network", "%s", opcodeName.c_str());
|
||||
sScriptMgr->OnPacketReceive(shared_from_this(), packet);
|
||||
break;
|
||||
default:
|
||||
case CMSG_PING:
|
||||
HandlePing(packet);
|
||||
break;
|
||||
case CMSG_AUTH_SESSION:
|
||||
if (_worldSession)
|
||||
{
|
||||
if (!_worldSession)
|
||||
{
|
||||
TC_LOG_ERROR("network.opcode", "ProcessIncoming: Client not authed opcode = %u", uint32(opcode));
|
||||
break;
|
||||
}
|
||||
|
||||
// Our Idle timer will reset on any non PING opcodes.
|
||||
// Catches people idling on the login screen and any lingering ingame connections.
|
||||
_worldSession->ResetTimeOutTime();
|
||||
|
||||
// Copy the packet to the heap before enqueuing
|
||||
_worldSession->QueuePacket(new WorldPacket(packet));
|
||||
TC_LOG_ERROR("network", "WorldSocket::ProcessIncoming: received duplicate CMSG_AUTH_SESSION from %s", _worldSession->GetPlayerInfo().c_str());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
AsyncReadHeader();
|
||||
sScriptMgr->OnPacketReceive(shared_from_this(), packet);
|
||||
HandleAuthSession(packet);
|
||||
break;
|
||||
case CMSG_KEEP_ALIVE:
|
||||
TC_LOG_DEBUG("network", "%s", opcodeName.c_str());
|
||||
sScriptMgr->OnPacketReceive(shared_from_this(), packet);
|
||||
break;
|
||||
default:
|
||||
{
|
||||
if (!_worldSession)
|
||||
{
|
||||
TC_LOG_ERROR("network.opcode", "ProcessIncoming: Client not authed opcode = %u", uint32(opcode));
|
||||
break;
|
||||
}
|
||||
|
||||
// Our Idle timer will reset on any non PING opcodes.
|
||||
// Catches people idling on the login screen and any lingering ingame connections.
|
||||
_worldSession->ResetTimeOutTime();
|
||||
|
||||
// Copy the packet to the heap before enqueuing
|
||||
_worldSession->QueuePacket(new WorldPacket(std::move(packet)));
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
CloseSocket();
|
||||
|
||||
AsyncReadHeader();
|
||||
}
|
||||
|
||||
void WorldSocket::AsyncWrite(WorldPacket& packet)
|
||||
|
||||
@@ -108,8 +108,8 @@ public:
|
||||
void AsyncWrite(WorldPacket& packet);
|
||||
|
||||
protected:
|
||||
void ReadHeaderHandler(boost::system::error_code error, size_t transferedBytes) override;
|
||||
void ReadDataHandler(boost::system::error_code error, size_t transferedBytes) override;
|
||||
void ReadHeaderHandler() override;
|
||||
void ReadDataHandler() override;
|
||||
|
||||
private:
|
||||
void HandleSendAuthSession();
|
||||
|
||||
93
src/server/shared/Networking/MessageBuffer.h
Normal file
93
src/server/shared/Networking/MessageBuffer.h
Normal file
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __MESSAGEBUFFER_H_
|
||||
#define __MESSAGEBUFFER_H_
|
||||
|
||||
#include "Define.h"
|
||||
#include <vector>
|
||||
|
||||
class MessageBuffer
|
||||
{
|
||||
typedef std::vector<uint8>::size_type size_type;
|
||||
|
||||
public:
|
||||
MessageBuffer() : _wpos(0), _storage() { }
|
||||
|
||||
MessageBuffer(MessageBuffer const& right) : _wpos(right._wpos), _storage(right._storage) { }
|
||||
|
||||
MessageBuffer(MessageBuffer&& right) : _wpos(right._wpos), _storage(right.Move()) { }
|
||||
|
||||
void Reset()
|
||||
{
|
||||
_storage.clear();
|
||||
_wpos = 0;
|
||||
}
|
||||
|
||||
bool IsMessageReady() const { return _wpos == _storage.size(); }
|
||||
|
||||
size_type GetMissingSize() const { return _storage.size() - _wpos; }
|
||||
|
||||
uint8* Data() { return _storage.data(); }
|
||||
|
||||
void Grow(size_type bytes)
|
||||
{
|
||||
_storage.resize(_storage.size() + bytes);
|
||||
}
|
||||
|
||||
uint8* GetWritePointer() { return &_storage[_wpos]; }
|
||||
|
||||
void WriteCompleted(size_type bytes) { _wpos += bytes; }
|
||||
|
||||
void ResetWritePointer() { _wpos = 0; }
|
||||
|
||||
size_type GetSize() { return _storage.size(); }
|
||||
|
||||
std::vector<uint8>&& Move()
|
||||
{
|
||||
_wpos = 0;
|
||||
return std::move(_storage);
|
||||
}
|
||||
|
||||
MessageBuffer& operator=(MessageBuffer& right)
|
||||
{
|
||||
if (this != &right)
|
||||
{
|
||||
_wpos = right._wpos;
|
||||
_storage = right._storage;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
MessageBuffer& operator=(MessageBuffer&& right)
|
||||
{
|
||||
if (this != &right)
|
||||
{
|
||||
_wpos = right._wpos;
|
||||
_storage = right.Move();
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
size_type _wpos;
|
||||
std::vector<uint8> _storage;
|
||||
};
|
||||
|
||||
#endif /* __MESSAGEBUFFER_H_ */
|
||||
@@ -18,7 +18,7 @@
|
||||
#ifndef __SOCKET_H__
|
||||
#define __SOCKET_H__
|
||||
|
||||
#include "Define.h"
|
||||
#include "MessageBuffer.h"
|
||||
#include "Log.h"
|
||||
#include <vector>
|
||||
#include <mutex>
|
||||
@@ -28,19 +28,23 @@
|
||||
#include <type_traits>
|
||||
#include <boost/asio/ip/tcp.hpp>
|
||||
#include <boost/asio/write.hpp>
|
||||
#include <boost/asio/read.hpp>
|
||||
|
||||
using boost::asio::ip::tcp;
|
||||
|
||||
#define READ_BLOCK_SIZE 4096
|
||||
|
||||
template<class T, class PacketType>
|
||||
class Socket : public std::enable_shared_from_this<T>
|
||||
{
|
||||
typedef typename std::conditional<std::is_pointer<PacketType>::value, PacketType, PacketType const&>::type WritePacketType;
|
||||
|
||||
public:
|
||||
Socket(tcp::socket&& socket, std::size_t headerSize) : _socket(std::move(socket)), _headerSize(headerSize)
|
||||
Socket(tcp::socket&& socket, std::size_t headerSize) : _socket(std::move(socket))
|
||||
{
|
||||
_remotePort = _socket.remote_endpoint().port();
|
||||
_remoteAddress = _socket.remote_endpoint().address();
|
||||
_remotePort = _socket.remote_endpoint().port();
|
||||
_readHeaderBuffer.Grow(headerSize);
|
||||
}
|
||||
|
||||
virtual void Start() = 0;
|
||||
@@ -57,25 +61,39 @@ public:
|
||||
|
||||
void AsyncReadHeader()
|
||||
{
|
||||
_socket.async_read_some(boost::asio::buffer(_readBuffer, _headerSize), std::bind(&Socket<T, PacketType>::ReadHeaderHandlerInternal, this->shared_from_this(),
|
||||
std::placeholders::_1, std::placeholders::_2));
|
||||
_readHeaderBuffer.ResetWritePointer();
|
||||
_readDataBuffer.Reset();
|
||||
|
||||
AsyncReadMissingHeaderData();
|
||||
}
|
||||
|
||||
void AsyncReadData(std::size_t size, std::size_t bufferOffset)
|
||||
void AsyncReadData(std::size_t size)
|
||||
{
|
||||
_socket.async_read_some(boost::asio::buffer(&_readBuffer[bufferOffset], size), std::bind(&Socket<T, PacketType>::ReadDataHandlerInternal, this->shared_from_this(),
|
||||
std::placeholders::_1, std::placeholders::_2));
|
||||
if (!size)
|
||||
{
|
||||
// if this is a packet with 0 length body just invoke handler directly
|
||||
ReadDataHandler();
|
||||
return;
|
||||
}
|
||||
|
||||
_readDataBuffer.Grow(size);
|
||||
AsyncReadMissingData();
|
||||
}
|
||||
|
||||
void ReadData(std::size_t size, std::size_t bufferOffset)
|
||||
void ReadData(std::size_t size)
|
||||
{
|
||||
boost::system::error_code error;
|
||||
|
||||
_socket.read_some(boost::asio::buffer(&_readBuffer[bufferOffset], size), error);
|
||||
_readDataBuffer.Grow(size);
|
||||
|
||||
if (error)
|
||||
std::size_t bytesRead = boost::asio::read(_socket, boost::asio::buffer(_readDataBuffer.GetWritePointer(), size), error);
|
||||
|
||||
_readDataBuffer.WriteCompleted(bytesRead);
|
||||
|
||||
if (error || !_readDataBuffer.IsMessageReady())
|
||||
{
|
||||
TC_LOG_DEBUG("network", "Socket::ReadData: %s errored with: %i (%s)", GetRemoteIpAddress().to_string().c_str(), error.value(), error.message().c_str());
|
||||
TC_LOG_DEBUG("network", "Socket::ReadData: %s errored with: %i (%s)", GetRemoteIpAddress().to_string().c_str(), error.value(),
|
||||
error.message().c_str());
|
||||
|
||||
CloseSocket();
|
||||
}
|
||||
@@ -83,8 +101,8 @@ public:
|
||||
|
||||
void AsyncWrite(WritePacketType data)
|
||||
{
|
||||
boost::asio::async_write(_socket, boost::asio::buffer(data), std::bind(&Socket<T, PacketType>::WriteHandler, this->shared_from_this(), std::placeholders::_1,
|
||||
std::placeholders::_2));
|
||||
boost::asio::async_write(_socket, boost::asio::buffer(data), std::bind(&Socket<T, PacketType>::WriteHandler, this->shared_from_this(),
|
||||
std::placeholders::_1, std::placeholders::_2));
|
||||
}
|
||||
|
||||
bool IsOpen() const { return _socket.is_open(); }
|
||||
@@ -94,7 +112,7 @@ public:
|
||||
_socket.shutdown(boost::asio::socket_base::shutdown_both, shutdownError);
|
||||
if (shutdownError)
|
||||
TC_LOG_DEBUG("network", "Socket::CloseSocket: %s errored when shutting down socket: %i (%s)", GetRemoteIpAddress().to_string().c_str(),
|
||||
shutdownError.value(), shutdownError.message().c_str());
|
||||
shutdownError.value(), shutdownError.message().c_str());
|
||||
|
||||
boost::system::error_code error;
|
||||
_socket.close(error);
|
||||
@@ -103,18 +121,72 @@ public:
|
||||
error.value(), error.message().c_str());
|
||||
}
|
||||
|
||||
uint8* GetReadBuffer() { return _readBuffer; }
|
||||
virtual bool IsHeaderReady() const { return _readHeaderBuffer.IsMessageReady(); }
|
||||
virtual bool IsDataReady() const { return _readDataBuffer.IsMessageReady(); }
|
||||
|
||||
uint8* GetHeaderBuffer() { return _readHeaderBuffer.Data(); }
|
||||
uint8* GetDataBuffer() { return _readDataBuffer.Data(); }
|
||||
|
||||
MessageBuffer&& MoveHeader() { return std::move(_readHeaderBuffer); }
|
||||
MessageBuffer&& MoveData() { return std::move(_readDataBuffer); }
|
||||
|
||||
protected:
|
||||
virtual void ReadHeaderHandler(boost::system::error_code error, size_t transferedBytes) = 0;
|
||||
virtual void ReadDataHandler(boost::system::error_code error, size_t transferedBytes) = 0;
|
||||
virtual void ReadHeaderHandler() = 0;
|
||||
virtual void ReadDataHandler() = 0;
|
||||
|
||||
std::mutex _writeLock;
|
||||
std::queue<PacketType> _writeQueue;
|
||||
|
||||
private:
|
||||
void ReadHeaderHandlerInternal(boost::system::error_code error, size_t transferedBytes) { ReadHeaderHandler(error, transferedBytes); }
|
||||
void ReadDataHandlerInternal(boost::system::error_code error, size_t transferedBytes) { ReadDataHandler(error, transferedBytes); }
|
||||
void AsyncReadMissingHeaderData()
|
||||
{
|
||||
_socket.async_read_some(boost::asio::buffer(_readHeaderBuffer.GetWritePointer(), std::min<std::size_t>(READ_BLOCK_SIZE, _readHeaderBuffer.GetMissingSize())),
|
||||
std::bind(&Socket<T, PacketType>::ReadHeaderHandlerInternal, this->shared_from_this(), std::placeholders::_1, std::placeholders::_2));
|
||||
}
|
||||
|
||||
void AsyncReadMissingData()
|
||||
{
|
||||
_socket.async_read_some(boost::asio::buffer(_readDataBuffer.GetWritePointer(), std::min<std::size_t>(READ_BLOCK_SIZE, _readDataBuffer.GetMissingSize())),
|
||||
std::bind(&Socket<T, PacketType>::ReadDataHandlerInternal, this->shared_from_this(), std::placeholders::_1, std::placeholders::_2));
|
||||
}
|
||||
|
||||
void ReadHeaderHandlerInternal(boost::system::error_code error, size_t transferredBytes)
|
||||
{
|
||||
if (error)
|
||||
{
|
||||
CloseSocket();
|
||||
return;
|
||||
}
|
||||
|
||||
_readHeaderBuffer.WriteCompleted(transferredBytes);
|
||||
if (!IsHeaderReady())
|
||||
{
|
||||
// incomplete, read more
|
||||
AsyncReadMissingHeaderData();
|
||||
return;
|
||||
}
|
||||
|
||||
ReadHeaderHandler();
|
||||
}
|
||||
|
||||
void ReadDataHandlerInternal(boost::system::error_code error, size_t transferredBytes)
|
||||
{
|
||||
if (error)
|
||||
{
|
||||
CloseSocket();
|
||||
return;
|
||||
}
|
||||
|
||||
_readDataBuffer.WriteCompleted(transferredBytes);
|
||||
if (!IsDataReady())
|
||||
{
|
||||
// incomplete, read more
|
||||
AsyncReadMissingData();
|
||||
return;
|
||||
}
|
||||
|
||||
ReadDataHandler();
|
||||
}
|
||||
|
||||
void WriteHandler(boost::system::error_code error, size_t /*transferedBytes*/)
|
||||
{
|
||||
@@ -140,12 +212,11 @@ private:
|
||||
|
||||
tcp::socket _socket;
|
||||
|
||||
uint8 _readBuffer[4096];
|
||||
|
||||
uint16 _remotePort;
|
||||
boost::asio::ip::address _remoteAddress;
|
||||
uint16 _remotePort;
|
||||
|
||||
std::size_t _headerSize;
|
||||
MessageBuffer _readHeaderBuffer;
|
||||
MessageBuffer _readDataBuffer;
|
||||
};
|
||||
|
||||
#endif // __SOCKET_H__
|
||||
|
||||
@@ -17,11 +17,16 @@
|
||||
*/
|
||||
|
||||
#include "ByteBuffer.h"
|
||||
#include "MessageBuffer.h"
|
||||
#include "Common.h"
|
||||
#include "Log.h"
|
||||
|
||||
#include <sstream>
|
||||
|
||||
ByteBuffer::ByteBuffer(MessageBuffer&& buffer) : _rpos(0), _wpos(0), _storage(buffer.Move())
|
||||
{
|
||||
}
|
||||
|
||||
ByteBufferPositionException::ByteBufferPositionException(bool add, size_t pos,
|
||||
size_t size, size_t valueSize)
|
||||
{
|
||||
|
||||
@@ -34,6 +34,8 @@
|
||||
#include <math.h>
|
||||
#include <boost/asio/buffer.hpp>
|
||||
|
||||
class MessageBuffer;
|
||||
|
||||
// Root of ByteBuffer exception hierarchy
|
||||
class ByteBufferException : public std::exception
|
||||
{
|
||||
@@ -82,14 +84,12 @@ class ByteBuffer
|
||||
}
|
||||
|
||||
ByteBuffer(ByteBuffer&& buf) : _rpos(buf._rpos), _wpos(buf._wpos),
|
||||
_storage(std::move(buf._storage))
|
||||
{
|
||||
}
|
||||
_storage(std::move(buf._storage)) { }
|
||||
|
||||
ByteBuffer(ByteBuffer const& right) : _rpos(right._rpos), _wpos(right._wpos),
|
||||
_storage(right._storage)
|
||||
{
|
||||
}
|
||||
_storage(right._storage) { }
|
||||
|
||||
ByteBuffer(MessageBuffer&& buffer);
|
||||
|
||||
ByteBuffer& operator=(ByteBuffer const& right)
|
||||
{
|
||||
|
||||
@@ -51,6 +51,8 @@ class WorldPacket : public ByteBuffer
|
||||
return *this;
|
||||
}
|
||||
|
||||
WorldPacket(uint16 opcode, MessageBuffer&& buffer) : ByteBuffer(std::move(buffer)), m_opcode(opcode) { }
|
||||
|
||||
void Initialize(uint16 opcode, size_t newres=200)
|
||||
{
|
||||
clear();
|
||||
|
||||
Reference in New Issue
Block a user