summaryrefslogtreecommitdiff
path: root/src/network/protocol.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/network/protocol.cpp')
-rw-r--r--src/network/protocol.cpp129
1 files changed, 129 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;
+}
+
}