/*
* This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
*
* 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 .
*/
#ifndef TRINITYCORE_WORLD_SOCKET_H
#define TRINITYCORE_WORLD_SOCKET_H
#include "AsyncCallbackProcessor.h"
#include "AuthDefines.h"
#include "DatabaseEnvFwd.h"
#include "MessageBuffer.h"
#include "Socket.h"
#include "WorldPacket.h"
#include "WorldPacketCrypt.h"
#include "MPSCQueue.h"
#include
#include
#include
namespace JSON::RealmList
{
class RealmJoinTicket;
}
typedef struct z_stream_s z_stream;
class EncryptablePacket;
class WorldPacket;
class WorldSession;
enum ConnectionType : int8;
enum OpcodeClient : uint32;
class EncryptablePacket : public WorldPacket
{
public:
EncryptablePacket(WorldPacket const& packet, bool encrypt) : WorldPacket(packet), _encrypt(encrypt)
{
SocketQueueLink.store(nullptr, std::memory_order_relaxed);
}
bool NeedsEncryption() const { return _encrypt; }
std::atomic SocketQueueLink;
private:
bool _encrypt;
};
namespace WorldPackets
{
class ServerPacket;
namespace Auth
{
class AuthSession;
class AuthContinuedSession;
class ConnectToFailed;
class Ping;
}
}
#pragma pack(push, 1)
struct PacketHeader
{
uint32 Size;
uint8 Tag[12];
bool IsValidSize() const { return Size < 0x10000; }
};
struct IncomingPacketHeader : PacketHeader
{
uint32 EncryptedOpcode;
};
#pragma pack(pop)
class TC_GAME_API WorldSocket final : public Trinity::Net::Socket<>
{
static uint32 const MinSizeForCompression;
static std::array const AuthCheckSeed;
static std::array const SessionKeySeed;
static std::array const ContinuedSessionSeed;
static std::array const EncryptionKeySeed;
using BaseSocket = Socket;
public:
WorldSocket(Trinity::Net::IoContextTcpSocket&& socket);
~WorldSocket();
WorldSocket(WorldSocket const& right) = delete;
WorldSocket(WorldSocket&& right) = delete;
WorldSocket& operator=(WorldSocket const& right) = delete;
WorldSocket& operator=(WorldSocket&& right) = delete;
void Start() override;
bool Update() override;
void SendPacket(WorldPacket const& packet);
ConnectionType GetConnectionType() const { return _type; }
void SendAuthResponseError(uint32 code);
void SetWorldSession(WorldSession* session);
void SetSendBufferSize(std::size_t sendBufferSize) { _sendBufferSize = sendBufferSize; }
void OnClose() override;
Trinity::Net::SocketReadCallbackResult ReadHandler() override;
void QueueQuery(QueryCallback&& queryCallback);
void SendAuthSession();
bool InitializeCompression();
protected:
bool ReadHeaderHandler();
enum class ReadDataHandlerResult
{
Ok = 0,
Error = 1,
WaitingForQuery = 2
};
ReadDataHandlerResult ReadDataHandler();
private:
/// writes network.opcode log
/// accessing WorldSession is not threadsafe, only do it when holding _worldSessionLock
void LogOpcodeText(OpcodeClient opcode, std::unique_lock const& guard) const;
/// sends and logs network.opcode without accessing WorldSession
void SendPacketAndLogOpcode(WorldPacket const& packet);
void WritePacketToBuffer(EncryptablePacket const& packet, MessageBuffer& buffer);
uint32 CompressPacket(uint8* buffer, WorldPacket const& packet);
void HandleAuthSession(std::shared_ptr authSession);
void HandleAuthSessionCallback(std::shared_ptr authSession,
std::shared_ptr joinTicket, PreparedQueryResult result);
void HandleAuthContinuedSession(std::shared_ptr authSession);
void HandleAuthContinuedSessionCallback(std::shared_ptr authSession, PreparedQueryResult result);
void LoadSessionPermissionsCallback(PreparedQueryResult result);
void HandleConnectToFailed(WorldPackets::Auth::ConnectToFailed& connectToFailed);
bool HandlePing(WorldPackets::Auth::Ping& ping);
void HandleEnterEncryptedModeAck();
ConnectionType _type;
uint64 _key;
std::array _serverChallenge;
WorldPacketCrypt _authCrypt;
SessionKey _sessionKey;
std::array _encryptKey;
TimePoint _LastPingTime;
uint32 _OverSpeedPings;
std::mutex _worldSessionLock;
WorldSession* _worldSession;
bool _authed;
bool _canRequestHotfixes;
MessageBuffer _headerBuffer;
MessageBuffer _packetBuffer;
MPSCQueue _bufferQueue;
std::size_t _sendBufferSize;
z_stream* _compressionStream;
QueryCallbackProcessor _queryProcessor;
std::string _ipCountry;
};
#endif