From 2ed8103ff1c0fca7372b3c3888f590ba41c525e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roman=20Smr=C5=BE?= Date: Sun, 13 Aug 2023 19:01:48 +0200 Subject: Connection class for network protocol --- src/network/protocol.cpp | 129 +++++++++++++++++++++++++++++++++++++++++++++++ src/network/protocol.h | 55 ++++++++++++++++++++ 2 files changed, 184 insertions(+) (limited to 'src/network') diff --git a/src/network/protocol.cpp b/src/network/protocol.cpp index 63cfde5..c247bf0 100644 --- a/src/network/protocol.cpp +++ b/src/network/protocol.cpp @@ -3,10 +3,27 @@ #include #include +#include +#include #include +using std::move; +using std::scoped_lock; + namespace erebos { +struct NetworkProtocol::ConnectionPriv +{ + Connection::Id id() const; + + NetworkProtocol * protocol; + const sockaddr_in6 peerAddress; + + mutex cmutex {}; + vector buffer {}; +}; + + NetworkProtocol::NetworkProtocol(): sock(-1) {} @@ -32,6 +49,44 @@ NetworkProtocol::~NetworkProtocol() { if (sock >= 0) close(sock); + + for (auto & c : connections) + c->protocol = nullptr; +} + +NetworkProtocol::PollResult NetworkProtocol::poll() +{ + sockaddr_in6 addr; + if (!recvfrom(buffer, addr)) + return ProtocolClosed {}; + + scoped_lock lock(protocolMutex); + for (const auto & c : connections) { + if (memcmp(&c->peerAddress, &addr, sizeof addr) == 0) { + scoped_lock clock(c->cmutex); + buffer.swap(c->buffer); + return ConnectionReadReady { c->id() }; + } + } + + auto conn = unique_ptr(new ConnectionPriv { + .protocol = this, + .peerAddress = addr, + }); + + connections.push_back(conn.get()); + buffer.swap(conn->buffer); + return NewConnection { Connection(move(conn)) }; +} + +NetworkProtocol::Connection NetworkProtocol::connect(sockaddr_in6 addr) +{ + auto conn = unique_ptr(new ConnectionPriv { + .protocol = this, + .peerAddress = addr, + }); + connections.push_back(conn.get()); + return Connection(move(conn)); } bool NetworkProtocol::recvfrom(vector & buffer, sockaddr_in6 & addr) @@ -66,4 +121,78 @@ void NetworkProtocol::shutdown() ::shutdown(sock, SHUT_RDWR); } + +NetworkProtocol::Connection::Id NetworkProtocol::ConnectionPriv::id() const +{ + return reinterpret_cast(this); +} + +NetworkProtocol::Connection::Connection(unique_ptr p_): + p(move(p_)) +{ +} + +NetworkProtocol::Connection::Connection(Connection && other): + p(move(other.p)) +{ +} + +NetworkProtocol::Connection & NetworkProtocol::Connection::operator=(Connection && other) +{ + close(); + p = move(other.p); + return *this; +} + +NetworkProtocol::Connection::~Connection() +{ + close(); +} + +NetworkProtocol::Connection::Id NetworkProtocol::Connection::id() const +{ + return p->id(); +} + +const sockaddr_in6 & NetworkProtocol::Connection::peerAddress() const +{ + return p->peerAddress; +} + +bool NetworkProtocol::Connection::receive(vector & buffer) +{ + scoped_lock lock(p->cmutex); + if (p->buffer.empty()) + return false; + + buffer.swap(p->buffer); + p->buffer.clear(); + return true; +} + +bool NetworkProtocol::Connection::send(const vector & buffer) +{ + p->protocol->sendto(buffer, p->peerAddress); + return true; +} + +void NetworkProtocol::Connection::close() +{ + if (not p) + return; + + if (p->protocol) { + scoped_lock lock(p->protocol->protocolMutex); + for (auto it = p->protocol->connections.begin(); + it != p->protocol->connections.end(); it++) { + if ((*it) == p.get()) { + p->protocol->connections.erase(it); + break; + } + } + } + + p = nullptr; +} + } diff --git a/src/network/protocol.h b/src/network/protocol.h index 6a22f3b..a9bbaff 100644 --- a/src/network/protocol.h +++ b/src/network/protocol.h @@ -3,10 +3,16 @@ #include #include +#include +#include +#include #include namespace erebos { +using std::mutex; +using std::unique_ptr; +using std::variant; using std::vector; class NetworkProtocol @@ -20,6 +26,21 @@ public: NetworkProtocol & operator=(NetworkProtocol &&); ~NetworkProtocol(); + class Connection; + + struct NewConnection; + struct ConnectionReadReady; + struct ProtocolClosed {}; + + using PollResult = variant< + NewConnection, + ConnectionReadReady, + ProtocolClosed>; + + PollResult poll(); + + Connection connect(sockaddr_in6 addr); + bool recvfrom(vector & buffer, sockaddr_in6 & addr); void sendto(const vector & buffer, sockaddr_in addr); void sendto(const vector & buffer, sockaddr_in6 addr); @@ -28,6 +49,40 @@ public: private: int sock; + + mutex protocolMutex; + vector buffer; + + struct ConnectionPriv; + vector connections; +}; + +class NetworkProtocol::Connection +{ + friend class NetworkProtocol; + Connection(unique_ptr p); +public: + Connection(const Connection &) = delete; + Connection(Connection &&); + Connection & operator=(const Connection &) = delete; + Connection & operator=(Connection &&); + ~Connection(); + + using Id = uintptr_t; + Id id() const; + + const sockaddr_in6 & peerAddress() const; + + bool receive(vector & buffer); + bool send(const vector & buffer); + + void close(); + +private: + unique_ptr p; }; +struct NetworkProtocol::NewConnection { Connection conn; }; +struct NetworkProtocol::ConnectionReadReady { Connection::Id id; }; + } -- cgit v1.2.3