Skip to content

Commit

Permalink
Core/Network: Refactored socket code, moved common operations to base…
Browse files Browse the repository at this point in the history
… Socket class
  • Loading branch information
Shauren committed Jul 26, 2014
1 parent 30e1342 commit c1b1ba4
Show file tree
Hide file tree
Showing 7 changed files with 344 additions and 270 deletions.
240 changes: 123 additions & 117 deletions src/server/authserver/Server/AuthSession.cpp

Large diffs are not rendered by default.

59 changes: 36 additions & 23 deletions src/server/authserver/Server/AuthSession.h
Expand Up @@ -19,46 +19,52 @@
#ifndef __AUTHSESSION_H__
#define __AUTHSESSION_H__

#include <memory>
#include <boost/asio/ip/tcp.hpp>
#include "Common.h"
#include "Socket.h"
#include "BigNumber.h"
#include <memory>
#include <boost/asio/ip/tcp.hpp>

using boost::asio::ip::tcp;

const size_t bufferSize = 4096;
struct AuthHandler;
class ByteBuffer;

#define BUFFER_SIZE 4096

class AuthSession : public std::enable_shared_from_this < AuthSession >
class AuthSession : public Socket<AuthSession>
{

public:
AuthSession(tcp::socket&& socket) : _socket(std::move(socket))
static std::unordered_map<uint8, AuthHandler> InitHandlers();

AuthSession(tcp::socket&& socket) : Socket(std::move(socket), 1)
{
N.SetHexStr("894B645E89E1535BBDAD5B8B290650530801B18EBFBF5E8FAB3C82872A3E9BB7");
g.SetDword(7);
}

void Start()
void Start() override
{
AsyncReadHeader();
}

bool _HandleLogonChallenge();
bool _HandleLogonProof();
bool _HandleReconnectChallenge();
bool _HandleReconnectProof();
bool _HandleRealmList();
using Socket<AuthSession>::AsyncWrite;
void AsyncWrite(ByteBuffer const& packet);

const std::string GetRemoteIpAddress() const { return _socket.remote_endpoint().address().to_string(); };
unsigned short GetRemotePort() const { return _socket.remote_endpoint().port(); }
protected:
void ReadHeaderHandler(boost::system::error_code error, size_t transferedBytes) override;
void ReadDataHandler(boost::system::error_code error, size_t transferedBytes) override;

private:
void AsyncReadHeader();
void AsyncReadData(bool (AuthSession::*handler)(), size_t dataSize, size_t bufferOffset);
void AsyncWrite(size_t length);
bool HandleLogonChallenge();
bool HandleLogonProof();
bool HandleReconnectChallenge();
bool HandleReconnectProof();
bool HandleRealmList();

void CloseSocket();
//data transfer handle for patch
bool HandleXferResume();
bool HandleXferCancel();
bool HandleXferAccept();

void SetVSFields(const std::string& rI);

Expand All @@ -67,10 +73,6 @@ class AuthSession : public std::enable_shared_from_this < AuthSession >
BigNumber K;
BigNumber _reconnectProof;

tcp::socket _socket;
char _readBuffer[BUFFER_SIZE];
char _writeBuffer[BUFFER_SIZE];

bool _isAuthenticated;
std::string _tokenKey;
std::string _login;
Expand All @@ -82,4 +84,15 @@ class AuthSession : public std::enable_shared_from_this < AuthSession >
AccountTypes _accountSecurityLevel;
};

#pragma pack(push, 1)

struct AuthHandler
{
uint32 status;
size_t packetSize;
bool (AuthSession::*handler)();
};

#pragma pack(pop)

