mgba/include/mgba-util/socket.h

543 lines
12 KiB
C
Raw Normal View History

/* Copyright (c) 2013-2014 Jeffrey Pfau
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
2014-02-04 07:01:26 +00:00
#ifndef SOCKET_H
#define SOCKET_H
#include <mgba-util/common.h>
2016-12-27 05:01:55 +00:00
CXX_GUARD_START
2016-04-18 01:03:13 +00:00
#if defined(__cplusplus) && !defined(restrict)
2014-07-20 23:37:54 +00:00
#define restrict __restrict__
#endif
2014-02-04 07:01:26 +00:00
#ifdef _WIN32
2014-04-24 04:42:08 +00:00
#include <ws2tcpip.h>
2014-02-04 07:01:26 +00:00
2015-01-16 08:11:50 +00:00
#define SOCKET_FAILED(s) ((s) == INVALID_SOCKET)
2014-02-04 07:01:26 +00:00
typedef SOCKET Socket;
#else
2020-02-09 01:46:56 +00:00
#ifdef GEKKO
#define USE_GETHOSTBYNAME
2020-02-09 01:46:56 +00:00
#include <network.h>
#else
2016-03-02 06:01:54 +00:00
#include <arpa/inet.h>
#include <netdb.h>
2014-02-04 07:01:26 +00:00
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <sys/types.h>
2014-02-04 07:01:26 +00:00
#include <sys/socket.h>
2020-02-09 01:46:56 +00:00
#endif
#include <errno.h>
#include <fcntl.h>
#include <sys/select.h>
2014-02-04 07:01:26 +00:00
2020-02-09 01:46:56 +00:00
#ifndef GEKKO
2014-04-24 04:42:08 +00:00
#define INVALID_SOCKET (-1)
2020-02-09 01:46:56 +00:00
#endif
2015-01-16 08:11:50 +00:00
#define SOCKET_FAILED(s) ((s) < 0)
2014-02-04 07:01:26 +00:00
typedef int Socket;
#endif
2022-08-08 04:31:42 +00:00
#if !defined(__3DS__) && !defined(GEKKO)
#define HAS_IPV6
#endif
2015-01-09 10:03:42 +00:00
enum IP {
IPV4,
IPV6
};
struct Address {
enum IP version;
union {
uint32_t ipv4;
uint8_t ipv6[16];
};
};
2014-02-04 07:01:26 +00:00
2022-02-15 04:41:44 +00:00
#ifdef __3DS__
2016-03-02 06:01:54 +00:00
#include <3ds.h>
#include <malloc.h>
#define SOCU_ALIGN 0x1000
#define SOCU_BUFFERSIZE 0x100000
extern u32* SOCUBuffer;
#endif
2018-09-14 01:12:32 +00:00
#ifdef __SWITCH__
2018-07-15 15:38:39 +00:00
#include <switch.h>
#endif
2020-08-19 01:41:51 +00:00
#ifdef PSP2
#include <psp2/net/net.h>
#include <psp2/sysmodule.h>
#endif
2016-03-02 06:01:54 +00:00
2015-02-24 07:27:28 +00:00
static inline void SocketSubsystemInit() {
2014-02-04 07:01:26 +00:00
#ifdef _WIN32
2015-02-24 07:27:28 +00:00
WSADATA data;
WSAStartup(MAKEWORD(2, 2), &data);
2022-02-15 04:41:44 +00:00
#elif defined(__3DS__)
2016-03-02 06:01:54 +00:00
if (!SOCUBuffer) {
SOCUBuffer = memalign(SOCU_ALIGN, SOCU_BUFFERSIZE);
socInit(SOCUBuffer, SOCU_BUFFERSIZE);
}
2018-09-14 01:12:32 +00:00
#elif defined(__SWITCH__)
2018-07-15 15:38:39 +00:00
socketInitializeDefault();
2020-02-09 01:46:56 +00:00
#elif defined(GEKKO)
net_init();
2020-08-19 01:41:51 +00:00
#elif defined(PSP2)
static uint8_t netMem[1024*1024];
sceSysmoduleLoadModule(SCE_SYSMODULE_NET);
sceNetInit(&(SceNetInitParam) { netMem, sizeof(netMem) });
2016-03-02 06:01:54 +00:00
#endif
}
static inline void SocketSubsystemDeinit() {
#ifdef _WIN32
WSACleanup();
2022-02-15 04:41:44 +00:00
#elif defined(__3DS__)
2016-03-02 06:01:54 +00:00
socExit();
free(SOCUBuffer);
SOCUBuffer = NULL;
2018-09-14 01:12:32 +00:00
#elif defined(__SWITCH__)
2018-07-15 15:38:39 +00:00
socketExit();
2020-02-09 01:46:56 +00:00
#elif defined(GEKKO)
net_deinit();
2020-08-19 01:41:51 +00:00
#elif defined(PSP2)
sceNetTerm();
sceSysmoduleUnloadModule(SCE_SYSMODULE_NET);
2015-02-24 07:27:28 +00:00
#endif
}
static inline int SocketError() {
#ifdef _WIN32
return WSAGetLastError();
#else
return errno;
#endif
}
static inline bool SocketWouldBlock() {
#ifdef _WIN32
return SocketError() == WSAEWOULDBLOCK;
#else
return SocketError() == EWOULDBLOCK || SocketError() == EAGAIN;
2014-02-04 07:01:26 +00:00
#endif
}
2014-02-05 09:22:34 +00:00
static inline ssize_t SocketSend(Socket socket, const void* buffer, size_t size) {
2015-02-24 08:02:24 +00:00
#ifdef _WIN32
return send(socket, (const char*) buffer, size, 0);
2020-02-09 01:46:56 +00:00
#elif defined(GEKKO)
return net_write(socket, buffer, size);
2015-02-24 08:02:24 +00:00
#else
return write(socket, buffer, size);
#endif
2014-02-04 07:01:26 +00:00
}
2014-02-05 09:22:34 +00:00
static inline ssize_t SocketRecv(Socket socket, void* buffer, size_t size) {
2018-09-14 01:12:32 +00:00
#if defined(_WIN32) || defined(__SWITCH__)
2015-02-24 08:02:24 +00:00
return recv(socket, (char*) buffer, size, 0);
2020-02-09 01:46:56 +00:00
#elif defined(GEKKO)
return net_read(socket, buffer, size);
2015-02-24 08:02:24 +00:00
#else
return read(socket, buffer, size);
#endif
2014-02-04 07:01:26 +00:00
}
2016-03-05 19:33:36 +00:00
static inline int SocketClose(Socket socket) {
#ifdef _WIN32
return closesocket(socket) == 0;
2020-02-09 01:46:56 +00:00
#elif defined(GEKKO)
return net_close(socket) >= 0;
2016-03-05 19:33:36 +00:00
#else
return close(socket) >= 0;
#endif
}
2022-08-08 04:31:42 +00:00
static inline void SocketCloseQuiet(Socket socket) {
int savedErrno = SocketError();
SocketClose(socket);
#ifdef _WIN32
WSASetLastError(savedErrno);
#else
errno = savedErrno;
#endif
}
static inline Socket SocketCreate(bool useIPv6, int protocol) {
if (useIPv6) {
#ifdef HAS_IPV6
return socket(AF_INET6, SOCK_STREAM, protocol);
#else
errno = EAFNOSUPPORT;
return INVALID_SOCKET;
#endif
} else {
2020-02-09 01:46:56 +00:00
#ifdef GEKKO
2022-08-08 04:31:42 +00:00
return net_socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
2020-02-09 01:46:56 +00:00
#else
2022-08-08 04:31:42 +00:00
return socket(AF_INET, SOCK_STREAM, protocol);
2020-02-09 01:46:56 +00:00
#endif
2022-08-08 04:31:42 +00:00
}
}
static inline Socket SocketOpenTCP(int port, const struct Address* bindAddress) {
bool useIPv6 = bindAddress && (bindAddress->version == IPV6);
Socket sock = SocketCreate(useIPv6, IPPROTO_TCP);
2014-04-24 04:42:08 +00:00
if (SOCKET_FAILED(sock)) {
2014-02-04 07:01:26 +00:00
return sock;
}
2015-01-09 10:03:42 +00:00
int err;
2022-09-22 03:22:14 +00:00
const int enable = 1;
#ifdef GEKKO
err = net_setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(enable));
2022-09-22 03:22:14 +00:00
#elif defined(_WIN32)
err = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const char*) &enable, sizeof(enable));
#else
err = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(enable));
#endif
if (err) {
2023-03-03 04:28:48 +00:00
SocketCloseQuiet(sock);
return INVALID_SOCKET;
}
2015-01-09 10:03:42 +00:00
if (!bindAddress) {
struct sockaddr_in bindInfo;
memset(&bindInfo, 0, sizeof(bindInfo));
bindInfo.sin_family = AF_INET;
bindInfo.sin_port = htons(port);
2022-02-15 04:41:44 +00:00
#ifndef __3DS__
2016-03-02 06:01:54 +00:00
bindInfo.sin_addr.s_addr = INADDR_ANY;
#else
bindInfo.sin_addr.s_addr = gethostid();
#endif
2020-02-09 01:46:56 +00:00
#ifdef GEKKO
err = net_bind(sock, (struct sockaddr*) &bindInfo, sizeof(bindInfo));
#else
2015-01-09 10:03:42 +00:00
err = bind(sock, (const struct sockaddr*) &bindInfo, sizeof(bindInfo));
2020-02-09 01:46:56 +00:00
#endif
2022-08-08 04:31:42 +00:00
} else if (!useIPv6) {
2015-01-09 10:03:42 +00:00
struct sockaddr_in bindInfo;
memset(&bindInfo, 0, sizeof(bindInfo));
bindInfo.sin_family = AF_INET;
bindInfo.sin_port = htons(port);
2016-04-28 05:17:21 +00:00
bindInfo.sin_addr.s_addr = htonl(bindAddress->ipv4);
2020-02-09 01:46:56 +00:00
#ifdef GEKKO
err = net_bind(sock, (struct sockaddr*) &bindInfo, sizeof(bindInfo));
#else
2015-01-09 10:03:42 +00:00
err = bind(sock, (const struct sockaddr*) &bindInfo, sizeof(bindInfo));
2020-02-09 01:46:56 +00:00
#endif
2022-02-15 04:41:44 +00:00
#if !defined(__3DS__) && !defined(GEKKO)
2015-01-09 10:03:42 +00:00
} else {
struct sockaddr_in6 bindInfo;
memset(&bindInfo, 0, sizeof(bindInfo));
bindInfo.sin6_family = AF_INET6;
bindInfo.sin6_port = htons(port);
memcpy(bindInfo.sin6_addr.s6_addr, bindAddress->ipv6, sizeof(bindInfo.sin6_addr.s6_addr));
err = bind(sock, (const struct sockaddr*) &bindInfo, sizeof(bindInfo));
2016-03-02 06:01:54 +00:00
#endif
2015-01-09 10:03:42 +00:00
}
2014-02-04 07:01:26 +00:00
if (err) {
2022-08-08 04:31:42 +00:00
SocketCloseQuiet(sock);
2015-02-24 07:27:28 +00:00
return INVALID_SOCKET;
2014-02-04 07:01:26 +00:00
}
return sock;
}
2015-01-09 10:03:42 +00:00
static inline Socket SocketConnectTCP(int port, const struct Address* destinationAddress) {
2022-08-08 04:31:42 +00:00
bool useIPv6 = destinationAddress && (destinationAddress->version == IPV6);
Socket sock = SocketCreate(useIPv6, IPPROTO_TCP);
2014-04-24 04:42:08 +00:00
if (SOCKET_FAILED(sock)) {
return sock;
}
2015-01-09 10:03:42 +00:00
int err;
if (!destinationAddress) {
struct sockaddr_in bindInfo;
memset(&bindInfo, 0, sizeof(bindInfo));
bindInfo.sin_family = AF_INET;
bindInfo.sin_port = htons(port);
2020-02-09 01:46:56 +00:00
#ifdef GEKKO
err = net_connect(sock, (struct sockaddr*) &bindInfo, sizeof(bindInfo));
#else
2015-01-09 10:03:42 +00:00
err = connect(sock, (const struct sockaddr*) &bindInfo, sizeof(bindInfo));
2020-02-09 01:46:56 +00:00
#endif
2015-01-09 10:03:42 +00:00
} else if (destinationAddress->version == IPV4) {
struct sockaddr_in bindInfo;
memset(&bindInfo, 0, sizeof(bindInfo));
bindInfo.sin_family = AF_INET;
bindInfo.sin_port = htons(port);
2016-04-28 05:17:21 +00:00
bindInfo.sin_addr.s_addr = htonl(destinationAddress->ipv4);
2020-02-09 01:46:56 +00:00
#ifdef GEKKO
err = net_connect(sock, (struct sockaddr*) &bindInfo, sizeof(bindInfo));
#else
2015-01-09 10:03:42 +00:00
err = connect(sock, (const struct sockaddr*) &bindInfo, sizeof(bindInfo));
2020-02-09 01:46:56 +00:00
#endif
2022-08-08 04:31:42 +00:00
#ifdef HAS_IPV6
2015-01-09 10:03:42 +00:00
} else {
struct sockaddr_in6 bindInfo;
memset(&bindInfo, 0, sizeof(bindInfo));
bindInfo.sin6_family = AF_INET6;
bindInfo.sin6_port = htons(port);
memcpy(bindInfo.sin6_addr.s6_addr, destinationAddress->ipv6, sizeof(bindInfo.sin6_addr.s6_addr));
err = connect(sock, (const struct sockaddr*) &bindInfo, sizeof(bindInfo));
2016-03-02 06:01:54 +00:00
#endif
2015-01-09 10:03:42 +00:00
}
if (err) {
2022-08-08 04:31:42 +00:00
SocketCloseQuiet(sock);
2015-02-24 07:27:28 +00:00
return INVALID_SOCKET;
}
return sock;
}
2014-02-05 09:22:34 +00:00
static inline Socket SocketListen(Socket socket, int queueLength) {
2020-02-09 01:46:56 +00:00
#ifdef GEKKO
return net_listen(socket, queueLength);
#else
2020-08-19 01:41:51 +00:00
#ifdef PSP2
if (queueLength <= 0) {
queueLength = 1;
}
#endif
2014-02-04 07:01:26 +00:00
return listen(socket, queueLength);
2020-02-09 01:46:56 +00:00
#endif
2014-02-04 07:01:26 +00:00
}
2015-01-09 10:03:42 +00:00
static inline Socket SocketAccept(Socket socket, struct Address* address) {
if (!address) {
2020-02-09 01:46:56 +00:00
#ifdef GEKKO
struct sockaddr_in addrInfo;
memset(&addrInfo, 0, sizeof(addrInfo));
socklen_t len = sizeof(addrInfo);
return net_accept(socket, (struct sockaddr*) &addrInfo, &len);
#else
2015-01-09 10:03:42 +00:00
return accept(socket, 0, 0);
2020-02-09 01:46:56 +00:00
#endif
2015-01-09 10:03:42 +00:00
}
if (address->version == IPV4) {
struct sockaddr_in addrInfo;
memset(&addrInfo, 0, sizeof(addrInfo));
addrInfo.sin_family = AF_INET;
addrInfo.sin_addr.s_addr = address->ipv4;
socklen_t len = sizeof(addrInfo);
2020-02-09 01:46:56 +00:00
#ifdef GEKKO
return net_accept(socket, (struct sockaddr*) &addrInfo, &len);
#else
2015-01-09 10:03:42 +00:00
return accept(socket, (struct sockaddr*) &addrInfo, &len);
2020-02-09 01:46:56 +00:00
#endif
2022-02-15 04:41:44 +00:00
#if !defined(__3DS__) && !defined(GEKKO)
2015-01-09 10:03:42 +00:00
} else {
struct sockaddr_in6 addrInfo;
memset(&addrInfo, 0, sizeof(addrInfo));
addrInfo.sin6_family = AF_INET6;
memcpy(addrInfo.sin6_addr.s6_addr, address->ipv6, sizeof(addrInfo.sin6_addr.s6_addr));
socklen_t len = sizeof(addrInfo);
return accept(socket, (struct sockaddr*) &addrInfo, &len);
2016-03-02 06:01:54 +00:00
#endif
2015-01-09 10:03:42 +00:00
}
2016-03-02 06:01:54 +00:00
return INVALID_SOCKET;
2014-02-04 07:01:26 +00:00
}
static inline int SocketSetBlocking(Socket socket, bool blocking) {
2014-02-04 07:01:26 +00:00
#ifdef _WIN32
2014-04-24 04:42:08 +00:00
u_long unblocking = !blocking;
return ioctlsocket(socket, FIONBIO, &unblocking) == NO_ERROR;
2020-02-09 01:46:56 +00:00
#else
#ifdef GEKKO
int flags = net_fcntl(socket, F_GETFL, 0);
2014-02-04 07:01:26 +00:00
#else
int flags = fcntl(socket, F_GETFL);
2020-02-09 01:46:56 +00:00
#endif
2014-02-04 07:01:26 +00:00
if (flags == -1) {
return 0;
}
if (blocking) {
flags &= ~O_NONBLOCK;
} else {
flags |= O_NONBLOCK;
}
2020-02-09 01:46:56 +00:00
#ifdef GEKKO
return net_fcntl(socket, F_SETFL, flags) >= 0;
#else
2014-02-04 07:01:26 +00:00
return fcntl(socket, F_SETFL, flags) >= 0;
#endif
2020-02-09 01:46:56 +00:00
#endif
2014-02-04 07:01:26 +00:00
}
static inline int SocketSetTCPPush(Socket socket, int push) {
2020-02-09 01:46:56 +00:00
#ifdef GEKKO
return net_setsockopt(socket, IPPROTO_TCP, TCP_NODELAY, (char*) &push, sizeof(int)) >= 0;
#else
return setsockopt(socket, IPPROTO_TCP, TCP_NODELAY, (char*) &push, sizeof(int)) >= 0;
2020-02-09 01:46:56 +00:00
#endif
}
static inline int SocketPoll(size_t nSockets, Socket* reads, Socket* writes, Socket* errors, int64_t timeoutMillis) {
fd_set rset;
fd_set wset;
fd_set eset;
FD_ZERO(&rset);
FD_ZERO(&wset);
FD_ZERO(&eset);
size_t i;
2015-02-15 07:40:59 +00:00
Socket maxFd = 0;
if (reads) {
for (i = 0; i < nSockets; ++i) {
if (SOCKET_FAILED(reads[i])) {
break;
}
if (reads[i] > maxFd) {
maxFd = reads[i];
}
FD_SET(reads[i], &rset);
reads[i] = INVALID_SOCKET;
}
}
if (writes) {
for (i = 0; i < nSockets; ++i) {
if (SOCKET_FAILED(writes[i])) {
break;
}
if (writes[i] > maxFd) {
maxFd = writes[i];
}
FD_SET(writes[i], &wset);
writes[i] = INVALID_SOCKET;
}
}
if (errors) {
for (i = 0; i < nSockets; ++i) {
if (SOCKET_FAILED(errors[i])) {
break;
}
if (errors[i] > maxFd) {
maxFd = errors[i];
}
FD_SET(errors[i], &eset);
errors[i] = INVALID_SOCKET;
}
}
++maxFd;
struct timeval tv;
tv.tv_sec = timeoutMillis / 1000;
tv.tv_usec = (timeoutMillis % 1000) * 1000;
2020-02-09 01:46:56 +00:00
#ifdef GEKKO
int result = net_select(maxFd, &rset, &wset, &eset, timeoutMillis < 0 ? 0 : &tv);
#else
int result = select(maxFd, &rset, &wset, &eset, timeoutMillis < 0 ? 0 : &tv);
2020-02-09 01:46:56 +00:00
#endif
size_t r = 0;
size_t w = 0;
size_t e = 0;
Socket j;
for (j = 0; j < maxFd; ++j) {
if (reads && FD_ISSET(j, &rset)) {
reads[r] = j;
++r;
}
if (writes && FD_ISSET(j, &wset)) {
writes[w] = j;
++w;
}
if (errors && FD_ISSET(j, &eset)) {
errors[e] = j;
++e;
}
}
if (reads) {
for (; r < nSockets; ++r) {
reads[r] = INVALID_SOCKET;
}
}
if (writes) {
for (; w < nSockets; ++w) {
writes[w] = INVALID_SOCKET;
}
}
if (errors) {
for (; e < nSockets; ++e) {
errors[e] = INVALID_SOCKET;
}
}
return result;
}
static inline int SocketResolveHost(const char* addrString, struct Address* destAddress) {
int result = 0;
#ifdef USE_GETHOSTBYNAME
#warning Using gethostbyname() for hostname resolution is not threadsafe
#ifdef GEKKO
struct hostent* host = net_gethostbyname(addrString);
#else
struct hostent* host = gethostbyname(addrString);
#endif
if (!host) {
return errno;
}
if (host->h_addrtype == AF_INET && host->h_length == 4) {
destAddress->version = IPV4;
destAddress->ipv4 = ntohl(*host->h_addr_list[0]);
2022-09-22 03:41:34 +00:00
}
#ifdef HAS_IPV6
else if (host->h_addrtype == AF_INET6 && host->h_length == 16) {
destAddress->version = IPV6;
memcpy(destAddress->ipv6, host->h_addr_list[0], 16);
2022-09-22 03:41:34 +00:00
}
#endif
else {
#ifdef GEKKO
result = errno;
#else
result = -h_errno;
#endif
}
#else
struct addrinfo* addr = NULL;
result = getaddrinfo(addrString, NULL, NULL, &addr);
if (result) {
2022-09-22 03:41:34 +00:00
#ifdef EAI_SYSTEM
if (result == EAI_SYSTEM) {
result = errno;
}
#endif
goto error;
}
if (addr->ai_family == AF_INET && addr->ai_addrlen == sizeof(struct sockaddr_in)) {
struct sockaddr_in* addr4 = (struct sockaddr_in*) addr->ai_addr;
destAddress->version = IPV4;
destAddress->ipv4 = ntohl(addr4->sin_addr.s_addr);
2022-09-22 03:41:34 +00:00
}
#ifdef HAS_IPV6
else if (addr->ai_family == AF_INET6 && addr->ai_addrlen == sizeof(struct sockaddr_in6)) {
struct sockaddr_in6* addr6 = (struct sockaddr_in6*) addr->ai_addr;
destAddress->version = IPV6;
memcpy(destAddress->ipv6, addr6->sin6_addr.s6_addr, 16);
2022-09-22 03:41:34 +00:00
}
#endif
else {
#ifdef _WIN32
result = WSANO_DATA;
#else
2022-09-22 03:41:34 +00:00
result = EAI_NONAME;
#endif
}
error:
if (addr) {
freeaddrinfo(addr);
}
#endif
return result;
}
2016-12-27 05:01:55 +00:00
CXX_GUARD_END
2014-02-04 07:01:26 +00:00
#endif