/* Crafter®.Network Copyright (C) 2025 Catcrafts® Catcrafts.net This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3.0 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ module; #include #include #include #include #include #include #include #include #include #include #include #include #include module Crafter.Network:ClientTCP_impl; import :ClientTCP; import Crafter.Thread; import std; using namespace Crafter; ClientTCP::ClientTCP(int socketid) : socketid(socketid) { } ClientTCP::ClientTCP(const char* hostName, std::uint16_t port) { host = gethostbyname(hostName); serv_addr.sin_family = AF_INET; serv_addr.sin_port = htons(port); serv_addr.sin_addr = *((struct in_addr *)host->h_addr); bzero(&(serv_addr.sin_zero),8); Connect(); } ClientTCP::ClientTCP(std::string hostName, std::uint16_t port): ClientTCP(hostName.c_str(), port) { } ClientTCP::ClientTCP(ClientTCP&& other) noexcept : socketid(other.socketid) { if(socketid != 1) { shutdown(socketid, SHUT_RDWR); close(socketid); } other.socketid = -1; } ClientTCP::~ClientTCP() { if(socketid != 1) { shutdown(socketid, SHUT_RDWR); close(socketid); } } void ClientTCP::Connect() { if((socketid = socket(AF_INET, SOCK_STREAM, 0)) == -1){ std::cerr << "Could not open socket" << std::endl; } if(connect(socketid,(sockaddr*)&serv_addr, sizeof(sockaddr)) == -1){ std::cerr << "Could not connect to server" << std::endl; } } void ClientTCP::Stop() { shutdown(socketid, SHUT_RDWR); close(socketid); socketid = -1; } void ClientTCP::Send(const void* buffer, std::uint32_t size) const { const char* data = reinterpret_cast(buffer); std::uint_fast32_t totalSent = 0; const std::uint_fast32_t chunkSize = 1024; while (totalSent < size) { std::uint_fast32_t bytesToSend = std::min(chunkSize, size - totalSent); int status = send(socketid, data + totalSent, bytesToSend, 0); if (status == 0) { throw SocketClosedException(); } else if (status < 0) { throw std::runtime_error(std::strerror(errno)); } totalSent += status; } } std::vector ClientTCP::RecieveSync(std::uint32_t bufferSize) const { std::vector totalBuffer(bufferSize); int read = recv(socketid, totalBuffer.data(), bufferSize, 0); if(read < 0) { throw std::runtime_error(std::strerror(errno)); } else if(read == 0) { throw SocketClosedException(); } return totalBuffer; } int ClientTCP::RecieveSync(std::uint32_t bufferSize, void* buffer) const { return recv(socketid, reinterpret_cast(buffer), bufferSize, 0); } std::vector ClientTCP::RecieveSync() const { int count; ioctl(socketid, FIONREAD, &count); if(count == 0){ count = 1024; } std::vector buffer(count); int read = recv(socketid, buffer.data(), count, 0); if(read < 0) { throw std::runtime_error(std::strerror(errno)); } else if(read == 0) { throw SocketClosedException(); } else if(count != read) { buffer.resize(read); } return buffer; } std::vector ClientTCP::RecieveUntilCloseSync() const { int count; ioctl(socketid, FIONREAD, &count); if(count == 0){ count = 1024; } std::vector buffer(count); int read = recv(socketid, buffer.data(), count, 0); if(read < 0) { throw std::runtime_error(std::strerror(errno)); } else if(read == 0) { throw SocketClosedException(); } while(true) { ioctl(socketid, FIONREAD, &count); if(count == 0){ count = 1024; } unsigned int oldSize = buffer.size(); buffer.resize(buffer.size()+count); int read = recv(socketid, buffer.data()+oldSize, count, 0); if(read < 0) { throw std::runtime_error(std::strerror(errno)); } else if(read == 0) { return buffer; } else if(count != read) { buffer.resize(read); } } return buffer; } std::vector ClientTCP::RecieveUntilFullSync(std::uint32_t bufferSize) const { std::vector buffer(bufferSize); int read = 0; while(read < bufferSize) { int newRead = recv(socketid, buffer.data()+read, bufferSize-read, 0); if(newRead < 0) { throw std::runtime_error(std::strerror(errno)); } else if(newRead == 0) { throw SocketClosedException(); } read+=newRead; } buffer.resize(read); return buffer; } void ClientTCP::RecieveAsync(std::uint32_t bufferSize, std::function)> recieveCallback) const { ThreadPool::Enqueue([recieveCallback, this, bufferSize](){ recieveCallback(this->RecieveSync(bufferSize)); }); } void ClientTCP::RecieveAsync(std::uint32_t bufferSize, std::function recieveCallback, char* buffer) const { ThreadPool::Enqueue([recieveCallback, this, bufferSize, buffer](){ recieveCallback(this->RecieveSync(bufferSize, buffer)); }); } void ClientTCP::RecieveUntilFullAsync(std::uint32_t bufferSize, std::function)> recieveCallback) const { ThreadPool::Enqueue([recieveCallback, this, bufferSize](){ recieveCallback(this->RecieveUntilFullSync(bufferSize)); }); } void ClientTCP::RecieveAsync(std::function)> recieveCallback) const { ThreadPool::Enqueue([this, recieveCallback](){ recieveCallback(this->RecieveSync()); }); } void ClientTCP::RecieveUntilCloseAsync(std::function)> recieveCallback) const { ThreadPool::Enqueue([this, recieveCallback](){ recieveCallback(this->RecieveUntilCloseSync()); }); }