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;
}
#ifdef _MSC_VER
#define abstract __declspec(novtable)
#else
#define abstract
#endif

View File

@ -5,7 +5,7 @@ namespace Feather
{
DedicatedServer::DedicatedServer(ServerProperties* properties) :
m_properties(properties),
m_listener(properties->serverPort.GetValue()),
m_listener(properties->serverPort.GetValue(), this),
m_status()
{
m_status.descriptionText = properties->motd.GetValue();
@ -20,4 +20,16 @@ namespace Feather
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/ServerStatus.h"
#include "network/IListenerInterface.h"
namespace Feather
{
class ServerProperties;
class DedicatedServer
class DedicatedServer final : public Network::IListenerInterface
{
public:
DedicatedServer(ServerProperties* properties);
~DedicatedServer();
void OnClientConnect(Network::TCPClient&& client) override;
void OnClientDisconnect(Network::TCPClient& client) override;
private:
ServerProperties* m_properties;
Network::TCPListener m_listener;
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 "PacketReader.h"
#include "PacketTypes.h"
@ -106,4 +107,5 @@ R"({
// TODO: validate state here
m_state = state;
}
}
}
#endif

View File

@ -1,12 +1,11 @@

#include "../Common.h"
#include "../Lockable.h"
#include "Protocol.h"
#include "TCPListener.h"
#include "NetworkManager.h"
#include "NetworkMessage.h"
#include "PacketReader.h"
#include "ClientHandle.h"
#include <event2/event.h>
#include <event2/listener.h>
@ -106,24 +105,13 @@ namespace Feather::Network
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:
TCPListenerClient(TCPListener* parent, evutil_socket_t socket)
: 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_buffer(evbuffer_new())
{
printf("Created TCPListenerClient\n");
bufferevent_setcb(m_bufferEvent,
@ -136,87 +124,71 @@ namespace Feather::Network
~TCPListenerClient()
{
evbuffer_free(m_buffer);
bufferevent_free(m_bufferEvent);
}
void ReadCallback()
{
printf("Read callback!\n");
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)
if (bufferevent_read_buffer(m_bufferEvent, m_buffer) != 0)
{
size_t oldSize = m_incomingData.size();
m_incomingData.resize(oldSize + length);
std::memcpy(&m_incomingData[oldSize], data, length);
printf("fuck");
return;
}
uint8_t* dataPtr = &(m_incomingData.data()[originalSize]);
PacketReader reader(dataPtr);
m_protocol.HandlePacket(reader);
}
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": [
const size_t size = evbuffer_get_length(m_buffer);
auto [data, lock] = m_data.borrow();
data.resize(size);
if (evbuffer_remove(m_buffer, data.data(), size) != size)
{
"name": "thinkofdeath",
"id": "4566e69f-c907-48ee-8d71-d7ba5aa00d20"
printf("fuck");
return;
}
]
},
"description": {
"text": "Hello Nukem!"
}
})";
auto message = WritePingMessage(json_template);
bufferevent_write(m_bufferEvent, message.GetData(), message.GetDataSize());
return true;
}
void WriteCallback()
{
printf("Write callback!\n");
//SendShitTest();
}
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.
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)
{
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))
@ -250,20 +222,5 @@ R"({
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
#include "Lockable.h"
#include "IListenerInterface.h"
#include <cstdint>
#include <memory>
#include <vector>
namespace Feather::Network
{
class Protocol;
class TCPSocket;
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
{
public:
TCPListener(uint16_t port);
TCPListener(uint16_t port, IListenerInterface* callbacks);
~TCPListener();
void DispatchQueuedPackets();
private:
IListenerInterface* m_callbacks;
std::unique_ptr<TCPSocket> m_socket;
std::vector<std::unique_ptr<TCPListenerClient>> m_clients;
};