/*** Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved. File: Net.hpp Date: 2021-6-9 Author: Reece ***/ #pragma once namespace Aurora::IO::Net { enum TransportProtocol { kProtocolUDP, kProtocolTCP }; enum IPProtocol { kIPProtocolV4, kIPProtocolV6 }; struct IPAddress { IPProtocol ip; bool hasIP; AuString address; union { AuUInt8 v4[4]; AuUInt16 v6[8]; }; AUKN_SYM AuString toString(); }; struct Endpoint { TransportProtocol protocol; IPAddress address; AuUInt16 port; // 0 - destination is a stateless datagram server // 1 - destination is a psuedo-stateful server AuUInt UDPTimeout; AUKN_SYM AuString toString(); }; class INetworkStream; class IBasicSocket; class IClientSocket; /** * DTLS/UDP/TCP/TLS -> TRUE = expects another datagram or read pump * -> FALSE = end of socket life */ using StreamHasData_cb = std::function &socket)>; using InitializeSocket_cb = std::function &socket)>; using ShutdownSocket_cb = std::function &socket)>; class IClientHasData { public: // DTLS/UDP/TCP/TLS -> TRUE = expects another datagram or read pump // FALSE = end of socket life virtual bool OnSocketHasData(const AuSPtr &socket) = 0; }; class FunctionalClientHasData : public IClientHasData { private: StreamHasData_cb socket_; public: FunctionalClientHasData(const StreamHasData_cb &socket) : socket_(socket) {} FunctionalClientHasData(StreamHasData_cb &&socket) : socket_(std::move(socket)) {} }; class IClientShutdown { public: virtual void OnSocketShutdown(const AuSPtr &socket) = 0; }; class FunctionalClientShutdown : public IClientShutdown { private: ShutdownSocket_cb socket_; public: FunctionalClientShutdown(const ShutdownSocket_cb &socket) : socket_(socket) {} FunctionalClientShutdown(ShutdownSocket_cb &&socket) : socket_(std::move(socket)) {} }; class IClientDoS { public: virtual void OnSocketDoS(const AuSPtr &socket) = 0; }; class FunctionalClientDoS: public IClientDoS { private: ShutdownSocket_cb socket_; public: FunctionalClientDoS(const ShutdownSocket_cb &socket) : socket_(socket) {} FunctionalClientDoS(ShutdownSocket_cb &&socket) : socket_(std::move(socket)) {} }; class IClientTLSBreakdown { public: virtual void OnSocketTLSBreakdown(const AuSPtr &socket) = 0; }; class FunctionalClientTLSBreakdown : public IClientTLSBreakdown { private: ShutdownSocket_cb socket_; public: FunctionalClientTLSBreakdown(const ShutdownSocket_cb &socket) : socket_(socket) {} FunctionalClientTLSBreakdown(ShutdownSocket_cb &&socket) : socket_(std::move(socket)) {} }; class IClientEvents { public: virtual void AddSubscriptionHasData(const AuSPtr &iface) = 0; virtual void RemoveSubscriptionHasData(const AuSPtr &iface) = 0; virtual void AddSubscriptionShutdown(const AuSPtr &iface) = 0; virtual void RemoveSubscriptionShutdown(const AuSPtr &iface) = 0; virtual void AddSubscriptionDoS(const AuSPtr &iface) = 0; virtual void RemoveSubscriptionDoS(const AuSPtr &iface) = 0; virtual void AddSubscriptionTlsBreakdown(const AuSPtr &iface) = 0; virtual void RemoveSubscriptionTlsBreakdown(const AuSPtr &iface) = 0; }; using Error_t = std::error_code; class IBasicSocket { public: virtual bool IsActive() = 0; virtual Error_t GetLastError() = 0; virtual void Shutdown() = 0; virtual bool GetLocalEndpoint(Endpoint &out) = 0; }; class IClientSocket : public IBasicSocket { public: virtual IClientEvents *GetClientEvents() = 0; virtual bool Initialize() = 0; virtual bool GetRemoteEndpoint(Endpoint &out) = 0; virtual bool PumpRead() = 0; virtual bool PumpWrite() = 0; virtual bool ReadAsync(AuUInt8 *buffer, AuUInt32 &length, bool all = false) = 0; virtual bool PeakAsync(AuUInt8 *buffer, AuUInt32 &length) = 0; virtual bool ReadSync(AuUInt8 *buffer, AuUInt32 &length, bool all = true) = 0; virtual bool WriteAsync(const AuUInt8 *buffer, AuUInt32 length) = 0; virtual bool WriteAsync(const AuUInt8 *buffer, AuUInt32 length, std::function) = 0; virtual bool WriteSync(const AuUInt8 *buffer, AuUInt32 length) = 0; /** * Sets the internal application buffer size * Noting that Linux's default network buffer looks like this: * Minimum, Initial, Maximum: 10240 87380 12582912 | 10KB, 86KB, 12MB */ virtual AuUInt GetInternalRingBuffer() = 0; virtual bool SetInternalRingBuffer(AuUInt bytes) = 0; /** * Defines the maximum amount of bytes each recieve frame can ingest */ virtual void SetRecvLength(AuOptional length) = 0; virtual AuUInt32 GetRecvLength() = 0; /** * Enable ad-hoc input buffer ingestion into our internal buffer * Only use when PumpRead will not suffice by design (ie: sync apps) */ virtual void BufferAdhoc(AuOptional value) = 0; }; class ILocalClientSocket : public IClientSocket { public: using ConnectCallback_cb = std::function; virtual bool Connect() = 0; virtual void ConnectAsync(ConnectCallback_cb cb) = 0; }; struct TlsConnect { Aurora::Crypto::X509::Certificate serverCertificate; AuSPtr socket; }; using TlsConnect_cb = std::function; struct ServerInfo { Endpoint listen; }; struct TLSServerInfo : ServerInfo { Aurora::Crypto::RSAPair cert; }; struct ClientInfo { Endpoint socket; AuString service; }; struct TLSClientInfo : ClientInfo { TlsConnect_cb pinning; }; class IServer : public IBasicSocket { public: virtual bool AddAcceptCallback(const InitializeSocket_cb &accept) = 0; // on accept* virtual bool AddExitCallback(const ShutdownSocket_cb &accept) = 0; // server shutdown* virtual void GetClients(AuList> &clients) = 0; virtual bool Listen() = 0; }; class INetworkingPool { public: /** Supported thread models: while (true) { // read from sockets pre-frame PumpRead(); // process other async network logic here // process writes and a few early reads before we sleep PumpWrite(); // yield Yield(); } while (true) { // process other async network logic here // run once Pump() } ...and none with BufferAdhoc enabled */ virtual void PumpRead() = 0; virtual void PumpWrite() = 0; virtual void Pump() = 0; virtual bool NewServer(const ServerInfo &listen, AuSPtr &out) = 0; virtual bool NewTlsServer(const TLSServerInfo &keys, AuSPtr &out) = 0; virtual bool NewClient(const ClientInfo &info, AuSPtr &out) = 0; virtual bool NewTlsClient(const TLSClientInfo &info, AuSPtr &out) = 0; }; }