Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Native Branch: Move IO::Networking::AsyncSocket to .cpp file #2734

Merged
merged 2 commits into from
Aug 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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