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){