diff options
Diffstat (limited to 'source/core/StarNetImpl.hpp')
-rw-r--r-- | source/core/StarNetImpl.hpp | 157 |
1 files changed, 157 insertions, 0 deletions
diff --git a/source/core/StarNetImpl.hpp b/source/core/StarNetImpl.hpp new file mode 100644 index 0000000..80d75da --- /dev/null +++ b/source/core/StarNetImpl.hpp @@ -0,0 +1,157 @@ +#ifdef STAR_SYSTEM_FAMILY_WINDOWS +#include <winsock2.h> +#include <ws2tcpip.h> +#include <stdio.h> +#else +#ifdef STAR_SYSTEM_FREEBSD +#include <sys/types.h> +#include <sys/socket.h> +#endif +#include <errno.h> +#include <string.h> +#include <arpa/inet.h> +#include <netdb.h> +#include <netinet/in.h> +#include <netinet/udp.h> +#include <netinet/tcp.h> +#include <unistd.h> +#include <fcntl.h> +#include <poll.h> +#endif + +#include "StarHostAddress.hpp" + +#ifndef AI_ADDRCONFIG +#define AI_ADDRCONFIG 0 +#endif + +namespace Star { + +#ifdef STAR_SYSTEM_FAMILY_WINDOWS +struct WindowsSocketInitializer { + WindowsSocketInitializer() { + WSADATA wsaData; + if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) + fatalError("WSAStartup failed", false); + }; +}; +static WindowsSocketInitializer g_windowsSocketInitializer; +#endif + +inline String netErrorString() { +#ifdef STAR_SYSTEM_WINDOWS + LPVOID lpMsgBuf = NULL; + + FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + WSAGetLastError(), + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language + (LPTSTR)&lpMsgBuf, + 0, + NULL); + + String result = String((char*)lpMsgBuf); + + if (lpMsgBuf != NULL) + LocalFree(lpMsgBuf); + + return result; +#else + return strf("%s - %s", errno, strerror(errno)); +#endif +} + +inline bool netErrorConnectionReset() { +#ifdef STAR_SYSTEM_FAMILY_WINDOWS + return WSAGetLastError() == WSAECONNRESET || WSAGetLastError() == WSAENETRESET; +#else + return errno == ECONNRESET || errno == ETIMEDOUT; +#endif +} + +inline bool netErrorInterrupt() { +#ifdef STAR_SYSTEM_FAMILY_WINDOWS + return WSAGetLastError() == WSAEINTR || WSAGetLastError() == WSAEWOULDBLOCK; +#else + return errno == EAGAIN || errno == EINTR || errno == EWOULDBLOCK; +#endif +} + +inline void setAddressFromNative(HostAddressWithPort& addressWithPort, NetworkMode mode, struct sockaddr_storage* sockAddr) { + switch (mode) { + case NetworkMode::IPv4: { + struct sockaddr_in* addr4 = (struct sockaddr_in*)sockAddr; + addressWithPort = HostAddressWithPort(mode, (uint8_t*)&(addr4->sin_addr.s_addr), ntohs(addr4->sin_port)); + break; + } + case NetworkMode::IPv6: { + struct sockaddr_in6* addr6 = (struct sockaddr_in6*)sockAddr; + addressWithPort = HostAddressWithPort(mode, (uint8_t*)&addr6->sin6_addr.s6_addr, ntohs(addr6->sin6_port)); + break; + } + default: + throw NetworkException("Invalid network mode for setAddressFromNative"); + } +} + +inline void setNativeFromAddress(HostAddressWithPort const& addressWithPort, struct sockaddr_storage* sockAddr, socklen_t* sockAddrLen) { + switch (addressWithPort.address().mode()) { + case NetworkMode::IPv4: { + struct sockaddr_in* addr4 = (struct sockaddr_in*)sockAddr; + *sockAddrLen = sizeof(*addr4); + + memset(addr4, 0, *sockAddrLen); + addr4->sin_family = AF_INET; + addr4->sin_port = htons(addressWithPort.port()); + memcpy(((char*)&addr4->sin_addr.s_addr), addressWithPort.address().bytes(), addressWithPort.address().size()); + + break; + } + case NetworkMode::IPv6: { + struct sockaddr_in6* addr6 = (struct sockaddr_in6*)sockAddr; + *sockAddrLen = sizeof(*addr6); + + memset(addr6, 0, *sockAddrLen); + addr6->sin6_family = AF_INET6; + addr6->sin6_port = htons(addressWithPort.port()); + memcpy(((char*)&addr6->sin6_addr.s6_addr), addressWithPort.address().bytes(), addressWithPort.address().size()); + break; + } + default: + throw NetworkException("Invalid network mode for setNativeFromAddress"); + } +} + +#ifdef STAR_SYSTEM_FAMILY_WINDOWS +inline bool invalidSocketDescriptor(SOCKET socket) { + return socket == INVALID_SOCKET; +} +#else +inline bool invalidSocketDescriptor(int socket) { + return socket < 0; +} +#endif + +struct SocketImpl { + SocketImpl() { + socketDesc = 0; + } + + void setSockOpt(int level, int optname, const void* optval, socklen_t len) { +#ifdef STAR_SYSTEM_FAMILY_WINDOWS + int ret = ::setsockopt(socketDesc, level, optname, (const char*)optval, len); +#else + int ret = ::setsockopt(socketDesc, level, optname, optval, len); +#endif + if (ret < 0) + throw NetworkException(strf("setSockOpt failed to set %d, %d: %s", level, optname, netErrorString())); + } + +#ifdef STAR_SYSTEM_FAMILY_WINDOWS + SOCKET socketDesc; +#else + int socketDesc; +#endif +}; + +} |