#pragma once // STL includes #include #include #include #include #include // C stdlib includes #include #include namespace tcp { using HostString = std::array; // // // Non blocking server // // struct ServerSettings { uint16_t port = 0; }; class NonBlockingServer { public: NonBlockingServer(ServerSettings settings); NonBlockingServer(const NonBlockingServer&) = delete; NonBlockingServer(NonBlockingServer&&) = delete; NonBlockingServer& operator=(const NonBlockingServer&) = delete; NonBlockingServer& operator=(NonBlockingServer&&) = delete; ~NonBlockingServer(); [[nodiscard]] std::expected start_listening(); bool next_client_available(); [[nodiscard]] std::expected accept_next_client(); void disconnect(); [[nodiscard]] std::expected send(std::span data); [[nodiscard]] std::expected recv(std::span buffer); bool data_available(); [[nodiscard]] std::expected, int> get_client_ip_as_string(); private: ServerSettings m_settings; const struct sockaddr_in m_serverAddress; int m_serverSocket = -1; pollfd m_serverPfdIn = {.fd = -1, .events = POLLIN}; pollfd m_clientPfdIn = {.fd = -1, .events = POLLIN}; int m_clientSocket = -1; struct sockaddr m_clientAddress; socklen_t m_clientAddrLen = sizeof(m_clientAddress); [[nodiscard]] std::expected create_socket(); void close_server_socket(); void close_client_socket(); }; // // // Non blocking client // // class NonBlockingClient { public: NonBlockingClient() = default; NonBlockingClient(const NonBlockingClient&) = delete; NonBlockingClient(NonBlockingClient&&) = delete; NonBlockingClient& operator=(const NonBlockingClient&) = delete; NonBlockingClient& operator=(NonBlockingClient&&) = delete; ~NonBlockingClient(); // clang-format off [[nodiscard]] std::expected connect(HostString host, uint16_t port); // clang-format on void disconnect(); [[nodiscard]] std::expected get_last_connection_status(); bool data_available(); [[nodiscard]] std::expected recv(std::span buffer); [[nodiscard]] std::expected send(std::span data); private: int m_socket = -1; pollfd m_pfdOut = {.fd = -1, .events = POLLOUT}; pollfd m_pfdIn = {.fd = -1, .events = POLLIN}; bool m_startedNewConAttempt = false; int m_lastKnownConStatus = ENOTCONN; void close_socket(); [[nodiscard]] std::expected create_socket(); [[nodiscard]] std::expected new_error_codes_available(); }; } // namespace tcp