summaryrefslogtreecommitdiff
path: root/src/network
diff options
context:
space:
mode:
authorRoman Smrž <roman.smrz@seznam.cz>2023-08-13 19:01:48 +0200
committerRoman Smrž <roman.smrz@seznam.cz>2023-08-16 21:49:39 +0200
commit2ed8103ff1c0fca7372b3c3888f590ba41c525e6 (patch)
tree103834746f4b64c7dbaf4a237447108cdf44c8d9 /src/network
parent7420a170928da75cb860e3fc8804416babdeec8c (diff)
Connection class for network protocol
Diffstat (limited to 'src/network')
-rw-r--r--src/network/protocol.cpp129
-rw-r--r--src/network/protocol.h55
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; };
+
}