//SPDX-License-Identifier: LGPL-3.0-only //SPDX-FileCopyrightText: Copyright (C) 2026 Catcrafts® module; #ifndef CRAFTER_NETWORK_BROWSER #include #include #include #include #include #include #include #include #include #include #include #include #include #endif export module Crafter.Network:ClientTCP; import std; #ifndef CRAFTER_NETWORK_BROWSER namespace Crafter { export class SocketClosedException : public std::exception { public: const char* what() const noexcept override { return "Socket closed"; } }; // A connect or a receive waited longer than its timeout. export class SocketTimeoutException : public std::exception { public: const char* what() const noexcept override { return "Socket timed out"; } }; export class ClientTCP { public: int socketid; ClientTCP(int socket); // A non-zero connectTimeout makes a connect nobody answers throw // SocketTimeoutException after that long, where it would otherwise // wait out the kernel's retries, about two minutes. A refused connect // fails at once either way. ClientTCP(const char* host, std::uint16_t port, std::chrono::milliseconds connectTimeout = std::chrono::milliseconds::zero()); ClientTCP(std::string host, std::uint16_t port, std::chrono::milliseconds connectTimeout = std::chrono::milliseconds::zero()); ~ClientTCP(); ClientTCP(const ClientTCP&) = delete; ClientTCP(ClientTCP&& other) noexcept; void Connect(std::chrono::milliseconds timeout = std::chrono::milliseconds::zero()); void Stop(); // Turns Nagle's algorithm off (TCP_NODELAY), so a small write goes // out at once instead of waiting for the ACK of the one before it. // For small messages that must arrive promptly, such as a stream of // frames. void SetNoDelay(bool enabled); // A receive that waits longer than this throws // SocketTimeoutException, losing what a whole-buffer receive had read // so far. Zero, the default, waits for good. void SetReceiveTimeout(std::chrono::milliseconds timeout); void Send(const void* buffer, std::uint32_t size) const; // The receives return what arrived, at least one byte; asked for none, // none, at once, without looking at the socket. They throw // SocketClosedException once the peer has closed, and // SocketTimeoutException when a receive timeout runs out. std::vector RecieveSync() const; std::vector RecieveUntilCloseSync() const; std::vector RecieveUntilFullSync(std::uint32_t bufferSize) const; std::vector RecieveSync(std::uint32_t bufferSize) const; // Into `buffer`; returns how many bytes it put there. std::uint32_t RecieveSync(std::uint32_t bufferSize, void* buffer) const; // The same receives on Crafter.Thread's ThreadPool. What arrived goes // to the callback; what a receive throws goes to onError instead (an // empty one drops it), as an exception left to escape a pool task // would end the program. void RecieveAsync(std::function)> recieveCallback, std::function onError) const; void RecieveUntilCloseAsync(std::function)> recieveCallback, std::function onError) const; void RecieveAsync(std::uint32_t bufferSize, std::function)> recieveCallback, std::function onError) const; void RecieveUntilFullAsync(std::uint32_t bufferSize, std::function)> recieveCallback, std::function onError) const; // Into `buffer`, which must outlive the receive; the callback gets the count. void RecieveAsync(std::uint32_t bufferSize, std::function recieveCallback, char* buffer, std::function onError) const; private: sockaddr_in serv_addr; }; } #endif