From c833204a5fbaa15e978a174138f68bff078bbd21 Mon Sep 17 00:00:00 2001 From: Emin Fedar Date: Thu, 15 Apr 2021 14:41:26 +0300 Subject: [PATCH 01/15] Timeout problem fixed. --- easysocket/include/tcpsocket.h | 7 ++----- easysocket/src/tcpsocket.cpp | 12 ++++++------ examples/tcp-client.cpp | 9 +++------ examples/tcp-server.cpp | 4 ++-- 4 files changed, 13 insertions(+), 19 deletions(-) diff --git a/easysocket/include/tcpsocket.h b/easysocket/include/tcpsocket.h index e0de8a6..2f040a1 100644 --- a/easysocket/include/tcpsocket.h +++ b/easysocket/include/tcpsocket.h @@ -14,7 +14,7 @@ class EASYSOCKET_API TCPSocket : public BaseSocket // Event Listeners: std::function onMessageReceived; std::function onRawMessageReceived; - std::function onSocketClosed; + std::function onSocketClosed; explicit TCPSocket(FDR_ON_ERROR, int socketId = -1); @@ -28,14 +28,11 @@ class EASYSOCKET_API TCPSocket : public BaseSocket void setAddressStruct(sockaddr_in addr); sockaddr_in getAddressStruct() const; - - void setTimeout(int seconds); - int getTimeout() const; private: static void Receive(TCPSocket *socket); - int timeout = 5; // 5 seconds timeout default. + void setTimeout(int seconds); }; #endif diff --git a/easysocket/src/tcpsocket.cpp b/easysocket/src/tcpsocket.cpp index cacc7be..b6f6b8a 100644 --- a/easysocket/src/tcpsocket.cpp +++ b/easysocket/src/tcpsocket.cpp @@ -1,8 +1,8 @@ #include #include + TCPSocket::TCPSocket(std::function onError, int socketId) : BaseSocket(onError, TCP, socketId) { - this->setTimeout(this->timeout); } int TCPSocket::Send(std::string message) @@ -55,6 +55,8 @@ void TCPSocket::Connect(uint32_t ipv4, uint16_t port, std::function onCo this->address.sin_port = htons(port); this->address.sin_addr.s_addr = ipv4; + this->setTimeout(5); + // Try to connect. if (connect(this->sock, (const sockaddr *)&this->address, sizeof(sockaddr_in)) < 0) { @@ -62,6 +64,8 @@ void TCPSocket::Connect(uint32_t ipv4, uint16_t port, std::function onCo return; } + this->setTimeout(0); + // Connected to the server, fire the event. onConnected(); @@ -86,7 +90,6 @@ sockaddr_in TCPSocket::getAddressStruct() const } void TCPSocket::setTimeout(int seconds) { - this->timeout = seconds; struct timeval tv; tv.tv_sec = seconds; tv.tv_usec = 0; @@ -94,9 +97,6 @@ void TCPSocket::setTimeout(int seconds) { setsockopt(this->sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(tv)); setsockopt(this->sock, SOL_SOCKET, SO_SNDTIMEO, (char *)&tv, sizeof(tv)); } -int TCPSocket::getTimeout() const{ - return this->timeout; -} void TCPSocket::Receive(TCPSocket *socket) { @@ -115,5 +115,5 @@ void TCPSocket::Receive(TCPSocket *socket) socket->Close(); if(socket->onSocketClosed) - socket->onSocketClosed(); + socket->onSocketClosed(errno); } diff --git a/examples/tcp-client.cpp b/examples/tcp-client.cpp index 1ea70f2..282b0d5 100644 --- a/examples/tcp-client.cpp +++ b/examples/tcp-client.cpp @@ -7,9 +7,6 @@ int main() { // Initialize socket. TCPSocket tcpSocket; - - // Set connection timeout seconds. - tcpSocket.setTimeout(5); // Start receiving from the host. tcpSocket.onMessageReceived = [](string message) { @@ -23,12 +20,12 @@ int main() */ // On socket closed: - tcpSocket.onSocketClosed = []{ - cout << "Connection closed." << endl; + tcpSocket.onSocketClosed = [](int errorCode){ + cout << "Connection closed: " << errorCode << endl; }; // Connect to the host. - tcpSocket.Connect("54.23.12.43", 8888, [&] { + tcpSocket.Connect("localhost", 8888, [&] { cout << "Connected to the server successfully." << endl; // Send String: diff --git a/examples/tcp-server.cpp b/examples/tcp-server.cpp index 4071321..af27e3f 100644 --- a/examples/tcp-server.cpp +++ b/examples/tcp-server.cpp @@ -26,8 +26,8 @@ int main() }; */ - newClient->onSocketClosed = [newClient]() { - cout << "Socket closed:" << newClient->remoteAddress() << ":" << newClient->remotePort() << endl; + newClient->onSocketClosed = [newClient](int errorCode) { + cout << "Socket closed:" << newClient->remoteAddress() << ":" << newClient->remotePort() << " -> " << errorCode << endl; }; }; From 52d7fcdbcedd3fc87d30b557c19e695cb10940c5 Mon Sep 17 00:00:00 2001 From: Malcolm Mielle Date: Mon, 6 Sep 2021 22:22:10 +0200 Subject: [PATCH 02/15] Update Thread and add install targets --- CMakeLists.txt | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index fa73ec5..3d87f99 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,6 +2,7 @@ cmake_minimum_required(VERSION 3.17) project(async_sockets_cpp) set(CMAKE_CXX_STANDARD 14) +find_package (Threads REQUIRED) add_library(async_sockets STATIC easysocket/include/basesocket.h easysocket/include/DllHelper.h @@ -14,14 +15,30 @@ add_library(async_sockets STATIC easysocket/include/basesocket.h easysocket/src/tcpsocket.cpp easysocket/src/udpserver.cpp easysocket/src/udpsocket.cpp) -target_include_directories(async_sockets PUBLIC easysocket/include) +target_include_directories(async_sockets PUBLIC + $ + $ + ) + +target_link_libraries(async_sockets PUBLIC Threads::Threads) add_executable(tcp-client examples/tcp-client.cpp) add_executable(tcp-server examples/tcp-server.cpp) add_executable(udp-client examples/udp-client.cpp) add_executable(udp-server examples/udp-server.cpp) -target_link_libraries(tcp-client async_sockets) -target_link_libraries(tcp-server async_sockets) -target_link_libraries(udp-client async_sockets) -target_link_libraries(udp-server async_sockets) +target_link_libraries(tcp-client PUBLIC async_sockets) +target_link_libraries(tcp-server PUBLIC async_sockets) +target_link_libraries(udp-client PUBLIC async_sockets) +target_link_libraries(udp-server PUBLIC async_sockets) + +set(FILESEASYSOCKET + easysocket/include/basesocket.h + easysocket/include/DllHelper.h + easysocket/include/tcpserver.h + easysocket/include/tcpsocket.h + easysocket/include/udpserver.h + easysocket/include/udpsocket.h) + +install(TARGETS async_sockets DESTINATION lib) +install(FILES ${FILESEASYSOCKET} DESTINATION include) From 605975317a6e78d33c7bc8fe644af8bec0f98657 Mon Sep 17 00:00:00 2001 From: Malcolm Mielle Date: Mon, 6 Sep 2021 22:43:07 +0200 Subject: [PATCH 03/15] Switch to CMAKE_CURRENT_SOURCE_DIR to allow FetchContent --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3d87f99..274e0e2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,7 +16,7 @@ add_library(async_sockets STATIC easysocket/include/basesocket.h easysocket/src/udpserver.cpp easysocket/src/udpsocket.cpp) target_include_directories(async_sockets PUBLIC - $ + $ $ ) From ac946e44fff3808d7556fda94a36a77aadc37b0c Mon Sep 17 00:00:00 2001 From: Emin Fedar Date: Thu, 9 Sep 2021 14:22:38 +0300 Subject: [PATCH 04/15] MAJOR: Transform to Header-only library. --- CMakeLists.txt | 44 ------- MakeHelper | 55 -------- README.md | 10 +- async-sockets/include/basesocket.hpp | 70 ++++++++++ async-sockets/include/tcpserver.hpp | 87 +++++++++++++ async-sockets/include/tcpsocket.hpp | 124 ++++++++++++++++++ async-sockets/include/udpserver.hpp | 30 +++++ async-sockets/include/udpsocket.hpp | 184 +++++++++++++++++++++++++++ async-sockets/install.sh | 14 ++ async-sockets/remove.sh | 7 + easysocket/Makefile | 86 ------------- easysocket/include/DllHelper.h | 20 --- easysocket/include/basesocket.h | 49 ------- easysocket/include/tcpserver.h | 33 ----- easysocket/include/tcpsocket.h | 38 ------ easysocket/include/udpserver.h | 18 --- easysocket/include/udpsocket.h | 33 ----- easysocket/install.sh | 6 - easysocket/remove.sh | 4 - easysocket/src/basesocket.cpp | 40 ------ easysocket/src/tcpserver.cpp | 77 ----------- easysocket/src/tcpsocket.cpp | 119 ----------------- easysocket/src/udpserver.cpp | 27 ---- easysocket/src/udpsocket.cpp | 171 ------------------------- examples/CMakeLists.txt | 21 +++ examples/Makefile | 59 +++------ examples/tcp-client.cpp | 6 +- examples/tcp-server.cpp | 3 +- examples/udp-client.cpp | 2 +- examples/udp-server.cpp | 2 +- 30 files changed, 569 insertions(+), 870 deletions(-) delete mode 100644 CMakeLists.txt delete mode 100644 MakeHelper create mode 100644 async-sockets/include/basesocket.hpp create mode 100644 async-sockets/include/tcpserver.hpp create mode 100644 async-sockets/include/tcpsocket.hpp create mode 100644 async-sockets/include/udpserver.hpp create mode 100644 async-sockets/include/udpsocket.hpp create mode 100755 async-sockets/install.sh create mode 100755 async-sockets/remove.sh delete mode 100644 easysocket/Makefile delete mode 100644 easysocket/include/DllHelper.h delete mode 100644 easysocket/include/basesocket.h delete mode 100644 easysocket/include/tcpserver.h delete mode 100644 easysocket/include/tcpsocket.h delete mode 100644 easysocket/include/udpserver.h delete mode 100644 easysocket/include/udpsocket.h delete mode 100755 easysocket/install.sh delete mode 100755 easysocket/remove.sh delete mode 100644 easysocket/src/basesocket.cpp delete mode 100644 easysocket/src/tcpserver.cpp delete mode 100644 easysocket/src/tcpsocket.cpp delete mode 100644 easysocket/src/udpserver.cpp delete mode 100644 easysocket/src/udpsocket.cpp create mode 100644 examples/CMakeLists.txt diff --git a/CMakeLists.txt b/CMakeLists.txt deleted file mode 100644 index 274e0e2..0000000 --- a/CMakeLists.txt +++ /dev/null @@ -1,44 +0,0 @@ -cmake_minimum_required(VERSION 3.17) -project(async_sockets_cpp) - -set(CMAKE_CXX_STANDARD 14) -find_package (Threads REQUIRED) - -add_library(async_sockets STATIC easysocket/include/basesocket.h - easysocket/include/DllHelper.h - easysocket/include/tcpserver.h - easysocket/include/tcpsocket.h - easysocket/include/udpserver.h - easysocket/include/udpsocket.h - easysocket/src/basesocket.cpp - easysocket/src/tcpserver.cpp - easysocket/src/tcpsocket.cpp - easysocket/src/udpserver.cpp - easysocket/src/udpsocket.cpp) -target_include_directories(async_sockets PUBLIC - $ - $ - ) - -target_link_libraries(async_sockets PUBLIC Threads::Threads) - -add_executable(tcp-client examples/tcp-client.cpp) -add_executable(tcp-server examples/tcp-server.cpp) -add_executable(udp-client examples/udp-client.cpp) -add_executable(udp-server examples/udp-server.cpp) - -target_link_libraries(tcp-client PUBLIC async_sockets) -target_link_libraries(tcp-server PUBLIC async_sockets) -target_link_libraries(udp-client PUBLIC async_sockets) -target_link_libraries(udp-server PUBLIC async_sockets) - -set(FILESEASYSOCKET - easysocket/include/basesocket.h - easysocket/include/DllHelper.h - easysocket/include/tcpserver.h - easysocket/include/tcpsocket.h - easysocket/include/udpserver.h - easysocket/include/udpsocket.h) - -install(TARGETS async_sockets DESTINATION lib) -install(FILES ${FILESEASYSOCKET} DESTINATION include) diff --git a/MakeHelper b/MakeHelper deleted file mode 100644 index c4bd21b..0000000 --- a/MakeHelper +++ /dev/null @@ -1,55 +0,0 @@ -#!make - -#OS Commands -define NoTrailSlash -$(patsubst %\\,%,$(patsubst %/,%,$(1))) -endef -define MakeExe -$(1)$(EXEEXT) -endef - -#If Windows -ifeq ($(OS), Windows_NT) - -DLLEXT := .dll -EXEEXT := .exe - -define ReplaceSlash -$(subst /,\\,$(1)) -endef -define MakeLib -$(1)$(DLLEXT) -endef -define RM --del /F /Q $(call ReplaceSlash,$(call NoTrailSlash,$(1))) -endef -define MD --mkdir $(call ReplaceSlash,$(call NoTrailSlash,$(1))) -endef -define CP --robocopy $(call ReplaceSlash,$(1)) $(call ReplaceSlash,$(2)) /E /is -endef - -else -#If not Windows, assume Linux - -DLLEXT := .so -EXEEXT := - -define ReplaceSlash -$(subst \\,/,$(1)) -endef -define MakeLib -lib$(1)$(DLLEXT) -endef -define RM -rm -rf $(1) -endef -define MD -mkdir -p $(1) -endef -define CP -cp -rf $(1) $(2) -endef - -endif diff --git a/README.md b/README.md index dd16d5a..3edf842 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,6 @@ # Asynchronous Sockets for C++ -Simple, thread-based, non-blocking asynchronous Client-Server classes in C++ for TCP & UDP. +Simple, multithread-based(not thread safe), non-blocking asynchronous Client-Server classes in C++ for TCP & UDP. +Creates a thread for every connection. Use `mutex`es or `atomic` variables to provide thread-safe functions. ```cpp // Initialize a tcp socket. @@ -27,6 +28,7 @@ You can compile all the examples by just going in the `examples/` directory and - [examples/tcp-server.cpp](https://github.com/eminfedar/async-sockets-cpp/blob/master/examples/tcp-server.cpp) - [examples/udp-client.cpp](https://github.com/eminfedar/async-sockets-cpp/blob/master/examples/udp-client.cpp) - [examples/udp-server.cpp](https://github.com/eminfedar/async-sockets-cpp/blob/master/examples/udp-server.cpp) - -## Future TO-DOs: -- Add Windows support (the library is only for *nix based systems like Linux & MacOS.) + +## Supported Platforms: +- Linux +- MacOS (not tested) diff --git a/async-sockets/include/basesocket.hpp b/async-sockets/include/basesocket.hpp new file mode 100644 index 0000000..144dcbf --- /dev/null +++ b/async-sockets/include/basesocket.hpp @@ -0,0 +1,70 @@ +#pragma once + +#if defined(__linux__) || defined(__APPLE__) +#include +#include +#include +#include +#include +#elif _WIN32 +#include +#endif + +#include +#include +#include + +#define FDR_UNUSED(expr){ (void)(expr); } +#define FDR_ON_ERROR std::function onError = [](int errorCode, std::string errorMessage){FDR_UNUSED(errorCode); FDR_UNUSED(errorMessage)} + +class BaseSocket +{ +// Definitions +public: + enum SocketType + { + TCP = SOCK_STREAM, + UDP = SOCK_DGRAM + }; + const uint16_t BUFFER_SIZE = 0xFFFF; + sockaddr_in address; + bool isClosed = false; + +protected: + int sock = 0; + static std::string ipToString(sockaddr_in addr) + { + char ip[INET_ADDRSTRLEN]; + inet_ntop(AF_INET, &(addr.sin_addr), ip, INET_ADDRSTRLEN); + + return std::string(ip); + } + + BaseSocket(FDR_ON_ERROR, SocketType sockType = TCP, int socketId = -1) + { + if (socketId < 0) + { + if ((this->sock = socket(AF_INET, sockType, 0)) < 0) + { + onError(errno, "Socket creating error."); + } + } + else + { + this->sock = socketId; + } + } + +// Methods +public: + virtual void Close() { + if(isClosed) return; + + isClosed = true; + close(this->sock); + } + + std::string remoteAddress() {return ipToString(this->address);} + int remotePort() {return ntohs(this->address.sin_port);} + int fileDescriptor() const { return this->sock; } +}; \ No newline at end of file diff --git a/async-sockets/include/tcpserver.hpp b/async-sockets/include/tcpserver.hpp new file mode 100644 index 0000000..3ed2737 --- /dev/null +++ b/async-sockets/include/tcpserver.hpp @@ -0,0 +1,87 @@ +#pragma once + +#include "tcpsocket.hpp" +#include + +class TCPServer : public BaseSocket +{ +public: + // Event Listeners: + std::function onNewConnection = [](TCPSocket* sock){FDR_UNUSED(sock)}; + + explicit TCPServer(FDR_ON_ERROR): BaseSocket(onError, SocketType::TCP) + { + int opt = 1; + setsockopt(this->sock,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(int)); + setsockopt(this->sock,SOL_SOCKET,SO_REUSEPORT,&opt,sizeof(int)); + } + + // Binding the server. + void Bind(const char *address, uint16_t port, FDR_ON_ERROR) + { + if (inet_pton(AF_INET, address, &this->address.sin_addr) <= 0) + { + onError(errno, "Invalid address. Address type not supported."); + return; + } + + this->address.sin_family = AF_INET; + this->address.sin_port = htons(port); + + if (bind(this->sock, (const sockaddr *)&this->address, sizeof(this->address)) < 0) + { + onError(errno, "Cannot bind the socket."); + return; + } + } + void Bind(int port, FDR_ON_ERROR) { this->Bind("0.0.0.0", port, onError); } + + // Start listening the server. + void Listen(FDR_ON_ERROR) + { + if (listen(this->sock, 20) < 0) + { + onError(errno, "Error: Server can't listen the socket."); + return; + } + + std::thread t(Accept, this, onError); + t.detach(); + } + + // Overriding Close to add shutdown(): + void Close() + { + shutdown(this->sock, SHUT_RDWR); + + BaseSocket::Close(); + } + +private: + static void Accept(TCPServer *server, FDR_ON_ERROR) + { + sockaddr_in newSocketInfo; + socklen_t newSocketInfoLength = sizeof(newSocketInfo); + + int newSock; + while (!server->isClosed) + { + while ((newSock = accept(server->sock, (sockaddr *)&newSocketInfo, &newSocketInfoLength)) < 0) + { + if (errno == EBADF || errno == EINVAL) return; + + onError(errno, "Error while accepting a new connection."); + return; + } + + if (!server->isClosed && newSock >= 0) + { + TCPSocket *newSocket = new TCPSocket(onError, newSock); + newSocket->setAddressStruct(newSocketInfo); + + server->onNewConnection(newSocket); + newSocket->Listen(); + } + } + } +}; \ No newline at end of file diff --git a/async-sockets/include/tcpsocket.hpp b/async-sockets/include/tcpsocket.hpp new file mode 100644 index 0000000..66f9455 --- /dev/null +++ b/async-sockets/include/tcpsocket.hpp @@ -0,0 +1,124 @@ +#pragma once + +#include "basesocket.hpp" +#include +#include +#include +#include + +class TCPSocket : public BaseSocket +{ +public: + // Event Listeners: + std::function onMessageReceived; + std::function onRawMessageReceived; + std::function onSocketClosed; + + explicit TCPSocket(FDR_ON_ERROR, int socketId = -1) : BaseSocket(onError, TCP, socketId){} + + // Send TCP Packages + int Send(const char *bytes, size_t byteslength) + { + if (this->isClosed) + return -1; + + int sent = 0; + if ((sent = send(this->sock, bytes, byteslength, 0)) < 0) + { + perror("send"); + } + return sent; + } + int Send(std::string message) { return this->Send(message.c_str(), message.length()); } + + void Connect(std::string host, uint16_t port, std::function onConnected = [](){}, FDR_ON_ERROR) + { + struct addrinfo hints, *res, *it; + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_STREAM; + + // Get address info from DNS + int status; + if ((status = getaddrinfo(host.c_str(), NULL, &hints, &res)) != 0) { + onError(errno, "Invalid address." + std::string(gai_strerror(status))); + return; + } + + for(it = res; it != NULL; it = it->ai_next) + { + if (it->ai_family == AF_INET) { // IPv4 + memcpy((void*)(&this->address), (void*)it->ai_addr, sizeof(sockaddr_in)); + break; // for now, just get first ip (ipv4). + } + } + + freeaddrinfo(res); + + this->Connect((uint32_t)this->address.sin_addr.s_addr, port, onConnected, onError); + } + void Connect(uint32_t ipv4, uint16_t port, std::function onConnected = [](){}, FDR_ON_ERROR) + { + this->address.sin_family = AF_INET; + this->address.sin_port = htons(port); + this->address.sin_addr.s_addr = ipv4; + + this->setTimeout(5); + + // Try to connect. + if (connect(this->sock, (const sockaddr *)&this->address, sizeof(sockaddr_in)) < 0) + { + onError(errno, "Connection failed to the host."); + this->setTimeout(0); + return; + } + + this->setTimeout(0); + + // Connected to the server, fire the event. + onConnected(); + + // Start listening from server: + this->Listen(); + } + + void Listen() + { + std::thread t(TCPSocket::Receive, this); + t.detach(); + } + + void setAddressStruct(sockaddr_in addr) {this->address = addr;} + sockaddr_in getAddressStruct() const {return this->address;} + +private: + static void Receive(TCPSocket *socket) + { + char tempBuffer[socket->BUFFER_SIZE]; + int messageLength; + + while ((messageLength = recv(socket->sock, tempBuffer, socket->BUFFER_SIZE, 0)) > 0) + { + tempBuffer[messageLength] = '\0'; + if(socket->onMessageReceived) + socket->onMessageReceived(std::string(tempBuffer, messageLength)); + + if(socket->onRawMessageReceived) + socket->onRawMessageReceived(tempBuffer, messageLength); + } + + socket->Close(); + if(socket->onSocketClosed) + socket->onSocketClosed(errno); + } + + void setTimeout(int seconds) + { + struct timeval tv; + tv.tv_sec = seconds; + tv.tv_usec = 0; + + setsockopt(this->sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(tv)); + setsockopt(this->sock, SOL_SOCKET, SO_SNDTIMEO, (char *)&tv, sizeof(tv)); + } +}; diff --git a/async-sockets/include/udpserver.hpp b/async-sockets/include/udpserver.hpp new file mode 100644 index 0000000..06f4794 --- /dev/null +++ b/async-sockets/include/udpserver.hpp @@ -0,0 +1,30 @@ +#pragma once + +#include "udpsocket.hpp" +#include + +class UDPServer : public UDPSocket +{ +public: + void Bind(std::string IPv4, std::uint16_t port, FDR_ON_ERROR) + { + if (inet_pton(AF_INET, IPv4.c_str(), &this->address.sin_addr) <= 0) + { + onError(errno, "Invalid address. Address type not supported."); + return; + } + + this->address.sin_family = AF_INET; + this->address.sin_port = htons(port); + + if (bind(this->sock, (const sockaddr *)&this->address, sizeof(this->address)) < 0) + { + onError(errno, "Cannot bind the socket."); + return; + } + } + void Bind(int port, FDR_ON_ERROR) + { + this->Bind("0.0.0.0", port, onError); + } +}; \ No newline at end of file diff --git a/async-sockets/include/udpsocket.hpp b/async-sockets/include/udpsocket.hpp new file mode 100644 index 0000000..11b7783 --- /dev/null +++ b/async-sockets/include/udpsocket.hpp @@ -0,0 +1,184 @@ +#pragma once + +#include "basesocket.hpp" +#include +#include + +class UDPSocket : public BaseSocket +{ +public: + std::function onMessageReceived; + std::function onRawMessageReceived; + + explicit UDPSocket(bool useConnect = false, FDR_ON_ERROR, int socketId = -1): BaseSocket(onError, SocketType::UDP, socketId) + { + if (useConnect) + { + + std::thread t(Receive, this); // usage with Connect() + t.detach(); + } + else + { + std::thread t(ReceiveFrom, this); + t.detach(); + } + } + + // SendTo with no connection + void SendTo(const char *bytes, size_t byteslength, std::string host, uint16_t port, FDR_ON_ERROR) + { + sockaddr_in hostAddr; + + struct addrinfo hints, *res, *it; + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_DGRAM; + + int status; + if ((status = getaddrinfo(host.c_str(), NULL, &hints, &res)) != 0) + { + onError(errno, "Invalid address." + std::string(gai_strerror(status))); + return; + } + + for (it = res; it != NULL; it = it->ai_next) + { + if (it->ai_family == AF_INET) + { // IPv4 + memcpy((void *)(&hostAddr), (void *)it->ai_addr, sizeof(sockaddr_in)); + break; // for now, just get first ip (ipv4). + } + } + + freeaddrinfo(res); + + hostAddr.sin_port = htons(port); + hostAddr.sin_family = AF_INET; + + if (sendto(this->sock, bytes, byteslength, 0, (sockaddr *)&hostAddr, sizeof(hostAddr)) < 0) + { + onError(errno, "Cannot send message to the address."); + return; + } + } + void SendTo(std::string message, std::string host, uint16_t port, FDR_ON_ERROR) + { + this->SendTo(message.c_str(), message.length(), host, port, onError); + } + + // Send with Connect() + int Send(const char *bytes, size_t byteslength) + { + if (this->isClosed) + return -1; + + int sent = 0; + if ((sent = send(this->sock, bytes, byteslength, 0)) < 0) + { + perror("send"); + } + return sent; + } + int Send(std::string message) + { + return this->Send(message.c_str(), message.length()); + } + + // To use "Send()", need to call Connect() first + void Connect(uint32_t ipv4, uint16_t port, FDR_ON_ERROR) + { + this->address.sin_family = AF_INET; + this->address.sin_port = htons(port); + this->address.sin_addr.s_addr = ipv4; + + // Try to connect. + if (connect(this->sock, (const sockaddr *)&this->address, sizeof(sockaddr_in)) < 0) + { + onError(errno, "Connection failed to the host."); + return; + } + } + void Connect(std::string host, uint16_t port, FDR_ON_ERROR) + { + struct addrinfo hints, *res, *it; + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_DGRAM; + + int status; + if ((status = getaddrinfo(host.c_str(), NULL, &hints, &res)) != 0) + { + onError(errno, "Invalid address." + std::string(gai_strerror(status))); + return; + } + + for (it = res; it != NULL; it = it->ai_next) + { + if (it->ai_family == AF_INET) + { // IPv4 + memcpy((void *)(&this->address), (void *)it->ai_addr, sizeof(sockaddr_in)); + break; // for now, just get first ip (ipv4). + } + } + + freeaddrinfo(res); + + this->Connect((uint32_t)this->address.sin_addr.s_addr, port, onError); + } + +private: + static void Receive(UDPSocket *udpSocket) + { + char tempBuffer[udpSocket->BUFFER_SIZE]; + + while (true) + { + int messageLength; + messageLength = recv(udpSocket->sock, tempBuffer, udpSocket->BUFFER_SIZE, 0); + + if (messageLength < 0) + { + perror("recvfrom"); + return; + } + else + { + tempBuffer[messageLength] = '\0'; + if (udpSocket->onMessageReceived) + udpSocket->onMessageReceived(std::string(tempBuffer, messageLength), ipToString(udpSocket->address), ntohs(udpSocket->address.sin_port)); + + if (udpSocket->onRawMessageReceived) + udpSocket->onRawMessageReceived(tempBuffer, messageLength, ipToString(udpSocket->address), ntohs(udpSocket->address.sin_port)); + } + } + } + static void ReceiveFrom(UDPSocket *udpSocket) + { + sockaddr_in hostAddr; + socklen_t hostAddrSize = sizeof(hostAddr); + + char tempBuffer[udpSocket->BUFFER_SIZE]; + + while (true) + { + int messageLength; + messageLength = recvfrom(udpSocket->sock, tempBuffer, udpSocket->BUFFER_SIZE, 0, (sockaddr *)&hostAddr, &hostAddrSize); + + if (messageLength < 0) + { + perror("recvfrom"); + return; + } + else + { + tempBuffer[messageLength] = '\0'; + if (udpSocket->onMessageReceived) + udpSocket->onMessageReceived(std::string(tempBuffer, messageLength), ipToString(hostAddr), ntohs(hostAddr.sin_port)); + + if (udpSocket->onRawMessageReceived) + udpSocket->onRawMessageReceived(tempBuffer, messageLength, ipToString(hostAddr), ntohs(hostAddr.sin_port)); + } + } + } +}; \ No newline at end of file diff --git a/async-sockets/install.sh b/async-sockets/install.sh new file mode 100755 index 0000000..a6bdd4b --- /dev/null +++ b/async-sockets/install.sh @@ -0,0 +1,14 @@ +#!/bin/bash +if [[ $EUID -ne 0 ]]; then + echo "This script must be run as root" + exit 1 +fi + +rm -rf /usr/local/include/async-sockets +mkdir /usr/local/include/async-sockets +cp -fR ./include/* /usr/local/include/async-sockets/ + +echo "Info: The library has been copied to -> /usr/local/include"; +echo "" +echo "Example usage:" +echo "#include " diff --git a/async-sockets/remove.sh b/async-sockets/remove.sh new file mode 100755 index 0000000..f816502 --- /dev/null +++ b/async-sockets/remove.sh @@ -0,0 +1,7 @@ +#!/bin/bash +if [[ $EUID -ne 0 ]]; then + echo "This script must be run as root" + exit 1 +fi + +rm -rf /usr/local/include/async-sockets diff --git a/easysocket/Makefile b/easysocket/Makefile deleted file mode 100644 index 705783b..0000000 --- a/easysocket/Makefile +++ /dev/null @@ -1,86 +0,0 @@ -#!make -# This make needs: -# g++ -# - -include ../MakeHelper - -# Project name -NAME := $(patsubst %/,%,$(notdir $(CURDIR))) - -#The Target Binary Program -TARGET := $(call MakeLib,$(NAME)) - -#The Directories, Source, Includes, Objects, Binary and Resources -SRCDIR ?= $(CURDIR)/src -INCDIR ?= $(CURDIR)/include -BUILDDIR ?= $(CURDIR)/obj/$(BUILD) -TARGETDIR ?= $(CURDIR)/bin/$(BUILD) -RESDIR ?= $(CURDIR)/rsc -SRCEXT := .cpp -OBJEXT := .o - -#Compiler and Linker -BUILD ?= release -CC := g++ - -#Flags, Libraries and Includes -CFLAGS.common := -std=c++17 -fPIC -Wall -Wextra -DBUILD_EASYSOCKET -CFLAGS.debug := $(CFLAGS.common) -g -CFLAGS.release := $(CFLAGS.common) -Werror -O3 -CFLAGS ?= $(CFLAGS.$(BUILD)) -LIB := -L$(TARGETDIR) -INC := -I$(INCDIR) - -#--------------------------------------------------------------------------------- -#DO NOT EDIT BELOW THIS LINE -#--------------------------------------------------------------------------------- -SOURCES := $(wildcard $(SRCDIR)/*$(SRCEXT)) -OBJECTS := $(patsubst $(SRCDIR)/%,$(BUILDDIR)/%,$(SOURCES:$(SRCEXT)=$(OBJEXT))) - -#Default Make -all: resources $(TARGET) tests docs - -#Remake -remake: cleaner all - -#Create template folder structure -template: directories - $(call MD,$(SRCDIR)) - $(call MD,$(INCDIR)) - $(call MD,$(RESDIR)) - -#Make the Directories -directories: - $(call MD,$(TARGETDIR)) - $(call MD,$(BUILDDIR)) - -#Copy Resources from Resources Directory to Target Directory -resources: template -# @$(call CP,$(RESDIR)/*,$(TARGETDIR)/) - -#Clean only Objecst -clean: - $(call RM,$(BUILDDIR)) - -#Full Clean, Objects and Binaries -cleaner: clean - $(call RM,$(TARGETDIR)) - -docs: -#TODO - -tests: -#TODO - -#Link the final executable/library -$(TARGET): $(OBJECTS) - $(CC) -shared -o $(TARGETDIR)/$(TARGET) $^ $(LIB) - -#Compile -$(BUILDDIR)/%$(OBJEXT): $(SRCDIR)/%$(SRCEXT) - $(call MD,$(dir $@)) - $(CC) $(CFLAGS) $(INC) -c -o $@ $< - -#Non-File Targets -.PHONY: all remake template directories resources clean cleaner diff --git a/easysocket/include/DllHelper.h b/easysocket/include/DllHelper.h deleted file mode 100644 index f553613..0000000 --- a/easysocket/include/DllHelper.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifdef BUILD_EASYSOCKET -#define EASYSOCKET_API EXPORT_EASYSOCKET -#else -#define EASYSOCKET_API IMPORT_EASYSOCKET -#endif - -#if defined(_MSC_VER) - // Microsoft - #define EXPORT_EASYSOCKET __declspec(dllexport) - #define IMPORT_EASYSOCKET __declspec(dllimport) -#elif defined(__GNUC__) - // GCC - #define EXPORT_EASYSOCKET __attribute__((visibility("default"))) - #define IMPORT_EASYSOCKET -#else - // do nothing and hope for the best? - #define EXPORT_EASYSOCKET - #define IMPORT_EASYSOCKET - #pragma warning Unknown dynamic link import/export semantics. -#endif diff --git a/easysocket/include/basesocket.h b/easysocket/include/basesocket.h deleted file mode 100644 index 0dfdc61..0000000 --- a/easysocket/include/basesocket.h +++ /dev/null @@ -1,49 +0,0 @@ -#ifndef FDR_BASESOCKET_H -#define FDR_BASESOCKET_H - -#include "DllHelper.h" - -#if defined(__linux__) || defined(__APPLE__) -#include -#include -#include -#include -#include -#elif _WIN32 -#include -#endif - -#include -#include - -#define FDR_UNUSED(expr){ (void)(expr); } -#define FDR_ON_ERROR std::function onError = [](int errorCode, std::string errorMessage){FDR_UNUSED(errorCode); FDR_UNUSED(errorMessage)} - -class EASYSOCKET_API BaseSocket -{ -protected: - int sock = 0; - - static std::string ipToString(sockaddr_in addr); - -public: - const uint16_t BUFFER_SIZE = 0xFFFF; - enum EASYSOCKET_API SocketType - { - TCP = SOCK_STREAM, - UDP = SOCK_DGRAM - }; - - sockaddr_in address; - bool isClosed = false; - - explicit BaseSocket(FDR_ON_ERROR, SocketType sockType = TCP, int socketId = -1); - - virtual void Close(); - - std::string remoteAddress(); - int remotePort(); - int fileDescriptor() const { return this->sock; } -}; - -#endif diff --git a/easysocket/include/tcpserver.h b/easysocket/include/tcpserver.h deleted file mode 100644 index f6d83b3..0000000 --- a/easysocket/include/tcpserver.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef FDR_TCPSERVER_H -#define FDR_TCPSERVER_H - -#include "DllHelper.h" - -#include "tcpsocket.h" -#include -#include -#include - -class EASYSOCKET_API TCPServer : public BaseSocket -{ -public: - // Event Listeners: - std::function onNewConnection = [](TCPSocket* sock){FDR_UNUSED(sock)}; - - explicit TCPServer(FDR_ON_ERROR); - - // Binding the server. - void Bind(int port, FDR_ON_ERROR); - void Bind(const char *address, uint16_t port, FDR_ON_ERROR); - - // Start listening the server. - void Listen(FDR_ON_ERROR); - - // Overriding Close to add shutdown(): - void Close() override; - -private: - static void Accept(TCPServer *server, FDR_ON_ERROR); -}; - -#endif diff --git a/easysocket/include/tcpsocket.h b/easysocket/include/tcpsocket.h deleted file mode 100644 index 2f040a1..0000000 --- a/easysocket/include/tcpsocket.h +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef FDR_TCPSOCKET_H -#define FDR_TCPSOCKET_H - -#include "DllHelper.h" - -#include "basesocket.h" -#include -#include -#include - -class EASYSOCKET_API TCPSocket : public BaseSocket -{ -public: - // Event Listeners: - std::function onMessageReceived; - std::function onRawMessageReceived; - std::function onSocketClosed; - - explicit TCPSocket(FDR_ON_ERROR, int socketId = -1); - - int Send(std::string message); - int Send(const char *bytes, size_t byteslength); - - void Connect(std::string host, uint16_t port, std::function onConnected = [](){}, FDR_ON_ERROR); - void Connect(uint32_t ipv4, uint16_t port, std::function onConnected = [](){}, FDR_ON_ERROR); - - void Listen(); - - void setAddressStruct(sockaddr_in addr); - sockaddr_in getAddressStruct() const; - -private: - static void Receive(TCPSocket *socket); - - void setTimeout(int seconds); -}; - -#endif diff --git a/easysocket/include/udpserver.h b/easysocket/include/udpserver.h deleted file mode 100644 index 5a8922f..0000000 --- a/easysocket/include/udpserver.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef FDR_UDPSERVER_H -#define FDR_UDPSERVER_H - -#include "DllHelper.h" - -#include "udpsocket.h" -#include - -class EASYSOCKET_API UDPServer : public UDPSocket -{ -public: - UDPServer(); - - void Bind(int port, FDR_ON_ERROR); - void Bind(std::string IPv4, std::uint16_t port, FDR_ON_ERROR); -}; - -#endif diff --git a/easysocket/include/udpsocket.h b/easysocket/include/udpsocket.h deleted file mode 100644 index ecc5691..0000000 --- a/easysocket/include/udpsocket.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef FDR_UDPSOCKET_H -#define FDR_UDPSOCKET_H - -#include "DllHelper.h" - -#include "basesocket.h" -#include -#include -#include - -class EASYSOCKET_API UDPSocket : public BaseSocket -{ -public: - std::function onMessageReceived; - std::function onRawMessageReceived; - - explicit UDPSocket(bool useConnect = false, FDR_ON_ERROR, int socketId = -1); - - void SendTo(std::string message, std::string host, uint16_t port, FDR_ON_ERROR); - void SendTo(const char *bytes, size_t byteslength, std::string host, uint16_t port, FDR_ON_ERROR); - - int Send(std::string message); - int Send(const char *bytes, size_t byteslength); - - void Connect(std::string host, uint16_t port, FDR_ON_ERROR); - void Connect(uint32_t ipv4, uint16_t port, FDR_ON_ERROR); - -private: - static void Receive(UDPSocket *udpSocket); - static void ReceiveFrom(UDPSocket *udpSocket); -}; - -#endif diff --git a/easysocket/install.sh b/easysocket/install.sh deleted file mode 100755 index a58e8e0..0000000 --- a/easysocket/install.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/sh - -rm -rf /usr/local/include/easysocket -mkdir /usr/local/include/easysocket -cp -f ./bin/release/libeasysocket.so /usr/lib/x86_64-linux-gnu/libeasysocket.so -cp -fR ./include/* /usr/local/include/easysocket/ diff --git a/easysocket/remove.sh b/easysocket/remove.sh deleted file mode 100755 index 2c7cbf8..0000000 --- a/easysocket/remove.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/sh - -rm -rf /usr/local/include/easysocket -rm /usr/lib/x86_64-linux-gnu/libeasysocket.so \ No newline at end of file diff --git a/easysocket/src/basesocket.cpp b/easysocket/src/basesocket.cpp deleted file mode 100644 index 2d99d2a..0000000 --- a/easysocket/src/basesocket.cpp +++ /dev/null @@ -1,40 +0,0 @@ -#include - -#include - -std::string BaseSocket::ipToString(sockaddr_in addr) -{ - char ip[INET_ADDRSTRLEN]; - inet_ntop(AF_INET, &(addr.sin_addr), ip, INET_ADDRSTRLEN); - - return std::string(ip); -} - -BaseSocket::BaseSocket(std::function onError, SocketType sockType, int socketId) : sock(socketId) -{ - if (socketId < 0) - { - if ((this->sock = socket(AF_INET, sockType, 0)) < 0) - { - onError(errno, "Socket creating error."); - } - } -} - -void BaseSocket::Close() -{ - if(isClosed) return; - - isClosed = true; - close(this->sock); -} - -std::string BaseSocket::remoteAddress() -{ - return ipToString(this->address); -} - -int BaseSocket::remotePort() -{ - return ntohs(this->address.sin_port); -} diff --git a/easysocket/src/tcpserver.cpp b/easysocket/src/tcpserver.cpp deleted file mode 100644 index f775fc9..0000000 --- a/easysocket/src/tcpserver.cpp +++ /dev/null @@ -1,77 +0,0 @@ -#include - -TCPServer::TCPServer(std::function onError) : BaseSocket(onError, TCP) -{ - int opt = 1; - setsockopt(this->sock,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(int)); - setsockopt(this->sock,SOL_SOCKET,SO_REUSEPORT,&opt,sizeof(int)); -} - -void TCPServer::Bind(int port, std::function onError) -{ - this->Bind("0.0.0.0", port, onError); -} - -void TCPServer::Bind(const char *address, uint16_t port, std::function onError) -{ - if (inet_pton(AF_INET, address, &this->address.sin_addr) <= 0) - { - onError(errno, "Invalid address. Address type not supported."); - return; - } - - this->address.sin_family = AF_INET; - this->address.sin_port = htons(port); - - if (bind(this->sock, (const sockaddr *)&this->address, sizeof(this->address)) < 0) - { - onError(errno, "Cannot bind the socket."); - return; - } -} - -void TCPServer::Listen(std::function onError) -{ - if (listen(this->sock, 10) < 0) - { - onError(errno, "Error: Server can't listen the socket."); - return; - } - - std::thread acceptThread(Accept, this, onError); - acceptThread.detach(); -} - -void TCPServer::Close() -{ - shutdown(this->sock, SHUT_RDWR); - - BaseSocket::Close(); -} - -void TCPServer::Accept(TCPServer *server, std::function onError) -{ - sockaddr_in newSocketInfo; - socklen_t newSocketInfoLength = sizeof(newSocketInfo); - - int newSock; - while (!server->isClosed) - { - while ((newSock = accept(server->sock, (sockaddr *)&newSocketInfo, &newSocketInfoLength)) < 0) - { - if (errno == EBADF || errno == EINVAL) return; - - onError(errno, "Error while accepting a new connection."); - return; - } - - if (!server->isClosed && newSock >= 0) - { - TCPSocket *newSocket = new TCPSocket([](int e, std::string er) { FDR_UNUSED(e); FDR_UNUSED(er); }, newSock); - newSocket->setAddressStruct(newSocketInfo); - - server->onNewConnection(newSocket); - newSocket->Listen(); - } - } -} diff --git a/easysocket/src/tcpsocket.cpp b/easysocket/src/tcpsocket.cpp deleted file mode 100644 index b6f6b8a..0000000 --- a/easysocket/src/tcpsocket.cpp +++ /dev/null @@ -1,119 +0,0 @@ -#include -#include - -TCPSocket::TCPSocket(std::function onError, int socketId) : BaseSocket(onError, TCP, socketId) -{ -} - -int TCPSocket::Send(std::string message) -{ - return this->Send(message.c_str(), message.length()); -} - -int TCPSocket::Send(const char *bytes, size_t byteslength) -{ - if (this->isClosed) - return -1; - - int sent = 0; - if ((sent = send(this->sock, bytes, byteslength, 0)) < 0) - { - perror("send"); - } - return sent; -} - -void TCPSocket::Connect(std::string host, uint16_t port, std::function onConnected, std::function onError) -{ - struct addrinfo hints, *res, *it; - memset(&hints, 0, sizeof(hints)); - hints.ai_family = AF_INET; - hints.ai_socktype = SOCK_STREAM; - - int status; - if ((status = getaddrinfo(host.c_str(), NULL, &hints, &res)) != 0) { - onError(errno, "Invalid address." + std::string(gai_strerror(status))); - return; - } - - for(it = res; it != NULL; it = it->ai_next) - { - if (it->ai_family == AF_INET) { // IPv4 - memcpy((void*)(&this->address), (void*)it->ai_addr, sizeof(sockaddr_in)); - break; // for now, just get first ip (ipv4). - } - } - - freeaddrinfo(res); - - this->Connect((uint32_t)this->address.sin_addr.s_addr, port, onConnected, onError); -} - -void TCPSocket::Connect(uint32_t ipv4, uint16_t port, std::function onConnected, std::function onError) -{ - this->address.sin_family = AF_INET; - this->address.sin_port = htons(port); - this->address.sin_addr.s_addr = ipv4; - - this->setTimeout(5); - - // Try to connect. - if (connect(this->sock, (const sockaddr *)&this->address, sizeof(sockaddr_in)) < 0) - { - onError(errno, "Connection failed to the host."); - return; - } - - this->setTimeout(0); - - // Connected to the server, fire the event. - onConnected(); - - // Start listening from server: - this->Listen(); -} - -void TCPSocket::Listen() -{ - // Start listening the socket from thread. - std::thread receiveListening(Receive, this); - receiveListening.detach(); -} - -void TCPSocket::setAddressStruct(sockaddr_in addr) -{ - this->address = addr; -} -sockaddr_in TCPSocket::getAddressStruct() const -{ - return this->address; -} - -void TCPSocket::setTimeout(int seconds) { - struct timeval tv; - tv.tv_sec = seconds; - tv.tv_usec = 0; - - setsockopt(this->sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(tv)); - setsockopt(this->sock, SOL_SOCKET, SO_SNDTIMEO, (char *)&tv, sizeof(tv)); -} - -void TCPSocket::Receive(TCPSocket *socket) -{ - char tempBuffer[socket->BUFFER_SIZE]; - int messageLength; - - while ((messageLength = recv(socket->sock, tempBuffer, socket->BUFFER_SIZE, 0)) > 0) - { - tempBuffer[messageLength] = '\0'; - if(socket->onMessageReceived) - socket->onMessageReceived(std::string(tempBuffer).substr(0, messageLength)); - - if(socket->onRawMessageReceived) - socket->onRawMessageReceived(tempBuffer, messageLength); - } - - socket->Close(); - if(socket->onSocketClosed) - socket->onSocketClosed(errno); -} diff --git a/easysocket/src/udpserver.cpp b/easysocket/src/udpserver.cpp deleted file mode 100644 index f12e284..0000000 --- a/easysocket/src/udpserver.cpp +++ /dev/null @@ -1,27 +0,0 @@ -#include - -UDPServer::UDPServer() -{ -} - -void UDPServer::Bind(int port, std::function onError) { - this->Bind("0.0.0.0", port, onError); -} - -void UDPServer::Bind(std::string IPv4, std::uint16_t port, std::function onError) -{ - if (inet_pton(AF_INET, IPv4.c_str(), &this->address.sin_addr) <= 0) - { - onError(errno, "Invalid address. Address type not supported."); - return; - } - - this->address.sin_family = AF_INET; - this->address.sin_port = htons(port); - - if (bind(this->sock, (const sockaddr *)&this->address, sizeof(this->address)) < 0) - { - onError(errno, "Cannot bind the socket."); - return; - } -} diff --git a/easysocket/src/udpsocket.cpp b/easysocket/src/udpsocket.cpp deleted file mode 100644 index 68924d6..0000000 --- a/easysocket/src/udpsocket.cpp +++ /dev/null @@ -1,171 +0,0 @@ -#include -#include - -UDPSocket::UDPSocket(bool useConnect, std::function onError, int socketId) : BaseSocket(onError, UDP, socketId) -{ - if (!useConnect) - { - std::thread recvfromThread(ReceiveFrom, this); - recvfromThread.detach(); - } - else - { - std::thread recvThread(Receive, this); - recvThread.detach(); - } -} - -void UDPSocket::SendTo(std::string message, std::string host, uint16_t port, std::function onError) -{ - this->SendTo(message.c_str(), message.length(), host, port, onError); -} - -void UDPSocket::SendTo(const char *bytes, size_t byteslength, std::string host, uint16_t port, std::function onError) -{ - sockaddr_in hostAddr; - - struct addrinfo hints, *res, *it; - memset(&hints, 0, sizeof(hints)); - hints.ai_family = AF_INET; - hints.ai_socktype = SOCK_DGRAM; - - int status; - if ((status = getaddrinfo(host.c_str(), NULL, &hints, &res)) != 0) - { - onError(errno, "Invalid address." + std::string(gai_strerror(status))); - return; - } - - for (it = res; it != NULL; it = it->ai_next) - { - if (it->ai_family == AF_INET) - { // IPv4 - memcpy((void *)(&hostAddr), (void *)it->ai_addr, sizeof(sockaddr_in)); - break; // for now, just get first ip (ipv4). - } - } - - freeaddrinfo(res); - - hostAddr.sin_port = htons(port); - hostAddr.sin_family = AF_INET; - - if (sendto(this->sock, bytes, byteslength, 0, (sockaddr *)&hostAddr, sizeof(hostAddr)) < 0) - { - onError(errno, "Cannot send message to the address."); - return; - } -} - -int UDPSocket::Send(std::string message) -{ - return this->Send(message.c_str(), message.length()); -} -int UDPSocket::Send(const char *bytes, size_t byteslength) -{ - if (this->isClosed) - return -1; - - int sent = 0; - if ((sent = send(this->sock, bytes, byteslength, 0)) < 0) - { - perror("send"); - } - return sent; -} - -void UDPSocket::Connect(std::string host, uint16_t port, std::function onError) -{ - struct addrinfo hints, *res, *it; - memset(&hints, 0, sizeof(hints)); - hints.ai_family = AF_INET; - hints.ai_socktype = SOCK_DGRAM; - - int status; - if ((status = getaddrinfo(host.c_str(), NULL, &hints, &res)) != 0) - { - onError(errno, "Invalid address." + std::string(gai_strerror(status))); - return; - } - - for (it = res; it != NULL; it = it->ai_next) - { - if (it->ai_family == AF_INET) - { // IPv4 - memcpy((void *)(&this->address), (void *)it->ai_addr, sizeof(sockaddr_in)); - break; // for now, just get first ip (ipv4). - } - } - - freeaddrinfo(res); - - this->Connect((uint32_t)this->address.sin_addr.s_addr, port, onError); -} -void UDPSocket::Connect(uint32_t ipv4, uint16_t port, std::function onError) -{ - this->address.sin_family = AF_INET; - this->address.sin_port = htons(port); - this->address.sin_addr.s_addr = ipv4; - - // Try to connect. - if (connect(this->sock, (const sockaddr *)&this->address, sizeof(sockaddr_in)) < 0) - { - onError(errno, "Connection failed to the host."); - return; - } -} - -void UDPSocket::Receive(UDPSocket *udpSocket) -{ - char tempBuffer[udpSocket->BUFFER_SIZE]; - - while (true) - { - int messageLength; - messageLength = recv(udpSocket->sock, tempBuffer, udpSocket->BUFFER_SIZE, 0); - - if (messageLength < 0) - { - perror("recvfrom"); - return; - } - else - { - tempBuffer[messageLength] = '\0'; - if (udpSocket->onMessageReceived) - udpSocket->onMessageReceived(std::string(tempBuffer).substr(0, messageLength), ipToString(udpSocket->address), ntohs(udpSocket->address.sin_port)); - - if (udpSocket->onRawMessageReceived) - udpSocket->onRawMessageReceived(tempBuffer, messageLength, ipToString(udpSocket->address), ntohs(udpSocket->address.sin_port)); - } - } -} - -void UDPSocket::ReceiveFrom(UDPSocket *udpSocket) -{ - sockaddr_in hostAddr; - socklen_t hostAddrSize = sizeof(hostAddr); - - char tempBuffer[udpSocket->BUFFER_SIZE]; - - while (true) - { - int messageLength; - messageLength = recvfrom(udpSocket->sock, tempBuffer, udpSocket->BUFFER_SIZE, 0, (sockaddr *)&hostAddr, &hostAddrSize); - - if (messageLength < 0) - { - perror("recvfrom"); - return; - } - else - { - tempBuffer[messageLength] = '\0'; - if (udpSocket->onMessageReceived) - udpSocket->onMessageReceived(std::string(tempBuffer).substr(0, messageLength), ipToString(hostAddr), ntohs(hostAddr.sin_port)); - - if (udpSocket->onRawMessageReceived) - udpSocket->onRawMessageReceived(tempBuffer, messageLength, ipToString(hostAddr), ntohs(hostAddr.sin_port)); - } - } -} diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt new file mode 100644 index 0000000..3f18e53 --- /dev/null +++ b/examples/CMakeLists.txt @@ -0,0 +1,21 @@ +cmake_minimum_required(VERSION 3.18) +project(ExampleProgram) + +set(CMAKE_CXX_STANDARD 11) + +add_executable(tcp-client tcp-client.cpp) +add_executable(tcp-server tcp-server.cpp) +add_executable(udp-client udp-client.cpp) +add_executable(udp-server udp-server.cpp) + +# Add -lpthread +target_link_libraries(tcp-client pthread) +target_link_libraries(tcp-server pthread) +target_link_libraries(udp-client pthread) +target_link_libraries(udp-server pthread) + +# Add -I../async-sockets +target_include_directories(tcp-client PUBLIC ../async-sockets) +target_include_directories(tcp-server PUBLIC ../async-sockets) +target_include_directories(udp-client PUBLIC ../async-sockets) +target_include_directories(udp-server PUBLIC ../async-sockets) diff --git a/examples/Makefile b/examples/Makefile index 558158a..fe78578 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -1,48 +1,25 @@ -#!make -# This make needs: -# g++ -# - -include ../MakeHelper - -#The Directories, Source, Includes, Objects, Binary and Resources -BUILDDIR ?= $(CURDIR)/obj/$(BUILD) -TARGETDIR ?= $(CURDIR)/bin/$(BUILD) - -#Compiler and Linker -BUILD ?= release -BITS ?= 64 CC := g++ +CFLAGS := --std=c++11 +LIBS := -lpthread +INC := -I../async-sockets/include +RM := rm -#Flags, Libraries and Includes -CFLAGS.common := -std=c++17 -m$(BITS) -Wall -Wextra -CFLAGS.debug := $(CFLAGS.common) -g -CFLAGS.release := $(CFLAGS.common) -Werror -O3 -CFLAGS ?= $(CFLAGS.$(BUILD)) -LIB := -L$(TARGETDIR) -leasysocket -lpthread -Wl,-rpath='$${ORIGIN}' -INC := -I$(CURDIR)/../easysocket/include +all: tcp-client tcp-server udp-client udp-server -build: - (cd ../easysocket && make TARGETDIR="$(TARGETDIR)") - $(CC) $(CFLAGS) $(INC) tcp-client.cpp -o $(TARGETDIR)/$(call MakeExe,tcp-client) $(LIB) - $(CC) $(CFLAGS) $(INC) udp-client.cpp -o $(TARGETDIR)/$(call MakeExe,udp-client) $(LIB) - $(CC) $(CFLAGS) $(INC) tcp-server.cpp -o $(TARGETDIR)/$(call MakeExe,tcp-server) $(LIB) - $(CC) $(CFLAGS) $(INC) udp-server.cpp -o $(TARGETDIR)/$(call MakeExe,udp-server) $(LIB) +tcp-client: + $(CC) $(CFLAGS) tcp-client.cpp $(INC) $(LIBS) -o tcp-client -template: - $(call MD,$(TARGETDIR)) - $(call MD,$(BUILDDIR)) +tcp-server: + $(CC) $(CFLAGS) tcp-server.cpp $(INC) $(LIBS) -o tcp-server -clean: - $(call RM,$(BUILDDIR)) +udp-client: + $(CC) $(CFLAGS) udp-client.cpp $(INC) $(LIBS) -o udp-client -cleaner: clean - $(call RM,$(TARGETDIR)) +udp-server: + $(CC) $(CFLAGS) udp-server.cpp $(INC) $(LIBS) -o udp-server -clean-deps: clean - (cd ../easysocket && make clean) - -cleaner-deps: cleaner - (cd ../easysocket && make cleaner) - -.PHONY: build template clean cleaner clean-deps cleaner-deps +clean: + $(RM) tcp-client + $(RM) tcp-server + $(RM) udp-client + $(RM) udp-server \ No newline at end of file diff --git a/examples/tcp-client.cpp b/examples/tcp-client.cpp index 282b0d5..27432c8 100644 --- a/examples/tcp-client.cpp +++ b/examples/tcp-client.cpp @@ -1,4 +1,4 @@ -#include +#include "../async-sockets/include/tcpsocket.hpp" #include using namespace std; @@ -6,7 +6,9 @@ using namespace std; int main() { // Initialize socket. - TCPSocket tcpSocket; + TCPSocket tcpSocket([](int errorCode, std::string errorMessage){ + cout << "Socket creation error:" << errorCode << " : " << errorMessage << endl; + }); // Start receiving from the host. tcpSocket.onMessageReceived = [](string message) { diff --git a/examples/tcp-server.cpp b/examples/tcp-server.cpp index af27e3f..c5c3437 100644 --- a/examples/tcp-server.cpp +++ b/examples/tcp-server.cpp @@ -1,4 +1,4 @@ -#include +#include "../async-sockets/include/tcpserver.hpp" #include using namespace std; @@ -28,6 +28,7 @@ int main() newClient->onSocketClosed = [newClient](int errorCode) { cout << "Socket closed:" << newClient->remoteAddress() << ":" << newClient->remotePort() << " -> " << errorCode << endl; + cout << flush; }; }; diff --git a/examples/udp-client.cpp b/examples/udp-client.cpp index 73f034d..bcaf2ba 100644 --- a/examples/udp-client.cpp +++ b/examples/udp-client.cpp @@ -1,4 +1,4 @@ -#include +#include "../async-sockets/include/udpsocket.hpp" #include using namespace std; diff --git a/examples/udp-server.cpp b/examples/udp-server.cpp index b5366c7..575c043 100644 --- a/examples/udp-server.cpp +++ b/examples/udp-server.cpp @@ -1,4 +1,4 @@ -#include +#include "../async-sockets/include/udpserver.hpp" #include using namespace std; From fd075b9b3f907d74841f5b3591ea97aa246295d3 Mon Sep 17 00:00:00 2001 From: Emin Fedar Date: Tue, 28 Sep 2021 15:52:47 +0300 Subject: [PATCH 05/15] Fix memory leak by removing tcpsocket after closing --- async-sockets/include/tcpsocket.hpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/async-sockets/include/tcpsocket.hpp b/async-sockets/include/tcpsocket.hpp index 66f9455..b008128 100644 --- a/async-sockets/include/tcpsocket.hpp +++ b/async-sockets/include/tcpsocket.hpp @@ -110,6 +110,9 @@ class TCPSocket : public BaseSocket socket->Close(); if(socket->onSocketClosed) socket->onSocketClosed(errno); + + if (socket != nullptr) + delete socket; } void setTimeout(int seconds) From a59eb494c73c3b7f676c3e3ef11e7c6d47b36d0a Mon Sep 17 00:00:00 2001 From: Friedrich Engel Date: Sat, 29 Jan 2022 16:20:50 +0100 Subject: [PATCH 06/15] added bind_broadcast for UDP_Server --- async-sockets/include/udpserver.hpp | 31 +++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/async-sockets/include/udpserver.hpp b/async-sockets/include/udpserver.hpp index 06f4794..2704307 100644 --- a/async-sockets/include/udpserver.hpp +++ b/async-sockets/include/udpserver.hpp @@ -23,8 +23,39 @@ class UDPServer : public UDPSocket return; } } + void Bind(int port, FDR_ON_ERROR) { this->Bind("0.0.0.0", port, onError); } + + void Bind_Broadcast(std::string IPv4, std::uint16_t port, FDR_ON_ERROR) + { + if (inet_pton(AF_INET, IPv4.c_str(), &this->address.sin_addr) <= 0) + { + onError(errno, "Invalid address. Address type not supported."); + return; + } + + this->address.sin_family = AF_INET; + this->address.sin_port = htons(port); + + if (bind(this->sock, (const sockaddr*)&this->address, sizeof(this->address)) < 0) + { + onError(errno, "Cannot bind the socket."); + return; + } + + int broadcast = 1; + if (setsockopt(this->sock, SOL_SOCKET, SO_BROADCAST, &broadcast, sizeof broadcast)) + { + onError(errno, "setsockopt(SO_BROADCAST) failed."); + return; + } + } + + void Bind_Broadcast(std::uint16_t port, FDR_ON_ERROR) + { + this->Bind_Broadcast("0.0.0.0", port, onError); + } }; \ No newline at end of file From d61a1a98673fe3095e0fd3bd55883f9ec6266c93 Mon Sep 17 00:00:00 2001 From: Friedrich Engel Date: Sat, 29 Jan 2022 17:57:15 +0100 Subject: [PATCH 07/15] added bind_broadcast for UDP_Server --- async-sockets/include/udpserver.hpp | 22 +--------------------- 1 file changed, 1 insertion(+), 21 deletions(-) diff --git a/async-sockets/include/udpserver.hpp b/async-sockets/include/udpserver.hpp index 2704307..addccfc 100644 --- a/async-sockets/include/udpserver.hpp +++ b/async-sockets/include/udpserver.hpp @@ -29,23 +29,8 @@ class UDPServer : public UDPSocket this->Bind("0.0.0.0", port, onError); } - void Bind_Broadcast(std::string IPv4, std::uint16_t port, FDR_ON_ERROR) + void setBroadcast(FDR_ON_ERROR) { - if (inet_pton(AF_INET, IPv4.c_str(), &this->address.sin_addr) <= 0) - { - onError(errno, "Invalid address. Address type not supported."); - return; - } - - this->address.sin_family = AF_INET; - this->address.sin_port = htons(port); - - if (bind(this->sock, (const sockaddr*)&this->address, sizeof(this->address)) < 0) - { - onError(errno, "Cannot bind the socket."); - return; - } - int broadcast = 1; if (setsockopt(this->sock, SOL_SOCKET, SO_BROADCAST, &broadcast, sizeof broadcast)) { @@ -53,9 +38,4 @@ class UDPServer : public UDPSocket return; } } - - void Bind_Broadcast(std::uint16_t port, FDR_ON_ERROR) - { - this->Bind_Broadcast("0.0.0.0", port, onError); - } }; \ No newline at end of file From a17b3e157fba5d97f57c7b42f2d3e72de24d4a10 Mon Sep 17 00:00:00 2001 From: Emin Fedar Date: Mon, 21 Feb 2022 22:39:49 +0300 Subject: [PATCH 08/15] Double free corruption fix. --- async-sockets/include/tcpserver.hpp | 1 + async-sockets/include/tcpsocket.hpp | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/async-sockets/include/tcpserver.hpp b/async-sockets/include/tcpserver.hpp index 3ed2737..6f93b12 100644 --- a/async-sockets/include/tcpserver.hpp +++ b/async-sockets/include/tcpserver.hpp @@ -77,6 +77,7 @@ class TCPServer : public BaseSocket if (!server->isClosed && newSock >= 0) { TCPSocket *newSocket = new TCPSocket(onError, newSock); + newSocket->deleteAfterClosed = true; newSocket->setAddressStruct(newSocketInfo); server->onNewConnection(newSocket); diff --git a/async-sockets/include/tcpsocket.hpp b/async-sockets/include/tcpsocket.hpp index b008128..586fc00 100644 --- a/async-sockets/include/tcpsocket.hpp +++ b/async-sockets/include/tcpsocket.hpp @@ -91,6 +91,8 @@ class TCPSocket : public BaseSocket void setAddressStruct(sockaddr_in addr) {this->address = addr;} sockaddr_in getAddressStruct() const {return this->address;} + bool deleteAfterClosed = false; + private: static void Receive(TCPSocket *socket) { @@ -111,7 +113,7 @@ class TCPSocket : public BaseSocket if(socket->onSocketClosed) socket->onSocketClosed(errno); - if (socket != nullptr) + if (socket->deleteAfterClosed && socket != nullptr) delete socket; } From fb72473e7f5ec38006107d924c248a17370ca7bd Mon Sep 17 00:00:00 2001 From: Emin Fedar Date: Thu, 27 Apr 2023 15:41:32 +0300 Subject: [PATCH 09/15] Update to v3.0 Fixed potential data races #25 Fixed BUFFER_SIZE bugs #27 Added new Send() function usages Removed unnecessary string copies (converted to const std::string&) --- .gitignore | 6 ++-- async-sockets/include/basesocket.hpp | 5 ++-- async-sockets/include/tcpserver.hpp | 14 +++++----- async-sockets/include/tcpsocket.hpp | 20 ++++++------- async-sockets/include/udpserver.hpp | 6 ++-- async-sockets/include/udpsocket.hpp | 42 +++++++++++++++++----------- examples/tcp-client.cpp | 3 +- examples/tcp-server.cpp | 2 +- examples/udp-client.cpp | 6 ++-- examples/udp-server.cpp | 9 +++--- 10 files changed, 61 insertions(+), 52 deletions(-) diff --git a/.gitignore b/.gitignore index cdc6718..eb40e66 100644 --- a/.gitignore +++ b/.gitignore @@ -31,8 +31,10 @@ *.out *.app -examples/bin -benchmarks/easysocket/bin +examples/tcp-client +examples/tcp-server +examples/udp-client +examples/udp-server .vscode .idea cmake-build-debug diff --git a/async-sockets/include/basesocket.hpp b/async-sockets/include/basesocket.hpp index 144dcbf..b32872f 100644 --- a/async-sockets/include/basesocket.hpp +++ b/async-sockets/include/basesocket.hpp @@ -13,6 +13,7 @@ #include #include #include +#include #define FDR_UNUSED(expr){ (void)(expr); } #define FDR_ON_ERROR std::function onError = [](int errorCode, std::string errorMessage){FDR_UNUSED(errorCode); FDR_UNUSED(errorMessage)} @@ -26,9 +27,9 @@ class BaseSocket TCP = SOCK_STREAM, UDP = SOCK_DGRAM }; - const uint16_t BUFFER_SIZE = 0xFFFF; sockaddr_in address; - bool isClosed = false; + std::atomic isClosed{false}; + constexpr static uint16_t BUFFER_SIZE = 0x1000; // 4096 bytes protected: int sock = 0; diff --git a/async-sockets/include/tcpserver.hpp b/async-sockets/include/tcpserver.hpp index 6f93b12..0b488fc 100644 --- a/async-sockets/include/tcpserver.hpp +++ b/async-sockets/include/tcpserver.hpp @@ -7,7 +7,7 @@ class TCPServer : public BaseSocket { public: // Event Listeners: - std::function onNewConnection = [](TCPSocket* sock){FDR_UNUSED(sock)}; + std::function onNewConnection = [](TCPSocket* sock){FDR_UNUSED(sock)}; explicit TCPServer(FDR_ON_ERROR): BaseSocket(onError, SocketType::TCP) { @@ -17,7 +17,7 @@ class TCPServer : public BaseSocket } // Binding the server. - void Bind(const char *address, uint16_t port, FDR_ON_ERROR) + void Bind(const char* address, uint16_t port, FDR_ON_ERROR) { if (inet_pton(AF_INET, address, &this->address.sin_addr) <= 0) { @@ -28,7 +28,7 @@ class TCPServer : public BaseSocket this->address.sin_family = AF_INET; this->address.sin_port = htons(port); - if (bind(this->sock, (const sockaddr *)&this->address, sizeof(this->address)) < 0) + if (bind(this->sock, (const sockaddr*)&this->address, sizeof(this->address)) < 0) { onError(errno, "Cannot bind the socket."); return; @@ -58,15 +58,15 @@ class TCPServer : public BaseSocket } private: - static void Accept(TCPServer *server, FDR_ON_ERROR) + static void Accept(TCPServer* server, FDR_ON_ERROR) { sockaddr_in newSocketInfo; socklen_t newSocketInfoLength = sizeof(newSocketInfo); - int newSock; + int newSock = -1; while (!server->isClosed) { - while ((newSock = accept(server->sock, (sockaddr *)&newSocketInfo, &newSocketInfoLength)) < 0) + if ((newSock = accept(server->sock, (sockaddr*)&newSocketInfo, &newSocketInfoLength)) < 0) { if (errno == EBADF || errno == EINVAL) return; @@ -76,7 +76,7 @@ class TCPServer : public BaseSocket if (!server->isClosed && newSock >= 0) { - TCPSocket *newSocket = new TCPSocket(onError, newSock); + TCPSocket* newSocket = new TCPSocket(onError, newSock); newSocket->deleteAfterClosed = true; newSocket->setAddressStruct(newSocketInfo); diff --git a/async-sockets/include/tcpsocket.hpp b/async-sockets/include/tcpsocket.hpp index 586fc00..5529c51 100644 --- a/async-sockets/include/tcpsocket.hpp +++ b/async-sockets/include/tcpsocket.hpp @@ -17,7 +17,7 @@ class TCPSocket : public BaseSocket explicit TCPSocket(FDR_ON_ERROR, int socketId = -1) : BaseSocket(onError, TCP, socketId){} // Send TCP Packages - int Send(const char *bytes, size_t byteslength) + int Send(const char* bytes, size_t byteslength) { if (this->isClosed) return -1; @@ -29,9 +29,9 @@ class TCPSocket : public BaseSocket } return sent; } - int Send(std::string message) { return this->Send(message.c_str(), message.length()); } + int Send(const std::string& message) { return this->Send(message.c_str(), message.length()); } - void Connect(std::string host, uint16_t port, std::function onConnected = [](){}, FDR_ON_ERROR) + void Connect(const char* host, uint16_t port, std::function onConnected = [](){}, FDR_ON_ERROR) { struct addrinfo hints, *res, *it; memset(&hints, 0, sizeof(hints)); @@ -40,7 +40,7 @@ class TCPSocket : public BaseSocket // Get address info from DNS int status; - if ((status = getaddrinfo(host.c_str(), NULL, &hints, &res)) != 0) { + if ((status = getaddrinfo(host, NULL, &hints, &res)) != 0) { onError(errno, "Invalid address." + std::string(gai_strerror(status))); return; } @@ -66,7 +66,7 @@ class TCPSocket : public BaseSocket this->setTimeout(5); // Try to connect. - if (connect(this->sock, (const sockaddr *)&this->address, sizeof(sockaddr_in)) < 0) + if (connect(this->sock, (const sockaddr*)&this->address, sizeof(sockaddr_in)) < 0) { onError(errno, "Connection failed to the host."); this->setTimeout(0); @@ -94,12 +94,12 @@ class TCPSocket : public BaseSocket bool deleteAfterClosed = false; private: - static void Receive(TCPSocket *socket) + static void Receive(TCPSocket* socket) { - char tempBuffer[socket->BUFFER_SIZE]; + char tempBuffer[TCPSocket::BUFFER_SIZE]; int messageLength; - while ((messageLength = recv(socket->sock, tempBuffer, socket->BUFFER_SIZE, 0)) > 0) + while ((messageLength = recv(socket->sock, tempBuffer, TCPSocket::BUFFER_SIZE, 0)) > 0) { tempBuffer[messageLength] = '\0'; if(socket->onMessageReceived) @@ -123,7 +123,7 @@ class TCPSocket : public BaseSocket tv.tv_sec = seconds; tv.tv_usec = 0; - setsockopt(this->sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(tv)); - setsockopt(this->sock, SOL_SOCKET, SO_SNDTIMEO, (char *)&tv, sizeof(tv)); + setsockopt(this->sock, SOL_SOCKET, SO_RCVTIMEO, (char*)&tv, sizeof(tv)); + setsockopt(this->sock, SOL_SOCKET, SO_SNDTIMEO, (char*)&tv, sizeof(tv)); } }; diff --git a/async-sockets/include/udpserver.hpp b/async-sockets/include/udpserver.hpp index addccfc..6c68292 100644 --- a/async-sockets/include/udpserver.hpp +++ b/async-sockets/include/udpserver.hpp @@ -6,9 +6,9 @@ class UDPServer : public UDPSocket { public: - void Bind(std::string IPv4, std::uint16_t port, FDR_ON_ERROR) + void Bind(const char* IPv4, std::uint16_t port, FDR_ON_ERROR) { - if (inet_pton(AF_INET, IPv4.c_str(), &this->address.sin_addr) <= 0) + if (inet_pton(AF_INET, IPv4, &this->address.sin_addr) <= 0) { onError(errno, "Invalid address. Address type not supported."); return; @@ -17,7 +17,7 @@ class UDPServer : public UDPSocket this->address.sin_family = AF_INET; this->address.sin_port = htons(port); - if (bind(this->sock, (const sockaddr *)&this->address, sizeof(this->address)) < 0) + if (bind(this->sock, (const sockaddr*)&this->address, sizeof(this->address)) < 0) { onError(errno, "Cannot bind the socket."); return; diff --git a/async-sockets/include/udpsocket.hpp b/async-sockets/include/udpsocket.hpp index 11b7783..5bcbd0c 100644 --- a/async-sockets/include/udpsocket.hpp +++ b/async-sockets/include/udpsocket.hpp @@ -26,7 +26,7 @@ class UDPSocket : public BaseSocket } // SendTo with no connection - void SendTo(const char *bytes, size_t byteslength, std::string host, uint16_t port, FDR_ON_ERROR) + void SendTo(const char* bytes, size_t byteslength, const char* host, uint16_t port, FDR_ON_ERROR) { sockaddr_in hostAddr; @@ -36,7 +36,7 @@ class UDPSocket : public BaseSocket hints.ai_socktype = SOCK_DGRAM; int status; - if ((status = getaddrinfo(host.c_str(), NULL, &hints, &res)) != 0) + if ((status = getaddrinfo(host, NULL, &hints, &res)) != 0) { onError(errno, "Invalid address." + std::string(gai_strerror(status))); return; @@ -46,7 +46,7 @@ class UDPSocket : public BaseSocket { if (it->ai_family == AF_INET) { // IPv4 - memcpy((void *)(&hostAddr), (void *)it->ai_addr, sizeof(sockaddr_in)); + memcpy((void* )(&hostAddr), (void* )it->ai_addr, sizeof(sockaddr_in)); break; // for now, just get first ip (ipv4). } } @@ -56,19 +56,27 @@ class UDPSocket : public BaseSocket hostAddr.sin_port = htons(port); hostAddr.sin_family = AF_INET; - if (sendto(this->sock, bytes, byteslength, 0, (sockaddr *)&hostAddr, sizeof(hostAddr)) < 0) + if (sendto(this->sock, bytes, byteslength, 0, (sockaddr*)&hostAddr, sizeof(hostAddr)) < 0) { onError(errno, "Cannot send message to the address."); return; } } - void SendTo(std::string message, std::string host, uint16_t port, FDR_ON_ERROR) + void SendTo(const char* bytes, size_t byteslength, const std::string& host, uint16_t port, FDR_ON_ERROR) + { + this->SendTo(bytes, byteslength, host.c_str(), port, onError); + } + void SendTo(const std::string& message, const char* host, uint16_t port, FDR_ON_ERROR) { this->SendTo(message.c_str(), message.length(), host, port, onError); } + void SendTo(const std::string& message, const std::string& host, uint16_t port, FDR_ON_ERROR) + { + this->SendTo(message.c_str(), message.length(), host.c_str(), port, onError); + } // Send with Connect() - int Send(const char *bytes, size_t byteslength) + int Send(const char* bytes, size_t byteslength) { if (this->isClosed) return -1; @@ -80,7 +88,7 @@ class UDPSocket : public BaseSocket } return sent; } - int Send(std::string message) + int Send(const std::string& message) { return this->Send(message.c_str(), message.length()); } @@ -93,13 +101,13 @@ class UDPSocket : public BaseSocket this->address.sin_addr.s_addr = ipv4; // Try to connect. - if (connect(this->sock, (const sockaddr *)&this->address, sizeof(sockaddr_in)) < 0) + if (connect(this->sock, (const sockaddr* )&this->address, sizeof(sockaddr_in)) < 0) { onError(errno, "Connection failed to the host."); return; } } - void Connect(std::string host, uint16_t port, FDR_ON_ERROR) + void Connect(const char* host, uint16_t port, FDR_ON_ERROR) { struct addrinfo hints, *res, *it; memset(&hints, 0, sizeof(hints)); @@ -107,7 +115,7 @@ class UDPSocket : public BaseSocket hints.ai_socktype = SOCK_DGRAM; int status; - if ((status = getaddrinfo(host.c_str(), NULL, &hints, &res)) != 0) + if ((status = getaddrinfo(host, NULL, &hints, &res)) != 0) { onError(errno, "Invalid address." + std::string(gai_strerror(status))); return; @@ -117,7 +125,7 @@ class UDPSocket : public BaseSocket { if (it->ai_family == AF_INET) { // IPv4 - memcpy((void *)(&this->address), (void *)it->ai_addr, sizeof(sockaddr_in)); + memcpy((void* )(&this->address), (void*)it->ai_addr, sizeof(sockaddr_in)); break; // for now, just get first ip (ipv4). } } @@ -128,14 +136,14 @@ class UDPSocket : public BaseSocket } private: - static void Receive(UDPSocket *udpSocket) + static void Receive(UDPSocket* udpSocket) { - char tempBuffer[udpSocket->BUFFER_SIZE]; + char tempBuffer[UDPSocket::BUFFER_SIZE]; while (true) { int messageLength; - messageLength = recv(udpSocket->sock, tempBuffer, udpSocket->BUFFER_SIZE, 0); + messageLength = recv(udpSocket->sock, tempBuffer, UDPSocket::BUFFER_SIZE, 0); if (messageLength < 0) { @@ -153,17 +161,17 @@ class UDPSocket : public BaseSocket } } } - static void ReceiveFrom(UDPSocket *udpSocket) + static void ReceiveFrom(UDPSocket* udpSocket) { sockaddr_in hostAddr; socklen_t hostAddrSize = sizeof(hostAddr); - char tempBuffer[udpSocket->BUFFER_SIZE]; + char tempBuffer[UDPSocket::BUFFER_SIZE]; while (true) { int messageLength; - messageLength = recvfrom(udpSocket->sock, tempBuffer, udpSocket->BUFFER_SIZE, 0, (sockaddr *)&hostAddr, &hostAddrSize); + messageLength = recvfrom(udpSocket->sock, tempBuffer, UDPSocket::BUFFER_SIZE, 0, (sockaddr* )&hostAddr, &hostAddrSize); if (messageLength < 0) { diff --git a/examples/tcp-client.cpp b/examples/tcp-client.cpp index 27432c8..f3542e8 100644 --- a/examples/tcp-client.cpp +++ b/examples/tcp-client.cpp @@ -38,8 +38,7 @@ int main() cout << errorCode << " : " << errorMessage << endl; }); - // You should do an input loop so the program will not end immediately: - // Because socket listenings are non-blocking. + // You should do an input loop, so the program won't terminate immediately string input; getline(cin, input); while (input != "exit") diff --git a/examples/tcp-server.cpp b/examples/tcp-server.cpp index c5c3437..56f5c17 100644 --- a/examples/tcp-server.cpp +++ b/examples/tcp-server.cpp @@ -44,7 +44,7 @@ int main() cout << errorCode << " : " << errorMessage << endl; }); - // You should do an input loop so the program will not terminated immediately: + // You should do an input loop, so the program won't terminate immediately string input; getline(cin, input); while (input != "exit") diff --git a/examples/udp-client.cpp b/examples/udp-client.cpp index bcaf2ba..3192510 100644 --- a/examples/udp-client.cpp +++ b/examples/udp-client.cpp @@ -6,8 +6,8 @@ using namespace std; int main() { // Our constants: - const string IP = "localhost"; - const uint16_t PORT = 8888; + constexpr const char* IP = "localhost"; + constexpr uint16_t PORT = 8888; // Initialize socket. UDPSocket udpSocket(true); // "true" to use Connection on UDP. Default is "false". @@ -28,7 +28,7 @@ int main() }; */ - // You should do an input loop so the program will not terminated immediately: + // You should do an input loop, so the program won't terminate immediately string input; getline(cin, input); while (input != "exit") diff --git a/examples/udp-server.cpp b/examples/udp-server.cpp index 575c043..f3e3f65 100644 --- a/examples/udp-server.cpp +++ b/examples/udp-server.cpp @@ -12,16 +12,15 @@ int main() /*udpServer.onMessageReceived = [&](string message, string ipv4, uint16_t port) { //cout << ipv4 << ":" << port << " => " << message << endl; - // Just send without control: + // Echo to client: udpServer.SendTo("A!", ipv4, port); };*/ // If you want to use raw byte arrays: - udpServer.onRawMessageReceived = [&](const char* message, int length, string ipv4, uint16_t port) { - //cout << ipv4 << ":" << port << " => " << message << "(" << length << ")" << endl; + cout << ipv4 << ":" << port << " => " << message << "(" << length << ")" << endl; - // Just send without control: + // Echo to client: udpServer.SendTo(message, length, ipv4, port); }; @@ -32,7 +31,7 @@ int main() cout << errorCode << " : " << errorMessage << endl; }); - // You should do an input loop so the program will not terminated immediately: + // You should do an input loop, so the program won't terminate immediately string input; getline(cin, input); while (input != "exit") From 49597c512cfa00a373d4c9f6c2d0a15d6c99486b Mon Sep 17 00:00:00 2001 From: Emin Fedar Date: Fri, 28 Apr 2023 08:45:58 +0300 Subject: [PATCH 10/15] Removed isClosed --- async-sockets/include/basesocket.hpp | 4 ---- async-sockets/include/tcpserver.hpp | 4 ++-- async-sockets/include/tcpsocket.hpp | 10 ++++++---- async-sockets/include/udpsocket.hpp | 3 --- 4 files changed, 8 insertions(+), 13 deletions(-) diff --git a/async-sockets/include/basesocket.hpp b/async-sockets/include/basesocket.hpp index b32872f..95af99f 100644 --- a/async-sockets/include/basesocket.hpp +++ b/async-sockets/include/basesocket.hpp @@ -28,7 +28,6 @@ class BaseSocket UDP = SOCK_DGRAM }; sockaddr_in address; - std::atomic isClosed{false}; constexpr static uint16_t BUFFER_SIZE = 0x1000; // 4096 bytes protected: @@ -59,9 +58,6 @@ class BaseSocket // Methods public: virtual void Close() { - if(isClosed) return; - - isClosed = true; close(this->sock); } diff --git a/async-sockets/include/tcpserver.hpp b/async-sockets/include/tcpserver.hpp index 0b488fc..ec0c905 100644 --- a/async-sockets/include/tcpserver.hpp +++ b/async-sockets/include/tcpserver.hpp @@ -64,7 +64,7 @@ class TCPServer : public BaseSocket socklen_t newSocketInfoLength = sizeof(newSocketInfo); int newSock = -1; - while (!server->isClosed) + while (true) { if ((newSock = accept(server->sock, (sockaddr*)&newSocketInfo, &newSocketInfoLength)) < 0) { @@ -74,7 +74,7 @@ class TCPServer : public BaseSocket return; } - if (!server->isClosed && newSock >= 0) + if (newSock >= 0) { TCPSocket* newSocket = new TCPSocket(onError, newSock); newSocket->deleteAfterClosed = true; diff --git a/async-sockets/include/tcpsocket.hpp b/async-sockets/include/tcpsocket.hpp index 5529c51..39515e7 100644 --- a/async-sockets/include/tcpsocket.hpp +++ b/async-sockets/include/tcpsocket.hpp @@ -19,10 +19,7 @@ class TCPSocket : public BaseSocket // Send TCP Packages int Send(const char* bytes, size_t byteslength) { - if (this->isClosed) - return -1; - - int sent = 0; + int sent = -1; if ((sent = send(this->sock, bytes, byteslength, 0)) < 0) { perror("send"); @@ -31,6 +28,7 @@ class TCPSocket : public BaseSocket } int Send(const std::string& message) { return this->Send(message.c_str(), message.length()); } + void Connect(const char* host, uint16_t port, std::function onConnected = [](){}, FDR_ON_ERROR) { struct addrinfo hints, *res, *it; @@ -81,6 +79,10 @@ class TCPSocket : public BaseSocket // Start listening from server: this->Listen(); } + void Connect(const std::string& host, uint16_t port, std::function onConnected = [](){}, FDR_ON_ERROR) + { + this->Connect(host.c_str(), port, onConnected, onError); + } void Listen() { diff --git a/async-sockets/include/udpsocket.hpp b/async-sockets/include/udpsocket.hpp index 5bcbd0c..f4cd0b3 100644 --- a/async-sockets/include/udpsocket.hpp +++ b/async-sockets/include/udpsocket.hpp @@ -78,9 +78,6 @@ class UDPSocket : public BaseSocket // Send with Connect() int Send(const char* bytes, size_t byteslength) { - if (this->isClosed) - return -1; - int sent = 0; if ((sent = send(this->sock, bytes, byteslength, 0)) < 0) { From 1ecd6262aa0b17e002f235aa7aaceef0aabb6d1e Mon Sep 17 00:00:00 2001 From: Emin Fedar Date: Fri, 28 Apr 2023 21:21:47 +0300 Subject: [PATCH 11/15] Refactor --- async-sockets/include/basesocket.hpp | 32 ++++---- async-sockets/include/tcpserver.hpp | 52 ++++++------- async-sockets/include/tcpsocket.hpp | 71 ++++++++--------- async-sockets/include/udpserver.hpp | 31 +++++--- async-sockets/include/udpsocket.hpp | 111 +++++++++++---------------- examples/Makefile | 2 +- examples/tcp-client.cpp | 11 ++- 7 files changed, 149 insertions(+), 161 deletions(-) diff --git a/async-sockets/include/basesocket.hpp b/async-sockets/include/basesocket.hpp index 95af99f..9bdc613 100644 --- a/async-sockets/include/basesocket.hpp +++ b/async-sockets/include/basesocket.hpp @@ -13,14 +13,12 @@ #include #include #include -#include #define FDR_UNUSED(expr){ (void)(expr); } #define FDR_ON_ERROR std::function onError = [](int errorCode, std::string errorMessage){FDR_UNUSED(errorCode); FDR_UNUSED(errorMessage)} class BaseSocket { -// Definitions public: enum SocketType { @@ -30,9 +28,20 @@ class BaseSocket sockaddr_in address; constexpr static uint16_t BUFFER_SIZE = 0x1000; // 4096 bytes + void Close() { + shutdown(this->sock, SHUT_RDWR); + close(this->sock); + } + + std::string remoteAddress() const { return ipToString(this->address); } + int remotePort() const { return ntohs(this->address.sin_port); } + int fileDescriptor() const { return this->sock; } + protected: int sock = 0; - static std::string ipToString(sockaddr_in addr) + + // Get std::string value of the IP from a `sockaddr_in` address struct + static std::string ipToString(const sockaddr_in& addr) { char ip[INET_ADDRSTRLEN]; inet_ntop(AF_INET, &(addr.sin_addr), ip, INET_ADDRSTRLEN); @@ -42,9 +51,11 @@ class BaseSocket BaseSocket(FDR_ON_ERROR, SocketType sockType = TCP, int socketId = -1) { - if (socketId < 0) + if (socketId == -1) { - if ((this->sock = socket(AF_INET, sockType, 0)) < 0) + this->sock = socket(AF_INET, sockType, 0); + + if ( this->sock == -1 ) { onError(errno, "Socket creating error."); } @@ -54,14 +65,5 @@ class BaseSocket this->sock = socketId; } } - -// Methods -public: - virtual void Close() { - close(this->sock); - } - - std::string remoteAddress() {return ipToString(this->address);} - int remotePort() {return ntohs(this->address.sin_port);} - int fileDescriptor() const { return this->sock; } + virtual ~BaseSocket(){} }; \ No newline at end of file diff --git a/async-sockets/include/tcpserver.hpp b/async-sockets/include/tcpserver.hpp index ec0c905..a91888b 100644 --- a/async-sockets/include/tcpserver.hpp +++ b/async-sockets/include/tcpserver.hpp @@ -16,30 +16,37 @@ class TCPServer : public BaseSocket setsockopt(this->sock,SOL_SOCKET,SO_REUSEPORT,&opt,sizeof(int)); } - // Binding the server. + // Bind the custom address & port of the server. void Bind(const char* address, uint16_t port, FDR_ON_ERROR) { - if (inet_pton(AF_INET, address, &this->address.sin_addr) <= 0) - { - onError(errno, "Invalid address. Address type not supported."); - return; + int status = inet_pton(AF_INET, address, &this->address.sin_addr); + switch (status) { + case -1: + onError(errno, "Invalid address. Address type not supported."); + return; + case 0: + onError(errno, "AF_INET is not supported. Please send message to developer."); + return; + default: + break; } this->address.sin_family = AF_INET; this->address.sin_port = htons(port); - if (bind(this->sock, (const sockaddr*)&this->address, sizeof(this->address)) < 0) + if (bind(this->sock, (const sockaddr*)&this->address, sizeof(this->address)) == -1) { onError(errno, "Cannot bind the socket."); return; } } - void Bind(int port, FDR_ON_ERROR) { this->Bind("0.0.0.0", port, onError); } + // Bind the address(0.0.0.0) & port of the server. + void Bind(uint16_t port, FDR_ON_ERROR) { this->Bind("0.0.0.0", port, onError); } - // Start listening the server. + // Start listening incoming connections. void Listen(FDR_ON_ERROR) { - if (listen(this->sock, 20) < 0) + if (listen(this->sock, 20) == -1) { onError(errno, "Error: Server can't listen the socket."); return; @@ -49,40 +56,31 @@ class TCPServer : public BaseSocket t.detach(); } - // Overriding Close to add shutdown(): - void Close() - { - shutdown(this->sock, SHUT_RDWR); - - BaseSocket::Close(); - } - private: static void Accept(TCPServer* server, FDR_ON_ERROR) { sockaddr_in newSocketInfo; socklen_t newSocketInfoLength = sizeof(newSocketInfo); - int newSock = -1; + int newSocketFileDescriptor = -1; while (true) { - if ((newSock = accept(server->sock, (sockaddr*)&newSocketInfo, &newSocketInfoLength)) < 0) + newSocketFileDescriptor = accept(server->sock, (sockaddr*)&newSocketInfo, &newSocketInfoLength); + if (newSocketFileDescriptor == -1) { if (errno == EBADF || errno == EINVAL) return; onError(errno, "Error while accepting a new connection."); + return; } - if (newSock >= 0) - { - TCPSocket* newSocket = new TCPSocket(onError, newSock); - newSocket->deleteAfterClosed = true; - newSocket->setAddressStruct(newSocketInfo); + TCPSocket* newSocket = new TCPSocket(onError, newSocketFileDescriptor); + newSocket->deleteAfterClosed = true; + newSocket->setAddressStruct(newSocketInfo); - server->onNewConnection(newSocket); - newSocket->Listen(); - } + server->onNewConnection(newSocket); + newSocket->Listen(); } } }; \ No newline at end of file diff --git a/async-sockets/include/tcpsocket.hpp b/async-sockets/include/tcpsocket.hpp index 39515e7..7cb3711 100644 --- a/async-sockets/include/tcpsocket.hpp +++ b/async-sockets/include/tcpsocket.hpp @@ -11,24 +11,43 @@ class TCPSocket : public BaseSocket public: // Event Listeners: std::function onMessageReceived; - std::function onRawMessageReceived; + std::function onRawMessageReceived; std::function onSocketClosed; explicit TCPSocket(FDR_ON_ERROR, int socketId = -1) : BaseSocket(onError, TCP, socketId){} - // Send TCP Packages - int Send(const char* bytes, size_t byteslength) + // Send raw bytes + ssize_t Send(const char* bytes, size_t byteslength) { return send(this->sock, bytes, byteslength, 0); } + // Send std::string + ssize_t Send(const std::string& message) { return this->Send(message.c_str(), message.length()); } + + // Connect to a TCP Server with `uint32_t ipv4` & `uint16_t port` values + void Connect(uint32_t ipv4, uint16_t port, std::function onConnected = [](){}, FDR_ON_ERROR) { - int sent = -1; - if ((sent = send(this->sock, bytes, byteslength, 0)) < 0) + this->address.sin_family = AF_INET; + this->address.sin_port = htons(port); + this->address.sin_addr.s_addr = ipv4; + + this->setTimeout(5); + + // Try to connect. + int status = connect(this->sock, (const sockaddr*)&this->address, sizeof(sockaddr_in)); + if ( status == -1) { - perror("send"); + onError(errno, "Connection failed to the host."); + this->setTimeout(0); + return; } - return sent; - } - int Send(const std::string& message) { return this->Send(message.c_str(), message.length()); } + this->setTimeout(0); + + // Connected to the server, fire the event. + onConnected(); + // Start listening from server: + this->Listen(); + } + // Connect to a TCP Server with `const char* host` & `uint16_t port` values void Connect(const char* host, uint16_t port, std::function onConnected = [](){}, FDR_ON_ERROR) { struct addrinfo hints, *res, *it; @@ -37,8 +56,8 @@ class TCPSocket : public BaseSocket hints.ai_socktype = SOCK_STREAM; // Get address info from DNS - int status; - if ((status = getaddrinfo(host, NULL, &hints, &res)) != 0) { + int status = getaddrinfo(host, NULL, &hints, &res); + if ( status != 0 ) { onError(errno, "Invalid address." + std::string(gai_strerror(status))); return; } @@ -47,7 +66,7 @@ class TCPSocket : public BaseSocket { if (it->ai_family == AF_INET) { // IPv4 memcpy((void*)(&this->address), (void*)it->ai_addr, sizeof(sockaddr_in)); - break; // for now, just get first ip (ipv4). + break; // for now, just get the first ip (ipv4). } } @@ -55,35 +74,13 @@ class TCPSocket : public BaseSocket this->Connect((uint32_t)this->address.sin_addr.s_addr, port, onConnected, onError); } - void Connect(uint32_t ipv4, uint16_t port, std::function onConnected = [](){}, FDR_ON_ERROR) - { - this->address.sin_family = AF_INET; - this->address.sin_port = htons(port); - this->address.sin_addr.s_addr = ipv4; - - this->setTimeout(5); - - // Try to connect. - if (connect(this->sock, (const sockaddr*)&this->address, sizeof(sockaddr_in)) < 0) - { - onError(errno, "Connection failed to the host."); - this->setTimeout(0); - return; - } - - this->setTimeout(0); - - // Connected to the server, fire the event. - onConnected(); - - // Start listening from server: - this->Listen(); - } + // Connect to a TCP Server with `const std::string& ipv4` & `uint16_t port` values void Connect(const std::string& host, uint16_t port, std::function onConnected = [](){}, FDR_ON_ERROR) { this->Connect(host.c_str(), port, onConnected, onError); } + // Start another thread to listen the socket void Listen() { std::thread t(TCPSocket::Receive, this); @@ -99,7 +96,7 @@ class TCPSocket : public BaseSocket static void Receive(TCPSocket* socket) { char tempBuffer[TCPSocket::BUFFER_SIZE]; - int messageLength; + ssize_t messageLength; while ((messageLength = recv(socket->sock, tempBuffer, TCPSocket::BUFFER_SIZE, 0)) > 0) { diff --git a/async-sockets/include/udpserver.hpp b/async-sockets/include/udpserver.hpp index 6c68292..df938d8 100644 --- a/async-sockets/include/udpserver.hpp +++ b/async-sockets/include/udpserver.hpp @@ -6,33 +6,44 @@ class UDPServer : public UDPSocket { public: - void Bind(const char* IPv4, std::uint16_t port, FDR_ON_ERROR) + // Bind the custom address & port of the server. + void Bind(const char* address, std::uint16_t port, FDR_ON_ERROR) { - if (inet_pton(AF_INET, IPv4, &this->address.sin_addr) <= 0) - { - onError(errno, "Invalid address. Address type not supported."); - return; + int status = inet_pton(AF_INET, address, &this->address.sin_addr); + switch (status) { + case -1: + onError(errno, "Invalid address. Address type not supported."); + return; + case 0: + onError(errno, "AF_INET is not supported. Please send message to developer."); + return; + default: + break; } this->address.sin_family = AF_INET; this->address.sin_port = htons(port); - if (bind(this->sock, (const sockaddr*)&this->address, sizeof(this->address)) < 0) + status = bind(this->sock, (const sockaddr*)&this->address, sizeof(this->address)); + if (status == -1) { onError(errno, "Cannot bind the socket."); return; } } - void Bind(int port, FDR_ON_ERROR) + // Bind the address(0.0.0.0) & port of the server. + void Bind(uint16_t port, FDR_ON_ERROR) { this->Bind("0.0.0.0", port, onError); } - void setBroadcast(FDR_ON_ERROR) + // Enable or disable the SO_BROADCAST flag + void setBroadcast(bool value, FDR_ON_ERROR) { - int broadcast = 1; - if (setsockopt(this->sock, SOL_SOCKET, SO_BROADCAST, &broadcast, sizeof broadcast)) + int broadcast = static_cast(value); + int status = setsockopt(this->sock, SOL_SOCKET, SO_BROADCAST, &broadcast, sizeof broadcast); + if (status == -1) { onError(errno, "setsockopt(SO_BROADCAST) failed."); return; diff --git a/async-sockets/include/udpsocket.hpp b/async-sockets/include/udpsocket.hpp index f4cd0b3..b065462 100644 --- a/async-sockets/include/udpsocket.hpp +++ b/async-sockets/include/udpsocket.hpp @@ -8,7 +8,7 @@ class UDPSocket : public BaseSocket { public: std::function onMessageReceived; - std::function onRawMessageReceived; + std::function onRawMessageReceived; explicit UDPSocket(bool useConnect = false, FDR_ON_ERROR, int socketId = -1): BaseSocket(onError, SocketType::UDP, socketId) { @@ -25,8 +25,8 @@ class UDPSocket : public BaseSocket } } - // SendTo with no connection - void SendTo(const char* bytes, size_t byteslength, const char* host, uint16_t port, FDR_ON_ERROR) + // Send raw bytes to a spesific `host` & `port` with no connection + ssize_t SendTo(const char* bytes, size_t byteslength, const char* host, uint16_t port, FDR_ON_ERROR) { sockaddr_in hostAddr; @@ -39,7 +39,7 @@ class UDPSocket : public BaseSocket if ((status = getaddrinfo(host, NULL, &hints, &res)) != 0) { onError(errno, "Invalid address." + std::string(gai_strerror(status))); - return; + return -1; } for (it = res; it != NULL; it = it->ai_next) @@ -55,42 +55,38 @@ class UDPSocket : public BaseSocket hostAddr.sin_port = htons(port); hostAddr.sin_family = AF_INET; - - if (sendto(this->sock, bytes, byteslength, 0, (sockaddr*)&hostAddr, sizeof(hostAddr)) < 0) + + ssize_t sent_length = sendto(this->sock, bytes, byteslength, 0, (sockaddr*)&hostAddr, sizeof(hostAddr)); + if (sent_length == -1) { onError(errno, "Cannot send message to the address."); - return; + return -1; } + + return sent_length; } - void SendTo(const char* bytes, size_t byteslength, const std::string& host, uint16_t port, FDR_ON_ERROR) + // Send raw bytes to a spesific `host` & `port` with no connection + ssize_t SendTo(const char* bytes, size_t byteslength, const std::string& host, uint16_t port, FDR_ON_ERROR) { - this->SendTo(bytes, byteslength, host.c_str(), port, onError); + return this->SendTo(bytes, byteslength, host.c_str(), port, onError); } - void SendTo(const std::string& message, const char* host, uint16_t port, FDR_ON_ERROR) + // Send std::string to a spesific `host` & `port` with no connection + ssize_t SendTo(const std::string& message, const char* host, uint16_t port, FDR_ON_ERROR) { - this->SendTo(message.c_str(), message.length(), host, port, onError); + return this->SendTo(message.c_str(), message.length(), host, port, onError); } - void SendTo(const std::string& message, const std::string& host, uint16_t port, FDR_ON_ERROR) + // Send std::string to a spesific `host` & `port` with no connection + ssize_t SendTo(const std::string& message, const std::string& host, uint16_t port, FDR_ON_ERROR) { - this->SendTo(message.c_str(), message.length(), host.c_str(), port, onError); + return this->SendTo(message.c_str(), message.length(), host.c_str(), port, onError); } - // Send with Connect() - int Send(const char* bytes, size_t byteslength) - { - int sent = 0; - if ((sent = send(this->sock, bytes, byteslength, 0)) < 0) - { - perror("send"); - } - return sent; - } - int Send(const std::string& message) - { - return this->Send(message.c_str(), message.length()); - } + // Send raw bytes to the `Connect()`ed server. + ssize_t Send(const char* bytes, size_t byteslength) { return send(this->sock, bytes, byteslength, 0); } + // Send std::string to the `Connect()`ed server. + ssize_t Send(const std::string& message) { return this->Send(message.c_str(), message.length()); } - // To use "Send()", need to call Connect() first + // Connect to a server with raw `uint32_t ipv4` and `uint16_t port` values. void Connect(uint32_t ipv4, uint16_t port, FDR_ON_ERROR) { this->address.sin_family = AF_INET; @@ -98,12 +94,14 @@ class UDPSocket : public BaseSocket this->address.sin_addr.s_addr = ipv4; // Try to connect. - if (connect(this->sock, (const sockaddr* )&this->address, sizeof(sockaddr_in)) < 0) + int status = connect(this->sock, (const sockaddr* )&this->address, sizeof(sockaddr_in)); + if (status == -1) { onError(errno, "Connection failed to the host."); return; } } + // Connect to a server with `host` address and `port` values. void Connect(const char* host, uint16_t port, FDR_ON_ERROR) { struct addrinfo hints, *res, *it; @@ -111,8 +109,8 @@ class UDPSocket : public BaseSocket hints.ai_family = AF_INET; hints.ai_socktype = SOCK_DGRAM; - int status; - if ((status = getaddrinfo(host, NULL, &hints, &res)) != 0) + int status = getaddrinfo(host, NULL, &hints, &res); + if (status != 0) { onError(errno, "Invalid address." + std::string(gai_strerror(status))); return; @@ -131,59 +129,42 @@ class UDPSocket : public BaseSocket this->Connect((uint32_t)this->address.sin_addr.s_addr, port, onError); } + // Connect to a server with `host` address and `port` values. + void Connect(const std::string& host, uint16_t port, FDR_ON_ERROR) { this->Connect(host.c_str(), port, onError); } private: static void Receive(UDPSocket* udpSocket) { char tempBuffer[UDPSocket::BUFFER_SIZE]; + ssize_t messageLength; - while (true) + while ((messageLength = recv(udpSocket->sock, tempBuffer, UDPSocket::BUFFER_SIZE, 0)) != -1) { - int messageLength; - messageLength = recv(udpSocket->sock, tempBuffer, UDPSocket::BUFFER_SIZE, 0); + tempBuffer[messageLength] = '\0'; + if (udpSocket->onMessageReceived) + udpSocket->onMessageReceived(std::string(tempBuffer, messageLength), ipToString(udpSocket->address), ntohs(udpSocket->address.sin_port)); - if (messageLength < 0) - { - perror("recvfrom"); - return; - } - else - { - tempBuffer[messageLength] = '\0'; - if (udpSocket->onMessageReceived) - udpSocket->onMessageReceived(std::string(tempBuffer, messageLength), ipToString(udpSocket->address), ntohs(udpSocket->address.sin_port)); - - if (udpSocket->onRawMessageReceived) - udpSocket->onRawMessageReceived(tempBuffer, messageLength, ipToString(udpSocket->address), ntohs(udpSocket->address.sin_port)); - } + if (udpSocket->onRawMessageReceived) + udpSocket->onRawMessageReceived(tempBuffer, messageLength, ipToString(udpSocket->address), ntohs(udpSocket->address.sin_port)); } } + static void ReceiveFrom(UDPSocket* udpSocket) { sockaddr_in hostAddr; socklen_t hostAddrSize = sizeof(hostAddr); char tempBuffer[UDPSocket::BUFFER_SIZE]; + ssize_t messageLength; - while (true) + while ((messageLength = recvfrom(udpSocket->sock, tempBuffer, UDPSocket::BUFFER_SIZE, 0, (sockaddr* )&hostAddr, &hostAddrSize)) != -1) { - int messageLength; - messageLength = recvfrom(udpSocket->sock, tempBuffer, UDPSocket::BUFFER_SIZE, 0, (sockaddr* )&hostAddr, &hostAddrSize); + tempBuffer[messageLength] = '\0'; + if (udpSocket->onMessageReceived) + udpSocket->onMessageReceived(std::string(tempBuffer, messageLength), ipToString(hostAddr), ntohs(hostAddr.sin_port)); - if (messageLength < 0) - { - perror("recvfrom"); - return; - } - else - { - tempBuffer[messageLength] = '\0'; - if (udpSocket->onMessageReceived) - udpSocket->onMessageReceived(std::string(tempBuffer, messageLength), ipToString(hostAddr), ntohs(hostAddr.sin_port)); - - if (udpSocket->onRawMessageReceived) - udpSocket->onRawMessageReceived(tempBuffer, messageLength, ipToString(hostAddr), ntohs(hostAddr.sin_port)); - } + if (udpSocket->onRawMessageReceived) + udpSocket->onRawMessageReceived(tempBuffer, messageLength, ipToString(hostAddr), ntohs(hostAddr.sin_port)); } } }; \ No newline at end of file diff --git a/examples/Makefile b/examples/Makefile index fe78578..efbd126 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -1,5 +1,5 @@ CC := g++ -CFLAGS := --std=c++11 +CFLAGS := --std=c++11 -Wall -Wextra -Werror=conversion LIBS := -lpthread INC := -I../async-sockets/include RM := rm diff --git a/examples/tcp-client.cpp b/examples/tcp-client.cpp index f3542e8..b698b52 100644 --- a/examples/tcp-client.cpp +++ b/examples/tcp-client.cpp @@ -11,15 +11,14 @@ int main() }); // Start receiving from the host. - tcpSocket.onMessageReceived = [](string message) { - cout << "Message from the Server: " << message << endl; - }; - // If you want to use raw bytes instead of std::string: - /* tcpSocket.onRawMessageReceived = [](const char* message, int length) { cout << "Message from the Server: " << message << "(" << length << ")" << endl; }; - */ + + // If you want to use std::string instead of const char*: + //tcpSocket.onMessageReceived = [](string message) { + // cout << "Message from the Server: " << message << endl; + //}; // On socket closed: tcpSocket.onSocketClosed = [](int errorCode){ From bcc2ba7b1c0ae3cec2da855833d2e146a9af5473 Mon Sep 17 00:00:00 2001 From: Stewart Wadsworth Date: Wed, 10 May 2023 22:14:55 -0400 Subject: [PATCH 12/15] the size of any temp buffers are now (optionally) exposed to the user if they want to change them. also the default size is now a #define so that it can be globally changed at compile time --- async-sockets/include/basesocket.hpp | 5 ++++- async-sockets/include/tcpsocket.hpp | 17 +++++++++++------ async-sockets/include/udpsocket.hpp | 15 +++++++++------ 3 files changed, 24 insertions(+), 13 deletions(-) diff --git a/async-sockets/include/basesocket.hpp b/async-sockets/include/basesocket.hpp index 9bdc613..a2ca33f 100644 --- a/async-sockets/include/basesocket.hpp +++ b/async-sockets/include/basesocket.hpp @@ -17,6 +17,10 @@ #define FDR_UNUSED(expr){ (void)(expr); } #define FDR_ON_ERROR std::function onError = [](int errorCode, std::string errorMessage){FDR_UNUSED(errorCode); FDR_UNUSED(errorMessage)} +#ifndef AS_DEFAULT_BUFFER_SIZE +#define AS_DEFAULT_BUFFER_SIZE 0x1000 /*4096 bytes*/ +#endif + class BaseSocket { public: @@ -26,7 +30,6 @@ class BaseSocket UDP = SOCK_DGRAM }; sockaddr_in address; - constexpr static uint16_t BUFFER_SIZE = 0x1000; // 4096 bytes void Close() { shutdown(this->sock, SHUT_RDWR); diff --git a/async-sockets/include/tcpsocket.hpp b/async-sockets/include/tcpsocket.hpp index 7cb3711..1b498a0 100644 --- a/async-sockets/include/tcpsocket.hpp +++ b/async-sockets/include/tcpsocket.hpp @@ -22,6 +22,7 @@ class TCPSocket : public BaseSocket ssize_t Send(const std::string& message) { return this->Send(message.c_str(), message.length()); } // Connect to a TCP Server with `uint32_t ipv4` & `uint16_t port` values + template void Connect(uint32_t ipv4, uint16_t port, std::function onConnected = [](){}, FDR_ON_ERROR) { this->address.sin_family = AF_INET; @@ -45,9 +46,10 @@ class TCPSocket : public BaseSocket onConnected(); // Start listening from server: - this->Listen(); + this->Listen(); } // Connect to a TCP Server with `const char* host` & `uint16_t port` values + template void Connect(const char* host, uint16_t port, std::function onConnected = [](){}, FDR_ON_ERROR) { struct addrinfo hints, *res, *it; @@ -72,18 +74,20 @@ class TCPSocket : public BaseSocket freeaddrinfo(res); - this->Connect((uint32_t)this->address.sin_addr.s_addr, port, onConnected, onError); + this->Connect((uint32_t)this->address.sin_addr.s_addr, port, onConnected, onError); } // Connect to a TCP Server with `const std::string& ipv4` & `uint16_t port` values + template void Connect(const std::string& host, uint16_t port, std::function onConnected = [](){}, FDR_ON_ERROR) { - this->Connect(host.c_str(), port, onConnected, onError); + this->Connect(host.c_str(), port, onConnected, onError); } // Start another thread to listen the socket + template void Listen() { - std::thread t(TCPSocket::Receive, this); + std::thread t(TCPSocket::Receive, this); t.detach(); } @@ -93,12 +97,13 @@ class TCPSocket : public BaseSocket bool deleteAfterClosed = false; private: + template static void Receive(TCPSocket* socket) { - char tempBuffer[TCPSocket::BUFFER_SIZE]; + char tempBuffer[BUFFER_SIZE]; ssize_t messageLength; - while ((messageLength = recv(socket->sock, tempBuffer, TCPSocket::BUFFER_SIZE, 0)) > 0) + while ((messageLength = recv(socket->sock, tempBuffer, BUFFER_SIZE, 0)) > 0) { tempBuffer[messageLength] = '\0'; if(socket->onMessageReceived) diff --git a/async-sockets/include/udpsocket.hpp b/async-sockets/include/udpsocket.hpp index b065462..41eb96d 100644 --- a/async-sockets/include/udpsocket.hpp +++ b/async-sockets/include/udpsocket.hpp @@ -10,17 +10,18 @@ class UDPSocket : public BaseSocket std::function onMessageReceived; std::function onRawMessageReceived; + template explicit UDPSocket(bool useConnect = false, FDR_ON_ERROR, int socketId = -1): BaseSocket(onError, SocketType::UDP, socketId) { if (useConnect) { - std::thread t(Receive, this); // usage with Connect() + std::thread t(Receive, this); // usage with Connect() t.detach(); } else { - std::thread t(ReceiveFrom, this); + std::thread t(ReceiveFrom, this); t.detach(); } } @@ -133,12 +134,13 @@ class UDPSocket : public BaseSocket void Connect(const std::string& host, uint16_t port, FDR_ON_ERROR) { this->Connect(host.c_str(), port, onError); } private: + template static void Receive(UDPSocket* udpSocket) { - char tempBuffer[UDPSocket::BUFFER_SIZE]; + char tempBuffer[BUFFER_SIZE]; ssize_t messageLength; - while ((messageLength = recv(udpSocket->sock, tempBuffer, UDPSocket::BUFFER_SIZE, 0)) != -1) + while ((messageLength = recv(udpSocket->sock, tempBuffer, BUFFER_SIZE, 0)) != -1) { tempBuffer[messageLength] = '\0'; if (udpSocket->onMessageReceived) @@ -149,15 +151,16 @@ class UDPSocket : public BaseSocket } } + template static void ReceiveFrom(UDPSocket* udpSocket) { sockaddr_in hostAddr; socklen_t hostAddrSize = sizeof(hostAddr); - char tempBuffer[UDPSocket::BUFFER_SIZE]; + char tempBuffer[BUFFER_SIZE]; ssize_t messageLength; - while ((messageLength = recvfrom(udpSocket->sock, tempBuffer, UDPSocket::BUFFER_SIZE, 0, (sockaddr* )&hostAddr, &hostAddrSize)) != -1) + while ((messageLength = recvfrom(udpSocket->sock, tempBuffer, BUFFER_SIZE, 0, (sockaddr* )&hostAddr, &hostAddrSize)) != -1) { tempBuffer[messageLength] = '\0'; if (udpSocket->onMessageReceived) From 09637b15aaa0f4570d6fba43fb852894880dd7fe Mon Sep 17 00:00:00 2001 From: Stewart Wadsworth Date: Wed, 10 May 2023 22:20:46 -0400 Subject: [PATCH 13/15] include custom buffer size in one example. make file will now automatically detect changes in files and rebuild only if needed.......not that it matters for this project really. --- examples/Makefile | 22 ++++++++++++---------- examples/tcp-client.cpp | 6 +++--- examples/tcp-server.cpp | 2 +- examples/udp-client.cpp | 2 +- examples/udp-server.cpp | 2 +- 5 files changed, 18 insertions(+), 16 deletions(-) diff --git a/examples/Makefile b/examples/Makefile index efbd126..2cd389d 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -1,25 +1,27 @@ CC := g++ CFLAGS := --std=c++11 -Wall -Wextra -Werror=conversion LIBS := -lpthread -INC := -I../async-sockets/include +INC := ../async-sockets/include RM := rm +.PHONY: all clean + all: tcp-client tcp-server udp-client udp-server -tcp-client: - $(CC) $(CFLAGS) tcp-client.cpp $(INC) $(LIBS) -o tcp-client +tcp-client: tcp-client.cpp $(INC)/tcpsocket.hpp + $(CC) $(CFLAGS) $< -I$(INC) $(LIBS) -o $@ -tcp-server: - $(CC) $(CFLAGS) tcp-server.cpp $(INC) $(LIBS) -o tcp-server +tcp-server: tcp-server.cpp $(INC)/tcpserver.hpp + $(CC) $(CFLAGS) $< -I$(INC) $(LIBS) -o $@ -udp-client: - $(CC) $(CFLAGS) udp-client.cpp $(INC) $(LIBS) -o udp-client +udp-client: udp-client.cpp $(INC)/udpsocket.hpp + $(CC) $(CFLAGS) $< -I$(INC) $(LIBS) -o $@ -udp-server: - $(CC) $(CFLAGS) udp-server.cpp $(INC) $(LIBS) -o udp-server +udp-server: udp-server.cpp $(INC)/udpserver.hpp + $(CC) $(CFLAGS) $< -I$(INC) $(LIBS) -o $@ clean: $(RM) tcp-client $(RM) tcp-server $(RM) udp-client - $(RM) udp-server \ No newline at end of file + $(RM) udp-server diff --git a/examples/tcp-client.cpp b/examples/tcp-client.cpp index b698b52..13dea87 100644 --- a/examples/tcp-client.cpp +++ b/examples/tcp-client.cpp @@ -1,4 +1,4 @@ -#include "../async-sockets/include/tcpsocket.hpp" +#include "tcpsocket.hpp" #include using namespace std; @@ -25,8 +25,8 @@ int main() cout << "Connection closed: " << errorCode << endl; }; - // Connect to the host. - tcpSocket.Connect("localhost", 8888, [&] { + // Connect to the host (with a custom buffer size). + tcpSocket.Connect<0xFFFF>("localhost", 8888, [&] { cout << "Connected to the server successfully." << endl; // Send String: diff --git a/examples/tcp-server.cpp b/examples/tcp-server.cpp index 56f5c17..5b44d40 100644 --- a/examples/tcp-server.cpp +++ b/examples/tcp-server.cpp @@ -1,4 +1,4 @@ -#include "../async-sockets/include/tcpserver.hpp" +#include "tcpserver.hpp" #include using namespace std; diff --git a/examples/udp-client.cpp b/examples/udp-client.cpp index 3192510..b689c41 100644 --- a/examples/udp-client.cpp +++ b/examples/udp-client.cpp @@ -1,4 +1,4 @@ -#include "../async-sockets/include/udpsocket.hpp" +#include "udpsocket.hpp" #include using namespace std; diff --git a/examples/udp-server.cpp b/examples/udp-server.cpp index f3e3f65..4201c55 100644 --- a/examples/udp-server.cpp +++ b/examples/udp-server.cpp @@ -1,4 +1,4 @@ -#include "../async-sockets/include/udpserver.hpp" +#include "udpserver.hpp" #include using namespace std; From c3440df6d779e73c1c2c46a66d00e6106e8ed40a Mon Sep 17 00:00:00 2001 From: stewart Date: Thu, 11 May 2023 21:45:36 -0400 Subject: [PATCH 14/15] change over to class templates --- async-sockets/include/tcpserver.hpp | 7 ++++--- async-sockets/include/tcpsocket.hpp | 14 +++++--------- async-sockets/include/udpserver.hpp | 3 ++- async-sockets/include/udpsocket.hpp | 9 +++------ examples/tcp-client.cpp | 4 ++-- examples/tcp-server.cpp | 4 ++-- examples/udp-client.cpp | 2 +- examples/udp-server.cpp | 2 +- 8 files changed, 20 insertions(+), 25 deletions(-) diff --git a/async-sockets/include/tcpserver.hpp b/async-sockets/include/tcpserver.hpp index a91888b..e7beb59 100644 --- a/async-sockets/include/tcpserver.hpp +++ b/async-sockets/include/tcpserver.hpp @@ -3,11 +3,12 @@ #include "tcpsocket.hpp" #include +template class TCPServer : public BaseSocket { public: // Event Listeners: - std::function onNewConnection = [](TCPSocket* sock){FDR_UNUSED(sock)}; + std::function*)> onNewConnection = [](TCPSocket* sock){FDR_UNUSED(sock)}; explicit TCPServer(FDR_ON_ERROR): BaseSocket(onError, SocketType::TCP) { @@ -57,7 +58,7 @@ class TCPServer : public BaseSocket } private: - static void Accept(TCPServer* server, FDR_ON_ERROR) + static void Accept(TCPServer* server, FDR_ON_ERROR) { sockaddr_in newSocketInfo; socklen_t newSocketInfoLength = sizeof(newSocketInfo); @@ -75,7 +76,7 @@ class TCPServer : public BaseSocket return; } - TCPSocket* newSocket = new TCPSocket(onError, newSocketFileDescriptor); + TCPSocket* newSocket = new TCPSocket(onError, newSocketFileDescriptor); newSocket->deleteAfterClosed = true; newSocket->setAddressStruct(newSocketInfo); diff --git a/async-sockets/include/tcpsocket.hpp b/async-sockets/include/tcpsocket.hpp index 1b498a0..2f31dea 100644 --- a/async-sockets/include/tcpsocket.hpp +++ b/async-sockets/include/tcpsocket.hpp @@ -6,6 +6,7 @@ #include #include +template class TCPSocket : public BaseSocket { public: @@ -22,7 +23,6 @@ class TCPSocket : public BaseSocket ssize_t Send(const std::string& message) { return this->Send(message.c_str(), message.length()); } // Connect to a TCP Server with `uint32_t ipv4` & `uint16_t port` values - template void Connect(uint32_t ipv4, uint16_t port, std::function onConnected = [](){}, FDR_ON_ERROR) { this->address.sin_family = AF_INET; @@ -46,10 +46,9 @@ class TCPSocket : public BaseSocket onConnected(); // Start listening from server: - this->Listen(); + this->Listen(); } // Connect to a TCP Server with `const char* host` & `uint16_t port` values - template void Connect(const char* host, uint16_t port, std::function onConnected = [](){}, FDR_ON_ERROR) { struct addrinfo hints, *res, *it; @@ -74,20 +73,18 @@ class TCPSocket : public BaseSocket freeaddrinfo(res); - this->Connect((uint32_t)this->address.sin_addr.s_addr, port, onConnected, onError); + this->Connect((uint32_t)this->address.sin_addr.s_addr, port, onConnected, onError); } // Connect to a TCP Server with `const std::string& ipv4` & `uint16_t port` values - template void Connect(const std::string& host, uint16_t port, std::function onConnected = [](){}, FDR_ON_ERROR) { - this->Connect(host.c_str(), port, onConnected, onError); + this->Connect(host.c_str(), port, onConnected, onError); } // Start another thread to listen the socket - template void Listen() { - std::thread t(TCPSocket::Receive, this); + std::thread t(TCPSocket::Receive, this); t.detach(); } @@ -97,7 +94,6 @@ class TCPSocket : public BaseSocket bool deleteAfterClosed = false; private: - template static void Receive(TCPSocket* socket) { char tempBuffer[BUFFER_SIZE]; diff --git a/async-sockets/include/udpserver.hpp b/async-sockets/include/udpserver.hpp index df938d8..65ba250 100644 --- a/async-sockets/include/udpserver.hpp +++ b/async-sockets/include/udpserver.hpp @@ -3,7 +3,8 @@ #include "udpsocket.hpp" #include -class UDPServer : public UDPSocket +template +class UDPServer : public UDPSocket { public: // Bind the custom address & port of the server. diff --git a/async-sockets/include/udpsocket.hpp b/async-sockets/include/udpsocket.hpp index 41eb96d..3610358 100644 --- a/async-sockets/include/udpsocket.hpp +++ b/async-sockets/include/udpsocket.hpp @@ -4,24 +4,23 @@ #include #include +template class UDPSocket : public BaseSocket { public: std::function onMessageReceived; std::function onRawMessageReceived; - template explicit UDPSocket(bool useConnect = false, FDR_ON_ERROR, int socketId = -1): BaseSocket(onError, SocketType::UDP, socketId) { if (useConnect) { - - std::thread t(Receive, this); // usage with Connect() + std::thread t(Receive, this); // usage with Connect() t.detach(); } else { - std::thread t(ReceiveFrom, this); + std::thread t(ReceiveFrom, this); t.detach(); } } @@ -134,7 +133,6 @@ class UDPSocket : public BaseSocket void Connect(const std::string& host, uint16_t port, FDR_ON_ERROR) { this->Connect(host.c_str(), port, onError); } private: - template static void Receive(UDPSocket* udpSocket) { char tempBuffer[BUFFER_SIZE]; @@ -151,7 +149,6 @@ class UDPSocket : public BaseSocket } } - template static void ReceiveFrom(UDPSocket* udpSocket) { sockaddr_in hostAddr; diff --git a/examples/tcp-client.cpp b/examples/tcp-client.cpp index 13dea87..3e82b5e 100644 --- a/examples/tcp-client.cpp +++ b/examples/tcp-client.cpp @@ -6,7 +6,7 @@ using namespace std; int main() { // Initialize socket. - TCPSocket tcpSocket([](int errorCode, std::string errorMessage){ + TCPSocket<> tcpSocket([](int errorCode, std::string errorMessage){ cout << "Socket creation error:" << errorCode << " : " << errorMessage << endl; }); @@ -26,7 +26,7 @@ int main() }; // Connect to the host (with a custom buffer size). - tcpSocket.Connect<0xFFFF>("localhost", 8888, [&] { + tcpSocket.Connect("localhost", 8888, [&] { cout << "Connected to the server successfully." << endl; // Send String: diff --git a/examples/tcp-server.cpp b/examples/tcp-server.cpp index 5b44d40..7c642b8 100644 --- a/examples/tcp-server.cpp +++ b/examples/tcp-server.cpp @@ -6,10 +6,10 @@ using namespace std; int main() { // Initialize server socket.. - TCPServer tcpServer; + TCPServer<> tcpServer; // When a new client connected: - tcpServer.onNewConnection = [&](TCPSocket *newClient) { + tcpServer.onNewConnection = [&](TCPSocket<> *newClient) { cout << "New client: ["; cout << newClient->remoteAddress() << ":" << newClient->remotePort() << "]" << endl; diff --git a/examples/udp-client.cpp b/examples/udp-client.cpp index b689c41..d9e63aa 100644 --- a/examples/udp-client.cpp +++ b/examples/udp-client.cpp @@ -10,7 +10,7 @@ int main() constexpr uint16_t PORT = 8888; // Initialize socket. - UDPSocket udpSocket(true); // "true" to use Connection on UDP. Default is "false". + UDPSocket<100> udpSocket(true); // "true" to use Connection on UDP. Default is "false". udpSocket.Connect(IP, PORT); // Send String: diff --git a/examples/udp-server.cpp b/examples/udp-server.cpp index 4201c55..990bb2d 100644 --- a/examples/udp-server.cpp +++ b/examples/udp-server.cpp @@ -6,7 +6,7 @@ using namespace std; int main() { // Initialize server socket.. - UDPServer udpServer; + UDPServer<> udpServer; // onMessageReceived will run when a message received with information of ip & port of sender: /*udpServer.onMessageReceived = [&](string message, string ipv4, uint16_t port) { From 78641cfde398d2cd71649f6911ee1bf4953498c0 Mon Sep 17 00:00:00 2001 From: Emin Fedar Date: Wed, 2 Aug 2023 15:42:20 +0300 Subject: [PATCH 15/15] fix: allocate one more byte to add null termination --- async-sockets/include/tcpsocket.hpp | 2 +- async-sockets/include/udpsocket.hpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/async-sockets/include/tcpsocket.hpp b/async-sockets/include/tcpsocket.hpp index 2f31dea..9ee8781 100644 --- a/async-sockets/include/tcpsocket.hpp +++ b/async-sockets/include/tcpsocket.hpp @@ -96,7 +96,7 @@ class TCPSocket : public BaseSocket private: static void Receive(TCPSocket* socket) { - char tempBuffer[BUFFER_SIZE]; + char tempBuffer[BUFFER_SIZE+1]; ssize_t messageLength; while ((messageLength = recv(socket->sock, tempBuffer, BUFFER_SIZE, 0)) > 0) diff --git a/async-sockets/include/udpsocket.hpp b/async-sockets/include/udpsocket.hpp index 3610358..f9b8b9a 100644 --- a/async-sockets/include/udpsocket.hpp +++ b/async-sockets/include/udpsocket.hpp @@ -135,7 +135,7 @@ class UDPSocket : public BaseSocket private: static void Receive(UDPSocket* udpSocket) { - char tempBuffer[BUFFER_SIZE]; + char tempBuffer[BUFFER_SIZE+1]; ssize_t messageLength; while ((messageLength = recv(udpSocket->sock, tempBuffer, BUFFER_SIZE, 0)) != -1) @@ -154,7 +154,7 @@ class UDPSocket : public BaseSocket sockaddr_in hostAddr; socklen_t hostAddrSize = sizeof(hostAddr); - char tempBuffer[BUFFER_SIZE]; + char tempBuffer[BUFFER_SIZE+1]; ssize_t messageLength; while ((messageLength = recvfrom(udpSocket->sock, tempBuffer, BUFFER_SIZE, 0, (sockaddr* )&hostAddr, &hostAddrSize)) != -1)