diff --git a/src/Common.h b/src/Common.h index d4dffa1..01d6cd3 100644 --- a/src/Common.h +++ b/src/Common.h @@ -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 \ No newline at end of file diff --git a/src/DedicatedServer.cpp b/src/DedicatedServer.cpp index a05e7e8..c82ea5f 100644 --- a/src/DedicatedServer.cpp +++ b/src/DedicatedServer.cpp @@ -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()); + } } diff --git a/src/DedicatedServer.h b/src/DedicatedServer.h index c4b682d..173411e 100644 --- a/src/DedicatedServer.h +++ b/src/DedicatedServer.h @@ -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 m_clients; }; } diff --git a/src/Lockable.h b/src/Lockable.h new file mode 100644 index 0000000..0cc45ae --- /dev/null +++ b/src/Lockable.h @@ -0,0 +1,21 @@ +#pragma once + +#include +#include + +namespace Feather +{ + template + class Lockable { + public: + auto borrow() { return std::pair< T&, std::lock_guard>{object, mutex}; } + auto borrow() const { return std::pair>{object, mutex}; } + + private: + T object; + mutable std::mutex mutex; + }; + + template + using LockableVector = Lockable>; +} \ No newline at end of file diff --git a/src/network/ClientHandle.h b/src/network/ClientHandle.h deleted file mode 100644 index 71c5bfb..0000000 --- a/src/network/ClientHandle.h +++ /dev/null @@ -1,24 +0,0 @@ -#pragma once - -#include "NetworkMessage.h" - -#include - -using std::queue; - -namespace Feather::Network -{ - class ClientHandle - { - private: - friend class TCPListener; - - queue m_queue; - - public: - void SendPacket(NetworkMessage* msg) - { - m_queue.push(msg); - } - }; -} \ No newline at end of file diff --git a/src/network/IListenerInterface.h b/src/network/IListenerInterface.h new file mode 100644 index 0000000..6c18607 --- /dev/null +++ b/src/network/IListenerInterface.h @@ -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; + }; +} \ No newline at end of file diff --git a/src/network/Protocol.cpp b/src/network/Protocol.cpp index b787916..82bf0a0 100644 --- a/src/network/Protocol.cpp +++ b/src/network/Protocol.cpp @@ -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; } -} \ No newline at end of file +} +#endif \ No newline at end of file diff --git a/src/network/TCPListener.cpp b/src/network/TCPListener.cpp index 3bf9940..fb98e12 100644 --- a/src/network/TCPListener.cpp +++ b/src/network/TCPListener.cpp @@ -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 #include @@ -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 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 - void WritePingMessage(T& message, std::string json) - { - // Packet ID - message.WriteVarInt(0); - // JSON Contents - message.WriteString(json.c_str(), static_cast(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& GetData() const + { + return m_data; + } + + private: + TCPListener* m_parent; + + bufferevent* m_bufferEvent; + evbuffer* m_buffer; + + LockableVector m_data; }; - TCPListener::TCPListener(uint16_t port) + TCPClient::TCPClient(std::unique_ptr&& client) + : m_client(std::move(client)) + { + } + + TCPClient::TCPClient(TCPClient&& client) + : m_client(std::move(client.m_client)) + { + } + + TCPClient::~TCPClient() + { + } + + const LockableVector& 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(); @@ -239,7 +211,7 @@ R"({ auto ListenerCallback = [](evconnlistener* evListener, evutil_socket_t socket, sockaddr* addr, int len, void* self) { TCPListener* listener = static_cast(self); - listener->m_clients.emplace_back(std::make_unique(listener, socket)); + listener->m_callbacks->OnClientConnect(std::make_unique(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(); - } - } } } \ No newline at end of file diff --git a/src/network/TCPListener.h b/src/network/TCPListener.h index f92e4e8..826237d 100644 --- a/src/network/TCPListener.h +++ b/src/network/TCPListener.h @@ -1,28 +1,38 @@ #pragma once +#include "Lockable.h" +#include "IListenerInterface.h" + #include #include #include namespace Feather::Network { - class Protocol; - class TCPSocket; class TCPListenerClient; + + class TCPClient + { + public: + TCPClient(std::unique_ptr&& client); + TCPClient(TCPClient&& client); + ~TCPClient(); + + const LockableVector& GetData() const; + + private: + std::unique_ptr 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 m_socket; - - std::vector> m_clients; };