Work on refactoring networking system

This commit is contained in:
Joshua Ashton 2020-07-29 01:46:31 +01:00
parent 31ebec99c5
commit 8423980536
9 changed files with 132 additions and 127 deletions

View File

@ -4,3 +4,9 @@ constexpr unsigned long long operator"" KB(unsigned long long l)
{ {
return l * 1024; return l * 1024;
} }
#ifdef _MSC_VER
#define abstract __declspec(novtable)
#else
#define abstract
#endif

View File

@ -5,7 +5,7 @@ namespace Feather
{ {
DedicatedServer::DedicatedServer(ServerProperties* properties) : DedicatedServer::DedicatedServer(ServerProperties* properties) :
m_properties(properties), m_properties(properties),
m_listener(properties->serverPort.GetValue()), m_listener(properties->serverPort.GetValue(), this),
m_status() m_status()
{ {
m_status.descriptionText = properties->motd.GetValue(); m_status.descriptionText = properties->motd.GetValue();
@ -20,4 +20,16 @@ namespace Feather
DedicatedServer::~DedicatedServer() DedicatedServer::~DedicatedServer()
{ {
} }
void DedicatedServer::OnClientConnect(Network::TCPClient&& client)
{
auto [clients, lock] = m_clients.borrow();
clients.emplace_back(std::move(client));
}
void DedicatedServer::OnClientDisconnect(Network::TCPClient& client)
{
auto [clients, lock] = m_clients.borrow();
//clients.erase(std::remove(clients.begin(), clients.end(), client), clients.end());
}
} }

View File

@ -2,20 +2,26 @@
#include "network/TCPListener.h" #include "network/TCPListener.h"
#include "network/ServerStatus.h" #include "network/ServerStatus.h"
#include "network/IListenerInterface.h"
namespace Feather namespace Feather
{ {
class ServerProperties; class ServerProperties;
class DedicatedServer class DedicatedServer final : public Network::IListenerInterface
{ {
public: public:
DedicatedServer(ServerProperties* properties); DedicatedServer(ServerProperties* properties);
~DedicatedServer(); ~DedicatedServer();
void OnClientConnect(Network::TCPClient&& client) override;
void OnClientDisconnect(Network::TCPClient& client) override;
private: private:
ServerProperties* m_properties; ServerProperties* m_properties;
Network::TCPListener m_listener; Network::TCPListener m_listener;
Network::ServerStatus m_status; Network::ServerStatus m_status;
LockableVector<Network::TCPClient> m_clients;
}; };
} }

21
src/Lockable.h Normal file
View File

@ -0,0 +1,21 @@
#pragma once
#include <mutex>
#include <vector>
namespace Feather
{
template <typename T>
class Lockable {
public:
auto borrow() { return std::pair< T&, std::lock_guard<std::mutex>>{object, mutex}; }
auto borrow() const { return std::pair<const T&, std::lock_guard<std::mutex>>{object, mutex}; }
private:
T object;
mutable std::mutex mutex;
};
template <typename T>
using LockableVector = Lockable<std::vector<T>>;
}

View File

@ -1,24 +0,0 @@
#pragma once
#include "NetworkMessage.h"
#include <queue>
using std::queue;
namespace Feather::Network
{
class ClientHandle
{
private:
friend class TCPListener;
queue<NetworkMessage*> m_queue;
public:
void SendPacket(NetworkMessage* msg)
{
m_queue.push(msg);
}
};
}

View File

@ -0,0 +1,15 @@
#pragma once
#include "../Common.h"
namespace Feather::Network
{
class TCPClient;
class abstract IListenerInterface
{
public:
virtual void OnClientConnect(TCPClient&& client) = 0;
virtual void OnClientDisconnect(TCPClient& client) = 0;
};
}

View File

@ -1,3 +1,4 @@
#if 0
#include "Protocol.h" #include "Protocol.h"
#include "PacketReader.h" #include "PacketReader.h"
#include "PacketTypes.h" #include "PacketTypes.h"
@ -106,4 +107,5 @@ R"({
// TODO: validate state here // TODO: validate state here
m_state = state; m_state = state;
} }
} }
#endif

View File

@ -1,12 +1,11 @@
 
#include "../Common.h" #include "../Common.h"
#include "../Lockable.h"
#include "Protocol.h"
#include "TCPListener.h" #include "TCPListener.h"
#include "NetworkManager.h" #include "NetworkManager.h"
#include "NetworkMessage.h" #include "NetworkMessage.h"
#include "PacketReader.h" #include "PacketReader.h"
#include "ClientHandle.h"
#include <event2/event.h> #include <event2/event.h>
#include <event2/listener.h> #include <event2/listener.h>
@ -106,24 +105,13 @@ namespace Feather::Network
bool m_ipv6; bool m_ipv6;
}; };
class TCPListenerClient final : public ClientHandle class TCPListenerClient
{ {
private:
friend class TCPListener;
// Protocol for this specific client
Protocol m_protocol;
TCPListener *m_parent;
bufferevent *m_bufferEvent;
std::vector<uint8_t> m_incomingData;
std::mutex m_mutex;
public: public:
TCPListenerClient(TCPListener* parent, evutil_socket_t socket) TCPListenerClient(TCPListener* parent, evutil_socket_t socket)
: m_parent(parent) : m_parent(parent)
, m_protocol(this)
, m_bufferEvent(bufferevent_socket_new(NetworkManager::Instance().GetEventBase(), socket, BEV_OPT_CLOSE_ON_FREE | BEV_OPT_THREADSAFE | BEV_OPT_DEFER_CALLBACKS | BEV_OPT_UNLOCK_CALLBACKS)) , m_bufferEvent(bufferevent_socket_new(NetworkManager::Instance().GetEventBase(), socket, BEV_OPT_CLOSE_ON_FREE | BEV_OPT_THREADSAFE | BEV_OPT_DEFER_CALLBACKS | BEV_OPT_UNLOCK_CALLBACKS))
, m_buffer(evbuffer_new())
{ {
printf("Created TCPListenerClient\n"); printf("Created TCPListenerClient\n");
bufferevent_setcb(m_bufferEvent, bufferevent_setcb(m_bufferEvent,
@ -136,87 +124,71 @@ namespace Feather::Network
~TCPListenerClient() ~TCPListenerClient()
{ {
evbuffer_free(m_buffer);
bufferevent_free(m_bufferEvent); bufferevent_free(m_bufferEvent);
} }
void ReadCallback() void ReadCallback()
{ {
printf("Read callback!\n"); if (bufferevent_read_buffer(m_bufferEvent, m_buffer) != 0)
auto lock = std::unique_lock(m_mutex);
uint8_t data[1KB];
size_t length;
size_t originalSize = m_incomingData.size();
// TODO: could switch to bufferevent_read_buffer and use evbuffer to avoid copies
while ((length = bufferevent_read(m_bufferEvent, data, sizeof(data))) > 0)
{ {
size_t oldSize = m_incomingData.size(); printf("fuck");
m_incomingData.resize(oldSize + length); return;
std::memcpy(&m_incomingData[oldSize], data, length);
} }
uint8_t* dataPtr = &(m_incomingData.data()[originalSize]); const size_t size = evbuffer_get_length(m_buffer);
PacketReader reader(dataPtr); auto [data, lock] = m_data.borrow();
data.resize(size);
m_protocol.HandlePacket(reader); if (evbuffer_remove(m_buffer, data.data(), size) != size)
}
template <typename T>
void WritePingMessage(T& message, std::string json)
{
// Packet ID
message.WriteVarInt(0);
// JSON Contents
message.WriteString(json.c_str(), static_cast<int32_t>(json.length()));
}
DEFINE_MESSAGE_WRAPPER(WritePingMessage);
bool SendShitTest()
{
auto lock = std::unique_lock(m_mutex);
const std::string json_template =
R"({
"version": {
"name": "1.16.1",
"protocol": 736
},
"players": {
"max": 10,
"online": 10,
"sample": [
{ {
"name": "thinkofdeath", printf("fuck");
"id": "4566e69f-c907-48ee-8d71-d7ba5aa00d20" return;
} }
]
},
"description": {
"text": "Hello Nukem!"
}
})";
auto message = WritePingMessage(json_template);
bufferevent_write(m_bufferEvent, message.GetData(), message.GetDataSize());
return true;
} }
void WriteCallback() void WriteCallback()
{ {
printf("Write callback!\n");
//SendShitTest();
} }
void EventCallback(short event) void EventCallback(short event)
{ {
printf("Event! %d\n", event);
} }
const LockableVector<uint8_t>& GetData() const
{
return m_data;
}
private:
TCPListener* m_parent;
bufferevent* m_bufferEvent;
evbuffer* m_buffer;
LockableVector<uint8_t> m_data;
}; };
TCPListener::TCPListener(uint16_t port) TCPClient::TCPClient(std::unique_ptr<TCPListenerClient>&& client)
: m_client(std::move(client))
{
}
TCPClient::TCPClient(TCPClient&& client)
: m_client(std::move(client.m_client))
{
}
TCPClient::~TCPClient()
{
}
const LockableVector<uint8_t>& TCPClient::GetData() const
{
return m_client->GetData();
}
TCPListener::TCPListener(uint16_t port, IListenerInterface* callbacks)
: m_callbacks(callbacks)
{ {
// Setup the listen socket. // Setup the listen socket.
auto socket = std::make_unique<TCPSocket>(); auto socket = std::make_unique<TCPSocket>();
@ -239,7 +211,7 @@ R"({
auto ListenerCallback = [](evconnlistener* evListener, evutil_socket_t socket, sockaddr* addr, int len, void* self) auto ListenerCallback = [](evconnlistener* evListener, evutil_socket_t socket, sockaddr* addr, int len, void* self)
{ {
TCPListener* listener = static_cast<TCPListener*>(self); TCPListener* listener = static_cast<TCPListener*>(self);
listener->m_clients.emplace_back(std::make_unique<TCPListenerClient>(listener, socket)); listener->m_callbacks->OnClientConnect(std::make_unique<TCPListenerClient>(listener, socket));
}; };
if (!socket->Listen(ListenerCallback, this)) if (!socket->Listen(ListenerCallback, this))
@ -250,20 +222,5 @@ R"({
TCPListener::~TCPListener() TCPListener::~TCPListener()
{ {
}
void TCPListener::DispatchQueuedPackets()
{
for (const auto& client : m_clients)
{
while (!client->m_queue.empty())
{
NetworkMessage *msg = client->m_queue.front();
printf("Writing packet of size %u\n", uint32_t(msg->GetDataSize()));
bufferevent_write(client->m_bufferEvent, msg->GetData(), msg->GetDataSize());
client->m_queue.pop();
}
}
} }
} }

View File

@ -1,28 +1,38 @@
#pragma once #pragma once
#include "Lockable.h"
#include "IListenerInterface.h"
#include <cstdint> #include <cstdint>
#include <memory> #include <memory>
#include <vector> #include <vector>
namespace Feather::Network namespace Feather::Network
{ {
class Protocol;
class TCPSocket; class TCPSocket;
class TCPListenerClient; class TCPListenerClient;
class TCPClient
{
public:
TCPClient(std::unique_ptr<TCPListenerClient>&& client);
TCPClient(TCPClient&& client);
~TCPClient();
const LockableVector<uint8_t>& GetData() const;
private:
std::unique_ptr<TCPListenerClient> m_client;
};
class TCPListener class TCPListener
{ {
public: public:
TCPListener(uint16_t port); TCPListener(uint16_t port, IListenerInterface* callbacks);
~TCPListener(); ~TCPListener();
void DispatchQueuedPackets();
private: private:
IListenerInterface* m_callbacks;
std::unique_ptr<TCPSocket> m_socket; std::unique_ptr<TCPSocket> m_socket;
std::vector<std::unique_ptr<TCPListenerClient>> m_clients;
}; };