Skip to content

Commit

Permalink
AsyncSocket non generic and offload to cpp file
Browse files Browse the repository at this point in the history
  • Loading branch information
0blu committed Aug 27, 2024
1 parent 8c3f71f commit 50c48e1
Show file tree
Hide file tree
Showing 11 changed files with 162 additions and 193 deletions.
4 changes: 2 additions & 2 deletions src/game/Protocol/WorldSocket.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ struct ServerPktHeader
#endif

WorldSocket::WorldSocket(IO::IoContext* ctx, IO::Networking::SocketDescriptor const& socketDescriptor)
: IO::Networking::AsyncSocket<WorldSocket>(ctx, socketDescriptor),
: IO::Networking::AsyncSocket(ctx, socketDescriptor),
m_lastPingTime(std::chrono::system_clock::time_point::min()),
m_overSpeedPings(0),
m_Session(nullptr),
Expand Down Expand Up @@ -127,7 +127,7 @@ void WorldSocket::DoRecvIncomingData()
return;
}

// by std::moving the content of the shared_ptr, we will seperate the unique_ptr out of the shared_ptr.
// by std::moving the content of the shared_ptr, we will separate the unique_ptr out of the shared_ptr.
if (self->_HandleCompleteReceivedPacket(std::move(*packetTmpSharedPtr)) == HandlerResult::Okay)
self->DoRecvIncomingData();
});
Expand Down
14 changes: 10 additions & 4 deletions src/game/Protocol/WorldSocket.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,18 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/

#ifndef MANGOS_GAME_SERVER_WORLDSOCKET_H
#define MANGOS_GAME_SERVER_WORLDSOCKET_H

#include "IO/Networking/AsyncSocket.h"
#include "Auth/AuthCrypt.h"
#include "Auth/BigNumber.h"
#include "WorldPacket.h"

#ifndef MANGOS_GAME_SERVER_WORLDSOCKET_H
#define MANGOS_GAME_SERVER_WORLDSOCKET_H
#include "WorldSession.h"

class WorldSocketMgr;

class WorldSocket : public IO::Networking::AsyncSocket<WorldSocket>
class WorldSocket : public std::enable_shared_from_this<WorldSocket>, private IO::Networking::AsyncSocket
{
friend WorldSocketMgr;

Expand Down Expand Up @@ -112,6 +113,11 @@ class WorldSocket : public IO::Networking::AsyncSocket<WorldSocket>
{
m_Session = nullptr;
}

// Making functions inherited from AsyncSocket public
using AsyncSocket::GetRemoteIpString;
using AsyncSocket::IsClosing;
using AsyncSocket::CloseSocket;
};

#endif // MANGOS_GAME_SERVER_WORLDSOCKET_H
2 changes: 1 addition & 1 deletion src/mangosd/remote/RemoteAccess/RASocket.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ static std::string const NEWLINE = "\r\n";
static std::string const PROMPT = "mangos>";

RASocket::RASocket(IO::IoContext* ctx, IO::Networking::SocketDescriptor const& socketDescriptor)
: IO::Networking::AsyncSocket<RASocket>(ctx, socketDescriptor),
: IO::Networking::AsyncSocket(ctx, socketDescriptor),
m_connectionState(ConnectionState::FreshConnection),
m_atLeastOnePacketWasReceived(false),
m_accountId(0),
Expand Down
2 changes: 1 addition & 1 deletion src/mangosd/remote/RemoteAccess/RASocket.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
#include <string>

