From 33abffa936fcb13d55e9d9ac0a60d4de2ed01af0 Mon Sep 17 00:00:00 2001 From: Megumumpkin Date: Wed, 3 Nov 2021 17:20:30 +0700 Subject: [PATCH] Linux Network Implementation (#337) * Linux Network Implementation * Linux Network - Faster IP Address Conversion --- WickedEngine/wiNetwork.h | 3 - WickedEngine/wiNetwork_Linux.cpp | 145 +++++++++++++++++++++++++++++-- 2 files changed, 138 insertions(+), 10 deletions(-) diff --git a/WickedEngine/wiNetwork.h b/WickedEngine/wiNetwork.h index fe9fa4f8f..45685c95e 100644 --- a/WickedEngine/wiNetwork.h +++ b/WickedEngine/wiNetwork.h @@ -24,9 +24,6 @@ namespace wiNetwork // Creates a socket that can be used to send or receive data bool CreateSocket(Socket* sock); - // Destroys socket - bool Destroy(Socket* sock); - // Sends data packet to destination connection // sock : socket that sends the packet // connection : connection to the receiver, it is provided by the call site diff --git a/WickedEngine/wiNetwork_Linux.cpp b/WickedEngine/wiNetwork_Linux.cpp index 93d693be4..f33b11909 100644 --- a/WickedEngine/wiNetwork_Linux.cpp +++ b/WickedEngine/wiNetwork_Linux.cpp @@ -3,43 +3,174 @@ #ifdef PLATFORM_LINUX #include "wiNetwork.h" #include "wiBackLog.h" +#include "wiTimer.h" + +#include +#include + +#include +#include namespace wiNetwork { + //For easy address conversion + struct in_addr_union { + union { + struct { uint8_t s_b1,s_b2,s_b3,s_b4; } S_un_b; + struct { uint16_t s_w1,s_w2; } S_un_w; + uint32_t S_addr; + }; + }; + + struct SocketInternal{ + int handle; + ~SocketInternal(){ + int result = close(handle); + if(result < 0){ + assert(0); + } + } + }; + + SocketInternal* to_internal(const Socket* param) + { + return static_cast(param->internal_state.get()); + } + void Initialize() { - wiBackLog::post("TODO wiNetwork_Linux"); + wiTimer timer; + + int result; + + wiBackLog::post("wiNetwork_Linux Initialized (" + std::to_string((int)std::round(timer.elapsed())) + " ms)"); } bool CreateSocket(Socket* sock) { - return false; - } - bool Destroy(Socket* sock) - { - return false; + std::shared_ptr socketinternal = std::make_shared(); + sock->internal_state = socketinternal; + + socketinternal->handle = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + + if(socketinternal->handle == -1){ + std::stringstream ss; + ss << "wiNetwork_Linux error in CreateSocket: Could not create socket"; + wiBackLog::post(ss.str().c_str()); + return false; + } + + return true; } bool Send(const Socket* sock, const Connection* connection, const void* data, size_t dataSize) { + if (sock->IsValid()){ + sockaddr_in target; + target.sin_family = AF_INET; + target.sin_port = htons(connection->port); + in_addr_union address; + address.S_un_b.s_b1 = connection->ipaddress[0]; + address.S_un_b.s_b2 = connection->ipaddress[1]; + address.S_un_b.s_b3 = connection->ipaddress[2]; + address.S_un_b.s_b4 = connection->ipaddress[3]; + target.sin_addr.s_addr = address.S_addr; + + auto socketinternal = to_internal(sock); + int result = sendto(socketinternal->handle, (const char*)data, (int)dataSize, 0, (const sockaddr*)&target, sizeof(target)); + if (result < 0) + { + std::stringstream ss; + ss << "wiNetwork_Linux error in Send: (Error Code: " + std::to_string(result) + ") " + strerror(result); + wiBackLog::post(ss.str().c_str()); + return false; + } + + return true; + } return false; } bool ListenPort(const Socket* sock, uint16_t port) { + if (sock->IsValid()){ + sockaddr_in target; + target.sin_family = AF_INET; + target.sin_port = htons(port); + target.sin_addr.s_addr = htonl(INADDR_ANY); + + auto socketinternal = to_internal(sock); + + int result = bind(socketinternal->handle, (struct sockaddr *)&target , sizeof(target)); + if (result < 0) + { + std::stringstream ss; + ss << "wiNetwork_Linux error in Send: (Error Code: " + std::to_string(result) + ") " + strerror(result); + wiBackLog::post(ss.str().c_str()); + return false; + } + + return true; + } return false; } bool CanReceive(const Socket* sock, long timeout_microseconds) { + if (sock->IsValid()){ + auto socketinternal = to_internal(sock); + + fd_set readfds; + FD_ZERO(&readfds); + FD_SET(socketinternal->handle, &readfds); + timeval timeout; + timeout.tv_sec = 0; + timeout.tv_usec = timeout_microseconds; + + int result = select(0, &readfds, NULL, NULL, &timeout); + if (result < 0) + { + std::stringstream ss; + ss << "wiNetwork_Linux error in Send: (Error Code: " + std::to_string(result) + ") " + strerror(result); + wiBackLog::post(ss.str().c_str()); + assert(0); + return false; + } + + return FD_ISSET(socketinternal->handle, &readfds); + } return false; } bool Receive(const Socket* sock, Connection* connection, void* data, size_t dataSize) { + if (sock->IsValid()){ + auto socketinternal = to_internal(sock); + + sockaddr_in sender; + int targetsize = sizeof(sender); + int result = recvfrom(socketinternal->handle, (char*)data, (int)dataSize, 0, (sockaddr*)& sender, (socklen_t*)&targetsize); + if (result < 0) + { + std::stringstream ss; + ss << "wiNetwork_Linux error in Send: (Error Code: " + std::to_string(result) + ") " + strerror(result); + wiBackLog::post(ss.str().c_str()); + assert(0); + return false; + } + + connection->port = htons(sender.sin_port); // reverse byte order from network to host + in_addr_union address; + address.S_addr = sender.sin_addr.s_addr; + connection->ipaddress[0] = address.S_un_b.s_b1; + connection->ipaddress[1] = address.S_un_b.s_b2; + connection->ipaddress[2] = address.S_un_b.s_b3; + connection->ipaddress[3] = address.S_un_b.s_b4; + + return true; + } return false; } - } #endif // LINUX