#endif
1 change: 1 addition & 0 deletions src/server/game/CMakeLists.txt
Expand Up @@ -123,6 +123,7 @@ include_directories(
${CMAKE_SOURCE_DIR}/src/server/shared/Dynamic/LinkedReference
${CMAKE_SOURCE_DIR}/src/server/shared/Dynamic
${CMAKE_SOURCE_DIR}/src/server/shared/Logging
${CMAKE_SOURCE_DIR}/src/server/shared/Networking
${CMAKE_SOURCE_DIR}/src/server/shared/Packets
${CMAKE_SOURCE_DIR}/src/server/shared/Threading
${CMAKE_SOURCE_DIR}/src/server/shared/Utilities
Expand Down
2 changes: 1 addition & 1 deletion src/server/game/Server/WorldSession.cpp
Expand Up @@ -130,7 +130,7 @@ WorldSession::WorldSession(uint32 id, std::shared_ptr<WorldSocket> sock, Account

if (sock)
{
m_Address = sock->GetRemoteIpAddress();
m_Address = sock->GetRemoteIpAddress().to_string();
ResetTimeOutTime();
LoginDatabase.PExecute("UPDATE account SET online = 1 WHERE id = %u;", GetAccountId()); // One-time query
}
Expand Down
178 changes: 66 additions & 112 deletions src/server/game/Server/WorldSocket.cpp
Expand Up @@ -31,7 +31,7 @@ using boost::asio::ip::tcp;
using boost::asio::streambuf;

WorldSocket::WorldSocket(tcp::socket&& socket)
: _socket(std::move(socket)), _authSeed(rand32()), _OverSpeedPings(0), _worldSession(nullptr)
: Socket(std::move(socket), sizeof(ClientPktHeader)), _authSeed(rand32()), _OverSpeedPings(0), _worldSession(nullptr)
{
}

Expand All @@ -58,113 +58,97 @@ void WorldSocket::HandleSendAuthSession()
AsyncWrite(packet);
}

void WorldSocket::AsyncReadHeader()
void WorldSocket::ReadHeaderHandler(boost::system::error_code error, size_t transferedBytes)
{
auto self(shared_from_this());
_socket.async_read_some(boost::asio::buffer(_readBuffer, sizeof(ClientPktHeader)), [this, self](boost::system::error_code error, size_t transferedBytes)
if (!error && transferedBytes == sizeof(ClientPktHeader))
{
if (!error && transferedBytes == sizeof(ClientPktHeader))
{
ClientPktHeader* header = (ClientPktHeader*)&_readBuffer;

if (_worldSession)
_authCrypt.DecryptRecv((uint8*)header, sizeof(ClientPktHeader));
_authCrypt.DecryptRecv(GetReadBuffer(), sizeof(ClientPktHeader));

EndianConvertReverse(header->size);
EndianConvert(header->cmd);
ClientPktHeader* header = reinterpret_cast<ClientPktHeader*>(GetReadBuffer());
EndianConvertReverse(header->size);
EndianConvert(header->cmd);

AsyncReadData(header->size - sizeof(header->cmd));
}
else
{
// _socket.is_open() till returns true even after calling close()
CloseSocket();
}
});
AsyncReadData(header->size - sizeof(header->cmd), sizeof(ClientPktHeader));
}
else
CloseSocket();
}

void WorldSocket::AsyncReadData(size_t dataSize)
void WorldSocket::ReadDataHandler(boost::system::error_code error, size_t transferedBytes)
{
auto self(shared_from_this());
_socket.async_read_some(boost::asio::buffer(&_readBuffer[sizeof(ClientPktHeader)], dataSize), [this, dataSize, self](boost::system::error_code error, size_t transferedBytes)
ClientPktHeader* header = reinterpret_cast<ClientPktHeader*>(GetReadBuffer());

if (!error && transferedBytes == (header->size - sizeof(header->cmd)))
{
if (!error && transferedBytes == dataSize)
{
ClientPktHeader* header = (ClientPktHeader*)&_readBuffer;
header->size -= sizeof(header->cmd);

header->size -= sizeof(header->cmd);
uint16 opcode = uint16(header->cmd);

uint16 opcode = (uint16)header->cmd;
std::string opcodeName = GetOpcodeNameForLogging(opcode);

std::string opcodeName = GetOpcodeNameForLogging(opcode);
WorldPacket packet(opcode, header->size);

WorldPacket packet(opcode, header->size);
if (header->size > 0)
{
packet.resize(header->size);

if (header->size > 0)
{
packet.resize(header->size);
std::memcpy(packet.contents(), &(GetReadBuffer()[sizeof(ClientPktHeader)]), header->size);
}

std::memcpy(packet.contents(), &_readBuffer[sizeof(ClientPktHeader)], header->size);
}
if (sPacketLog->CanLogPacket())
sPacketLog->LogPacket(packet, CLIENT_TO_SERVER);

if (sPacketLog->CanLogPacket())
sPacketLog->LogPacket(packet, CLIENT_TO_SERVER);
TC_LOG_TRACE("network.opcode", "C->S: %s %s", (_worldSession ? _worldSession->GetPlayerInfo() : GetRemoteIpAddress().to_string()).c_str(), GetOpcodeNameForLogging(opcode).c_str());

TC_LOG_TRACE("network.opcode", "C->S: %s %s", (_worldSession ? _worldSession->GetPlayerInfo() : GetRemoteIpAddress()).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;
}

switch (opcode)
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)
{
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:
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.opcode", "ProcessIncoming: Client not authed opcode = %u", uint32(opcode));
break;
}
}

AsyncReadHeader();
}
else
{
// _socket.is_open() till returns true even after calling close()
CloseSocket();
// 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));
break;
}
}
});

