tcp-lib/src/tcp.hpp

122 lines
3.1 KiB
C++

#pragma once
// STL includes
#include <array>
#include <cerrno>
#include <cstdint>
#include <expected>
#include <span>
// C stdlib includes
#include <netinet/in.h>
#include <sys/poll.h>
namespace tcp {
using HostString = std::array<char, 64>;
//
//
// 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<void, int> start_listening();
bool next_client_available();
[[nodiscard]] std::expected<void, int> accept_next_client();
void disconnect();
[[nodiscard]] std::expected<int, int>
send(std::span<const std::byte> data);
[[nodiscard]] std::expected<int, int>
recv(std::span<std::byte> buffer);
bool data_available();
[[nodiscard]] std::expected<std::array<char, 16>, 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<void, int> 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<void, int>
connect(HostString host, uint16_t port);
// clang-format on
void disconnect();
[[nodiscard]] std::expected<int, int> get_last_connection_status();
bool data_available();
[[nodiscard]] std::expected<int, int> recv(std::span<std::byte> buffer);
[[nodiscard]] std::expected<int, int> send(std::span<const std::byte> 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<void, int> create_socket();
[[nodiscard]] std::expected<bool, int> new_error_codes_available();
};
} // namespace tcp