#pragma once #include "channel.h" #include #include #include #include #include #include #include #include namespace erebos { using std::mutex; using std::optional; using std::unique_ptr; using std::variant; using std::vector; class NetworkProtocol { public: NetworkProtocol(); explicit NetworkProtocol(int sock, Identity self); NetworkProtocol(const NetworkProtocol &) = delete; NetworkProtocol(NetworkProtocol &&); NetworkProtocol & operator=(const NetworkProtocol &) = delete; NetworkProtocol & operator=(NetworkProtocol &&); ~NetworkProtocol(); static constexpr char defaultVersion[] = "0.1"; class Connection; struct Header; struct ReceivedAnnounce; struct NewConnection; struct ConnectionReadReady; struct ProtocolClosed {}; using PollResult = variant< ReceivedAnnounce, NewConnection, ConnectionReadReady, ProtocolClosed>; PollResult poll(); struct Cookie { vector value; }; using ChannelState = variant, shared_ptr, Stored, unique_ptr>; Connection connect(sockaddr_in6 addr); void updateIdentity(Identity self); void announceTo(variant addr); void shutdown(); private: bool recvfrom(vector & buffer, sockaddr_in6 & addr); void sendto(const vector & buffer, variant addr); void sendCookie(variant addr); optional verifyNewConnection(const Header & header, sockaddr_in6 addr); Cookie generateCookie(variant addr) const; bool verifyCookie(variant addr, const Cookie & cookie) const; int sock; mutex protocolMutex; vector buffer; optional self; 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; optional
receive(const PartialStorage &); bool send(const PartialStorage &, NetworkProtocol::Header, const vector &, bool secure); void close(); // temporary: ChannelState & channel(); void trySendOutQueue(); private: static optional
parsePacket(vector & buf, Channel * channel, const PartialStorage & st, bool & secure); unique_ptr p; }; struct NetworkProtocol::ReceivedAnnounce { sockaddr_in6 addr; Digest digest; }; struct NetworkProtocol::NewConnection { Connection conn; }; struct NetworkProtocol::ConnectionReadReady { Connection::Id id; }; struct NetworkProtocol::Header { struct Acknowledged { Digest value; }; struct Version { string value; }; struct Initiation { Digest value; }; struct CookieSet { Cookie value; }; struct CookieEcho { Cookie value; }; struct DataRequest { Digest value; }; struct DataResponse { Digest value; }; struct AnnounceSelf { Digest value; }; struct AnnounceUpdate { Digest value; }; struct ChannelRequest { Digest value; }; struct ChannelAccept { Digest value; }; struct ServiceType { UUID value; }; struct ServiceRef { Digest value; }; using Item = variant< Acknowledged, Version, Initiation, CookieSet, CookieEcho, DataRequest, DataResponse, AnnounceSelf, AnnounceUpdate, ChannelRequest, ChannelAccept, ServiceType, ServiceRef>; Header(const vector & items): items(items) {} static optional
load(const PartialRef &); static optional
load(const PartialObject &); PartialObject toObject(const PartialStorage &) const; template const T * lookupFirst() const; vector items; }; template const T * NetworkProtocol::Header::lookupFirst() const { for (const auto & h : items) if (auto ptr = std::get_if(&h)) return ptr; return nullptr; } bool operator==(const NetworkProtocol::Header::Item &, const NetworkProtocol::Header::Item &); inline bool operator!=(const NetworkProtocol::Header::Item & left, const NetworkProtocol::Header::Item & right) { return not (left == right); } inline bool operator==(const NetworkProtocol::Cookie & left, const NetworkProtocol::Cookie & right) { return left.value == right.value; } class ReplyBuilder { public: void header(NetworkProtocol::Header::Item &&); void body(const Ref &); const vector & header() const { return mheader; } vector body() const; private: vector mheader; vector mbody; }; struct WaitingRef { const Storage storage; const PartialRef ref; vector missing; optional check(); optional check(ReplyBuilder &); }; }