AsyncReadHeader();
}
else
CloseSocket();
}

void WorldSocket::AsyncWrite(WorldPacket const& packet)
{
if (sPacketLog->CanLogPacket())
sPacketLog->LogPacket(packet, SERVER_TO_CLIENT);

TC_LOG_TRACE("network.opcode", "S->C: %s %s", (_worldSession ? _worldSession->GetPlayerInfo() : GetRemoteIpAddress()).c_str(), GetOpcodeNameForLogging(packet.GetOpcode()).c_str());
TC_LOG_TRACE("network.opcode", "S->C: %s %s", (_worldSession ? _worldSession->GetPlayerInfo() : GetRemoteIpAddress().to_string()).c_str(), GetOpcodeNameForLogging(packet.GetOpcode()).c_str());

ServerPktHeader header(packet.size() + 2, packet.GetOpcode());

Expand All @@ -185,25 +169,6 @@ void WorldSocket::AsyncWrite(WorldPacket const& packet)
AsyncWrite(_writeQueue.front());
}

void WorldSocket::AsyncWrite(std::vector<uint8> const& data)
{
auto self(shared_from_this());
boost::asio::async_write(_socket, boost::asio::buffer(data), [this, self](boost::system::error_code error, std::size_t /*length*/)
{
if (!error)
{
std::lock_guard<std::mutex> deleteGuard(_writeLock);

_writeQueue.pop();

if (!_writeQueue.empty())
AsyncWrite(_writeQueue.front());
}
else
CloseSocket();
});
}

void WorldSocket::HandleAuthSession(WorldPacket& recvPacket)
{
uint8 digest[20];
Expand All @@ -223,7 +188,7 @@ void WorldSocket::HandleAuthSession(WorldPacket& recvPacket)
if (sWorld->IsClosed())
{
SendAuthResponseError(AUTH_REJECT);
TC_LOG_ERROR("network", "WorldSocket::HandleAuthSession: World closed, denying client (%s).", GetRemoteIpAddress().c_str());
TC_LOG_ERROR("network", "WorldSocket::HandleAuthSession: World closed, denying client (%s).", GetRemoteIpAddress().to_string().c_str());
return;
}

Expand Down Expand Up @@ -270,7 +235,7 @@ void WorldSocket::HandleAuthSession(WorldPacket& recvPacket)
expansion = world_expansion;

// For hook purposes, we get Remoteaddress at this point.
std::string address = GetRemoteIpAddress();
std::string address = GetRemoteIpAddress().to_string();

// As we don't know if attempted login process by ip works, we update last_attempt_ip right away
stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_LAST_ATTEMPT_IP);
Expand Down Expand Up @@ -471,7 +436,7 @@ void WorldSocket::HandlePing(WorldPacket& recvPacket)
if (_worldSession && !_worldSession->HasPermission(rbac::RBAC_PERM_SKIP_CHECK_OVERSPEED_PING))
{
TC_LOG_ERROR("network", "WorldSocket::HandlePing: %s kicked for over-speed pings (address: %s)",
_worldSession->GetPlayerInfo().c_str(), GetRemoteIpAddress().c_str());
_worldSession->GetPlayerInfo().c_str(), GetRemoteIpAddress().to_string().c_str());

CloseSocket();
return;
Expand All @@ -489,8 +454,7 @@ void WorldSocket::HandlePing(WorldPacket& recvPacket)
}
else
{
TC_LOG_ERROR("network", "WorldSocket::HandlePing: peer sent CMSG_PING, but is not authenticated or got recently kicked, address = %s",
GetRemoteIpAddress().c_str());
TC_LOG_ERROR("network", "WorldSocket::HandlePing: peer sent CMSG_PING, but is not authenticated or got recently kicked, address = %s", GetRemoteIpAddress().to_string().c_str());

CloseSocket();
return;
Expand All @@ -500,13 +464,3 @@ void WorldSocket::HandlePing(WorldPacket& recvPacket)
packet << ping;
return AsyncWrite(packet);
}

void WorldSocket::CloseSocket()
{
boost::system::error_code socketError;
_socket.close(socketError);
if (socketError)
TC_LOG_DEBUG("network", "WorldSocket::CloseSocket: Player '%s' (%s) errored when closing socket: %i (%s)",
_worldSession ? _worldSession->GetPlayerInfo().c_str() : "unknown", GetRemoteIpAddress().c_str(),
socketError.value(), socketError.message().c_str());
}

1 comment on commit c1b1ba4

@jaredjones
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Forgot std::shared_from_this. So, Travis is failing.

Please sign in to comment.