From fb72473e7f5ec38006107d924c248a17370ca7bd Mon Sep 17 00:00:00 2001 From: Emin Fedar Date: Thu, 27 Apr 2023 15:41:32 +0300 Subject: [PATCH 1/7] 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 2/7] 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 3/7] 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 4/7] 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 5/7] 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 6/7] 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 7/7] 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)