/// Remote Administration socket
class RASocket : public IO::Networking::AsyncSocket<RASocket>
class RASocket : public std::enable_shared_from_this<RASocket>, private IO::Networking::AsyncSocket
{
public:
RASocket(IO::IoContext* ctx, IO::Networking::SocketDescriptor const& socketDescriptor);
Expand Down
2 changes: 1 addition & 1 deletion src/realmd/AuthSocket.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ typedef struct AuthHandler
std::array<uint8, 16> VersionChallenge = { { 0xBA, 0xA3, 0x1E, 0x99, 0xA0, 0x0B, 0x21, 0x57, 0xFC, 0x37, 0x3F, 0xB3, 0x69, 0xCD, 0xD2, 0xF1 } };

// Accept the connection and set the s random value for SRP6 // TODO where is this SRP6 done?
AuthSocket::AuthSocket(IO::IoContext* ctx, IO::Networking::SocketDescriptor const& socketDescriptor) : IO::Networking::AsyncSocket<AuthSocket>(ctx, socketDescriptor)
AuthSocket::AuthSocket(IO::IoContext* ctx, IO::Networking::SocketDescriptor const& socketDescriptor) : IO::Networking::AsyncSocket(ctx, socketDescriptor)
{
sLog.Out(LOG_BASIC, LOG_LVL_BASIC, "Accepting connection from '%s'", GetRemoteIpString().c_str());
}
Expand Down
2 changes: 1 addition & 1 deletion src/realmd/AuthSocket.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ enum LockFlag
struct sAuthLogonProof_C;

// Handle login commands
class AuthSocket : public IO::Networking::AsyncSocket<AuthSocket>
class AuthSocket : public std::enable_shared_from_this<AuthSocket>, private IO::Networking::AsyncSocket
{
public:
explicit AuthSocket(IO::IoContext* ctx, IO::Networking::SocketDescriptor const& clientAddress);
Expand Down
5 changes: 5 additions & 0 deletions src/shared/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,9 @@ set (shared_SRCS
IO/Networking/Internal.cpp
IO/Networking/AsyncServerListener.h
IO/Networking/AsyncSocket.h
IO/Networking/AsyncSocket.cpp
IO/Networking/AsyncSocket_posix.cpp
IO/Networking/AsyncSocket_windows.cpp
IO/Networking/NetworkError.h
IO/Networking/NetworkError.cpp
IO/Networking/SocketDescriptor.h
Expand Down Expand Up @@ -162,6 +165,7 @@ if(WIN32) # For window build: Exclude Unix/MacOS files
IO/Utils_Unix.h
IO/Context/IoContext_unix.cpp
IO/Context/IoContext_macos.cpp
IO/Networking/AsyncSocket_posix.cpp
IO/Timer/impl/unix/AsyncSystemTimer.cpp
IO/Timer/impl/unix/TimerHandle.cpp
IO/Filesystem/impl/unix/FileSystem.cpp
Expand All @@ -185,6 +189,7 @@ else()
revision.h
migrations_list.h
IO/Context/IoContext_windows.cpp
IO/Networking/AsyncSocket_windows.cpp
IO/Timer/impl/windows/AsyncSystemTimer.cpp
IO/Timer/impl/windows/TimerHandle.cpp
IO/Filesystem/impl/windows/FileSystem.cpp
Expand Down
49 changes: 49 additions & 0 deletions src/shared/IO/Networking/AsyncSocket.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#include "AsyncSocket.h"
#include "Log.h"
#include "Errors.h"

IO::Networking::AsyncSocket::~AsyncSocket() noexcept(false)
{
sLog.Out(LOG_NETWORK, LOG_LVL_DETAIL, "Destructor called ~AsyncSocket: No references left");
CloseSocket();

//#ifdef DEBUG
// Logic behind these checks:
// If the destructor is called, there should be no more std::shared_ptr<> references to this object
// Every Read(...) or Write(...) should use `shared_from_this()` if this is not the case, one of the following checks will fail
int state = m_atomicState.load(std::memory_order::memory_order_relaxed);
MANGOS_ASSERT(!(state & SocketStateFlags::CONTEXT_PRESENT));
MANGOS_ASSERT(!(state & SocketStateFlags::WRITE_PRESENT));
MANGOS_ASSERT(!(state & SocketStateFlags::READ_PRESENT));
//#endif // _DEBUG
}

bool IO::Networking::AsyncSocket::IsClosing() const
{
bool isClosing = m_atomicState.load(std::memory_order::memory_order_relaxed) & SHUTDOWN_PENDING;
return isClosing;
}

IO::Networking::IpEndpoint const& IO::Networking::AsyncSocket::GetRemoteEndpoint() const
{
return m_socket.m_peerEndpoint;
}

std::string IO::Networking::AsyncSocket::GetRemoteIpString() const
{
return GetRemoteEndpoint().ip.toString(); // Just gets the IP part e.g. "192.168.13.37"
}

void IO::Networking::AsyncSocket::ReadSkip(std::size_t skipSize, std::function<void(IO::NetworkError const&)> const& callback)
{
std::shared_ptr<std::vector<uint8_t>> skipBuffer(new std::vector<uint8_t>());
skipBuffer->resize(skipSize);
Read((char*)skipBuffer->data(), skipSize, [skipBuffer, callback](IO::NetworkError const& error, size_t)
{
// KEEP skipBuffer in scope!
// Do not remove skipBuffer before Read() is done, since we are transferring into it via async IO
// and since we are using a raw pointer, the Task has no knowledge about the lifetime of the std::vector
skipBuffer->clear();
callback(error);
});
}
76 changes: 7 additions & 69 deletions src/shared/IO/Networking/AsyncSocket.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,25 +9,18 @@
#include <functional>
#include <atomic>
#include "ByteBuffer.h"
#include "Errors.h"
#include "IO/Context/IoContext.h"
#include "IO/Networking/NetworkError.h"
#include "IO/Networking/SocketDescriptor.h"
#include "IO/Context/AsyncIoOperation.h"

namespace IO { namespace Networking {
template<typename SocketType>
class AsyncSocketListener;

// this socket is different in that it does not block on reads
template<typename SocketType>
class AsyncSocket : public std::enable_shared_from_this<SocketType>
/// You have to keep the instance alive while a transaction is running. Use [self = shared_from_this()] on every callback!
class AsyncSocket
#if defined(__linux__) || defined(__APPLE__)
, public IO::SystemIoEventReceiver
: public IO::SystemIoEventReceiver
#endif
{
friend class AsyncSocketListener<SocketType>;

public:
explicit AsyncSocket(IO::IoContext* ctx, SocketDescriptor socketDescriptor) : m_ctx(ctx), m_socket(std::move(socketDescriptor)) {}
~AsyncSocket() noexcept(false); // this destructor will throw if there is a pending transaction
Expand All @@ -44,6 +37,7 @@ namespace IO { namespace Networking {

/// Keep in mind to keep the source buffer in scope of the callback, otherwise random memory might get overwritten
/// Most of the time this is not an issue, since you want to process the incoming buffer
/// You have to keep the pointer alive until the callback is called. Use [self = shared_from_this()]
void Read(char* target, std::size_t size, std::function<void(IO::NetworkError const&, std::size_t)> const& callback);
void ReadSome(char* target, std::size_t maxSize, std::function<void(IO::NetworkError const&, size_t)> const& callback);
void ReadSkip(std::size_t skipSize, std::function<void(IO::NetworkError const&)> const& callback);
Expand All @@ -53,10 +47,13 @@ namespace IO { namespace Networking {
void EnterIoContext(std::function<void(IO::NetworkError)> const& callback);

/// Warning: Using this function will NOT copy the buffer, dont overwrite it unless callback is triggered! (but a reference to the smart_ptr will be held throughout the transfer, so you dont need to)
/// You have to keep the pointer alive until the callback is called. Use [self = shared_from_this()]
void Write(std::shared_ptr<std::vector<uint8_t> const> const& source, std::function<void(IO::NetworkError const&)> const& callback);
/// Warning: Using this function will NOT copy the buffer, dont overwrite it unless callback is triggered! (but a reference to the smart_ptr will be held throughout the transfer, so you dont need to)
/// You have to keep the pointer alive until the callback is called. Use [self = shared_from_this()]
void Write(std::shared_ptr<ByteBuffer const> const& source, std::function<void(IO::NetworkError const&)> const& callback);
/// Warning: Using this function will NOT copy the buffer, dont overwrite it unless callback is triggered! (but a reference to the smart_ptr will be held throughout the transfer, so you dont need to)
/// You have to keep the pointer alive until the callback is called. Use [self = shared_from_this()]
void Write(std::shared_ptr<uint8 const> const& source, uint64_t size, std::function<void(IO::NetworkError const&)> const& callback);

void CloseSocket();
Expand Down Expand Up @@ -127,63 +124,4 @@ namespace IO { namespace Networking {
};
}} // namespace IO::Networking

template<typename SocketType>
IO::Networking::AsyncSocket<SocketType>::~AsyncSocket() noexcept(false)
{
sLog.Out(LOG_NETWORK, LOG_LVL_DETAIL, "Destructor called ~AsyncSocket: No references left");
CloseSocket();

//#ifdef DEBUG
// Logic behind these checks:
// If the destructor is called, there should be no more std::shared_ptr<> references to this object
// Every Read(...) or Write(...) should use `shared_from_this()` if this is not the case, one of the following checks will fail
int state = m_atomicState.load(std::memory_order::memory_order_relaxed);
MANGOS_ASSERT(!(state & SocketStateFlags::CONTEXT_PRESENT));
MANGOS_ASSERT(!(state & SocketStateFlags::WRITE_PRESENT));
MANGOS_ASSERT(!(state & SocketStateFlags::READ_PRESENT));
//#endif // _DEBUG
}

template<typename SocketType>
bool IO::Networking::AsyncSocket<SocketType>::IsClosing() const
{
bool isClosing = m_atomicState.load(std::memory_order::memory_order_relaxed) & SHUTDOWN_PENDING;
return isClosing;
}

template<typename SocketType>
IO::Networking::IpEndpoint const& IO::Networking::AsyncSocket<SocketType>::GetRemoteEndpoint() const
{
return m_socket.m_peerEndpoint;
}

template<typename SocketType>
std::string IO::Networking::AsyncSocket<SocketType>::GetRemoteIpString() const
{
return GetRemoteEndpoint().ip.toString(); // Just gets the IP part e.g. "192.168.13.37"
}

template<typename SocketType>
void IO::Networking::AsyncSocket<SocketType>::ReadSkip(std::size_t skipSize, std::function<void(IO::NetworkError const&)> const& callback)
{
std::shared_ptr<std::vector<uint8_t>> skipBuffer(new std::vector<uint8_t>());
skipBuffer->resize(skipSize);
Read((char*)skipBuffer->data(), skipSize, [skipBuffer, callback](IO::NetworkError const& error, size_t)
{
// KEEP skipBuffer in scope!
// Do not remove skipBuffer before Read() is done, since we are transferring into it via async IO
// and since we are using a raw pointer, the Task has no knowledge about the lifetime of the std::vector
skipBuffer->clear();
callback(error);
});
}

#if defined(WIN32)
#include "./impl/windows/AsyncSocket_impl.h"
#elif defined(__linux__) || defined(__APPLE__)
#include "./impl/unix/AsyncSocket_impl.h"
#else
#error "IO::Networking not supported on your platform"
#endif

#endif //MANGOS_IO_NETWORKING_ASYNCSOCKET_H
Loading

0 comments on commit 50c48e1

Please sign in to comment.