diff --git a/README.md b/README.md index ab00155..ab9743f 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,127 @@ -# About +# Crafter.Network -C++ networking library \ No newline at end of file +A cross-platform C++ networking library providing TCP and HTTP client/server functionality with modern C++ features. + +## Overview + +Crafter.Network is a comprehensive networking library designed for modern C++ applications. It provides both TCP and HTTP networking capabilities with support for synchronous and asynchronous operations, making it suitable for a wide range of networking tasks. + +## Features + +- **TCP Networking**: Client and server implementations for TCP connections +- **HTTP Support**: Full HTTP client and server implementations with routing capabilities +- **Asynchronous Operations**: Thread pool-based async operations for improved performance +- **Cross-Platform**: Built for Unix-like systems with socket-based networking +- **Modern C++**: Uses C++ modules, STL containers, and modern C++ features + +## Architecture + +The library follows a modular design using C++20 modules: + +### Core Modules +- `Crafter.Network`: Main module that exports all components +- `Crafter.Network:ClientTCP`: TCP client implementation +- `Crafter.Network:ListenerTCP`: TCP server implementation +- `Crafter.Network:ClientHTTP`: HTTP client implementation +- `Crafter.Network:ListenerHTTP`: HTTP server implementation +- `Crafter.Network:HTTP`: HTTP protocol utilities and data structures + +## Components + +### TCP Components + +#### ClientTCP +```cpp +// Create a TCP client +Crafter::ClientTCP client("localhost", 8080); +client.Send("Hello World", 11); + +// Receive data +std::vector data = client.RecieveSync(); +``` + +#### ListenerTCP +```cpp +// Create a TCP listener +auto callback = [](Crafter::ClientTCP* client) { + // Handle new connection +}; +Crafter::ListenerTCP listener(8080, callback); +listener.ListenSyncSync(); // Synchronous listening +``` + +### HTTP Components + +#### ClientHTTP +```cpp +// Create an HTTP client +Crafter::ClientHTTP client("httpbin.org", 80); + +// Send HTTP request +std::string request = Crafter::CreateRequestHTTP("GET", "/get", "httpbin.org"); +Crafter::HTTPResponse response = client.Send(request); +``` + +#### ListenerHTTP +```cpp +// Create an HTTP listener with routes +std::unordered_map> routes; +routes["/hello"] = [](const Crafter::HTTPRequest& req) { + return Crafter::CreateResponseHTTP("200 OK", "Hello World!"); +}; + +Crafter::ListenerHTTP listener(8080, routes); +listener.Listen(); +``` + +## Build Configuration + +The project uses a configuration system with multiple build targets: + +- **base**: Core interfaces only +- **lib**: Static library build with dependencies +- **lib-debug**: Debug static library build +- **lib-shared**: Shared library build with dependencies + +## Testing + +The library includes comprehensive tests covering: +- Compilation verification +- HTTP receive functionality +- HTTP send functionality +- HTTP send/receive operations +- Keep-alive HTTP operations +- Large HTTP data transfers + +## Dependencies + +- Crafter.Thread: Thread pool management for asynchronous operations + +## Usage Example + +```cpp +#include +#include + +int main() { + // Simple HTTP client example + Crafter::ClientHTTP client("httpbin.org", 80); + + auto request = Crafter::CreateRequestHTTP("GET", "/get", "httpbin.org"); + auto response = client.Send(request); + + std::cout << "Status: " << response.status << std::endl; + std::cout << "Body: " << response.body << std::endl; + + return 0; +} +``` + +## License + +This library is licensed under the GNU Lesser General Public License version 3.0. See [LICENSE](LICENSE) for more information. + +## Copyright + +Copyright (C) 2025 Catcrafts® +Catcrafts.net \ No newline at end of file diff --git a/implementations/Crafter.Network-ClientHTTP.cpp b/implementations/Crafter.Network-ClientHTTP.cpp index 8b68b6f..22e2224 100644 --- a/implementations/Crafter.Network-ClientHTTP.cpp +++ b/implementations/Crafter.Network-ClientHTTP.cpp @@ -46,7 +46,9 @@ ClientHTTP::ClientHTTP(std::string host, std::uint16_t port): ClientHTTP(host.c_ } HTTPResponse ClientHTTP::Send(const char* request, std::uint32_t length) { + std::cout << "Send started" << std::endl; client.Send(request, length); + std::cout << "Send Complete" << std::endl; std::vector buffer; HTTPResponse response; std::uint32_t i = 0; @@ -54,11 +56,14 @@ HTTPResponse ClientHTTP::Send(const char* request, std::uint32_t length) { while(true) { try { buffer = client.RecieveSync(); + std::cout << "Recieved: " << buffer.size() << std::endl; } catch(const SocketClosedException& e) { + std::cout << "Retry" << std::endl; client.Stop(); client.Connect(); client.Send(request, length); buffer = client.RecieveSync(); + std::cout << "Recieved: " << buffer.size() << std::endl; } for(; i < buffer.size(); i++) { @@ -104,27 +109,29 @@ HTTPResponse ClientHTTP::Send(const char* request, std::uint32_t length) { i = 0; } headersComplete:; + std::cout << "Header complete" << std::endl; i+=4; std::unordered_map::iterator it = response.headers.find("content-length"); if(it != response.headers.end()) { const int lenght = std::stoi(it->second); + std::cout << "Content lenght: " << lenght << std::endl; response.body.resize(lenght, 0); if(i < buffer.size()){ std::memcpy(&response.body[0], buffer.data()+i, buffer.size()-i); } const int remaining = lenght-(buffer.size()-i); + std::cout << "Remain: " << remaining << std::endl; if(remaining > 0){ - int index = buffer.size()-i; - while(index < lenght) { - std::vector bodyBuffer = client.RecieveSync(remaining); - std::memcpy(&response.body[index], bodyBuffer.data(), bodyBuffer.size()); - index+=bodyBuffer.size(); - } + std::vector bodyBuffer = client.RecieveUntilFullSync(remaining); + std::memcpy(&response.body[ buffer.size()-i], bodyBuffer.data(), bodyBuffer.size()); + std::cout << "Recieved: " << bodyBuffer.size() << std::endl; } } else { + std::cout << "No Content Lenght" << std::endl; std::unordered_map::iterator it = response.headers.find("transfer-encoding"); if(it != response.headers.end() && it->second == "chunked") { + std::cout << "Chunked" << std::endl; while(i < buffer.size()){ std::string lenght; int lenghtStart = i; @@ -183,14 +190,17 @@ HTTPResponse ClientHTTP::Send(const char* request, std::uint32_t length) { } bodyFinished:; } else { + std::cout << "Recv until close" << std::endl; std::vector bodyBuffer = client.RecieveUntilCloseSync(); response.body.resize((buffer.size()-i)+(bodyBuffer.size()), 0); if(i < buffer.size()){ std::memcpy(&response.body[0], buffer.data()+i, buffer.size()-i); } std::memcpy(&response.body[buffer.size()-i], bodyBuffer.data(), bodyBuffer.size()); + std::cout << "Closed" << std::endl; } } + std::cout << "Response recieved" << std::endl; return response; } HTTPResponse ClientHTTP::Send(std::string request) { diff --git a/implementations/Crafter.Network-ClientTCP.cpp b/implementations/Crafter.Network-ClientTCP.cpp index 42fb537..58c517b 100755 --- a/implementations/Crafter.Network-ClientTCP.cpp +++ b/implementations/Crafter.Network-ClientTCP.cpp @@ -95,21 +95,12 @@ void ClientTCP::Stop() { } 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; + int status = send(socketid, reinterpret_cast(buffer), size, 0); - 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; + if (status == 0) { + throw SocketClosedException(); + } else if (status < 0) { + throw std::runtime_error(std::strerror(errno)); } } std::vector ClientTCP::RecieveSync(std::uint32_t bufferSize) const {