Crafter.Network/implementations/Crafter.Network-ClientTCP.cpp
2026-07-22 17:55:45 +02:00

198 lines
5.7 KiB
C++
Executable file

//SPDX-License-Identifier: LGPL-3.0-only
//SPDX-FileCopyrightText: Copyright (C) 2026 Catcrafts®
module;
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <sys/uio.h>
#include <sys/time.h>
#include <sys/wait.h>
#include <sys/ioctl.h>
#include <netdb.h>
#include <strings.h>
#include <cerrno>
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 {
int status = send(socketid, reinterpret_cast<const char*>(buffer), size, 0);
if (status == 0) {
throw SocketClosedException();
} else if (status < 0) {
throw std::runtime_error(std::strerror(errno));
}
}
std::vector<char> ClientTCP::RecieveSync(std::uint32_t bufferSize) const {
std::vector<char> 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<char*>(buffer), bufferSize, 0);
}
std::vector<char> ClientTCP::RecieveSync() const {
int count;
ioctl(socketid, FIONREAD, &count);
if(count == 0){
count = 1024;
}
std::vector<char> 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<char> ClientTCP::RecieveUntilCloseSync() const {
int count;
ioctl(socketid, FIONREAD, &count);
if(count == 0){
count = 1024;
}
std::vector<char> 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<char> ClientTCP::RecieveUntilFullSync(std::uint32_t bufferSize) const {
std::vector<char> 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<void(std::vector<char>)> recieveCallback) const {
ThreadPool::Enqueue([recieveCallback, this, bufferSize](){
recieveCallback(this->RecieveSync(bufferSize));
});
}
void ClientTCP::RecieveAsync(std::uint32_t bufferSize, std::function<void(int)> recieveCallback, char* buffer) const {
ThreadPool::Enqueue([recieveCallback, this, bufferSize, buffer](){
recieveCallback(this->RecieveSync(bufferSize, buffer));
});
}
void ClientTCP::RecieveUntilFullAsync(std::uint32_t bufferSize, std::function<void(std::vector<char>)> recieveCallback) const {
ThreadPool::Enqueue([recieveCallback, this, bufferSize](){
recieveCallback(this->RecieveUntilFullSync(bufferSize));
});
}
void ClientTCP::RecieveAsync(std::function<void(std::vector<char>)> recieveCallback) const {
ThreadPool::Enqueue([this, recieveCallback](){
recieveCallback(this->RecieveSync());
});
}
void ClientTCP::RecieveUntilCloseAsync(std::function<void(std::vector<char>)> recieveCallback) const {
ThreadPool::Enqueue([this, recieveCallback](){
recieveCallback(this->RecieveUntilCloseSync());
});
}