diff options
author | Roman Smrž <roman.smrz@seznam.cz> | 2023-08-13 19:01:48 +0200 |
---|---|---|
committer | Roman Smrž <roman.smrz@seznam.cz> | 2023-08-16 21:49:39 +0200 |
commit | 2ed8103ff1c0fca7372b3c3888f590ba41c525e6 (patch) | |
tree | 103834746f4b64c7dbaf4a237447108cdf44c8d9 /src/network | |
parent | 7420a170928da75cb860e3fc8804416babdeec8c (diff) |
Connection class for network protocol
Diffstat (limited to 'src/network')
-rw-r--r-- | src/network/protocol.cpp | 129 | ||||
-rw-r--r-- | src/network/protocol.h | 55 |
2 files changed, 184 insertions, 0 deletions
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 <sys/socket.h> #include <unistd.h> +#include <cstring> +#include <mutex> #include <system_error> +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<uint8_t> 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<ConnectionPriv>(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<ConnectionPriv>(new ConnectionPriv { + .protocol = this, + .peerAddress = addr, + }); + connections.push_back(conn.get()); + return Connection(move(conn)); } bool NetworkProtocol::recvfrom(vector<uint8_t> & 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<uintptr_t>(this); +} + +NetworkProtocol::Connection::Connection(unique_ptr<ConnectionPriv> 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<uint8_t> & 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<uint8_t> & 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 <netinet/in.h> #include <cstdint> +#include <memory> +#include <mutex> +#include <variant> #include <vector> 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<uint8_t> & buffer, sockaddr_in6 & addr); void sendto(const vector<uint8_t> & buffer, sockaddr_in addr); void sendto(const vector<uint8_t> & buffer, sockaddr_in6 addr); @@ -28,6 +49,40 @@ public: private: int sock; + + mutex protocolMutex; + vector<uint8_t> buffer; + + struct ConnectionPriv; + vector<ConnectionPriv *> connections; +}; + +class NetworkProtocol::Connection +{ + friend class NetworkProtocol; + Connection(unique_ptr<ConnectionPriv> 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<uint8_t> & buffer); + bool send(const vector<uint8_t> & buffer); + + void close(); + +private: + unique_ptr<ConnectionPriv> p; }; +struct NetworkProtocol::NewConnection { Connection conn; }; +struct NetworkProtocol::ConnectionReadReady { Connection::Id id; }; + } |