Work on refactoring networking system
This commit is contained in:
parent
31ebec99c5
commit
8423980536
|
@ -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
|
|
@ -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());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -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>>;
|
||||||
|
}
|
|
@ -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);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -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;
|
||||||
|
};
|
||||||
|
}
|
|
@ -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
|
|
@ -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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue