all repos — mgba @ 4f327de2102f47e2641dca2cda94688058497866

mGBA Game Boy Advance Emulator

include/mgba-util/socket.h (view raw)

  1/* Copyright (c) 2013-2014 Jeffrey Pfau
  2 *
  3 * This Source Code Form is subject to the terms of the Mozilla Public
  4 * License, v. 2.0. If a copy of the MPL was not distributed with this
  5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  6#ifndef SOCKET_H
  7#define SOCKET_H
  8
  9#include <mgba-util/common.h>
 10
 11CXX_GUARD_START
 12
 13#if defined(__cplusplus) && !defined(restrict)
 14#define restrict __restrict__
 15#endif
 16
 17#ifdef _WIN32
 18#include <ws2tcpip.h>
 19
 20#define SOCKET_FAILED(s) ((s) == INVALID_SOCKET)
 21typedef SOCKET Socket;
 22#else
 23#ifdef GEKKO
 24#include <network.h>
 25#else
 26#include <arpa/inet.h>
 27#include <netinet/in.h>
 28#include <netinet/tcp.h>
 29#include <sys/socket.h>
 30#endif
 31#include <errno.h>
 32#include <fcntl.h>
 33#include <sys/select.h>
 34
 35#ifndef GEKKO
 36#define INVALID_SOCKET (-1)
 37#endif
 38#define SOCKET_FAILED(s) ((s) < 0)
 39typedef int Socket;
 40#endif
 41
 42enum IP {
 43	IPV4,
 44	IPV6
 45};
 46
 47struct Address {
 48	enum IP version;
 49	union {
 50		uint32_t ipv4;
 51		uint8_t ipv6[16];
 52	};
 53};
 54
 55#ifdef _3DS
 56#include <3ds.h>
 57#include <malloc.h>
 58
 59#define SOCU_ALIGN 0x1000
 60#define SOCU_BUFFERSIZE 0x100000
 61
 62extern u32* SOCUBuffer;
 63#endif
 64#ifdef __SWITCH__
 65#include <switch.h>
 66#endif
 67
 68static inline void SocketSubsystemInit() {
 69#ifdef _WIN32
 70	WSADATA data;
 71	WSAStartup(MAKEWORD(2, 2), &data);
 72#elif defined(_3DS)
 73	if (!SOCUBuffer) {
 74		SOCUBuffer = memalign(SOCU_ALIGN, SOCU_BUFFERSIZE);
 75		socInit(SOCUBuffer, SOCU_BUFFERSIZE);
 76	}
 77#elif defined(__SWITCH__)
 78	socketInitializeDefault();
 79#elif defined(GEKKO)
 80	net_init();
 81#endif
 82}
 83
 84static inline void SocketSubsystemDeinit() {
 85#ifdef _WIN32
 86	WSACleanup();
 87#elif defined(_3DS)
 88	socExit();
 89	free(SOCUBuffer);
 90	SOCUBuffer = NULL;
 91#elif defined(__SWITCH__)
 92	socketExit();
 93#elif defined(GEKKO)
 94	net_deinit();
 95#endif
 96}
 97
 98static inline int SocketError() {
 99#ifdef _WIN32
100	return WSAGetLastError();
101#else
102	return errno;
103#endif
104}
105
106static inline bool SocketWouldBlock() {
107#ifdef _WIN32
108	return SocketError() == WSAEWOULDBLOCK;
109#else
110	return SocketError() == EWOULDBLOCK || SocketError() == EAGAIN;
111#endif
112}
113
114static inline ssize_t SocketSend(Socket socket, const void* buffer, size_t size) {
115#ifdef _WIN32
116	return send(socket, (const char*) buffer, size, 0);
117#elif defined(GEKKO)
118	return net_write(socket, buffer, size);
119#else
120	return write(socket, buffer, size);
121#endif
122}
123
124static inline ssize_t SocketRecv(Socket socket, void* buffer, size_t size) {
125#if defined(_WIN32) || defined(__SWITCH__)
126	return recv(socket, (char*) buffer, size, 0);
127#elif defined(GEKKO)
128	return net_read(socket, buffer, size);
129#else
130	return read(socket, buffer, size);
131#endif
132}
133
134static inline int SocketClose(Socket socket) {
135#ifdef _WIN32
136	return closesocket(socket) == 0;
137#elif defined(GEKKO)
138	return net_close(socket) >= 0;
139#else
140	return close(socket) >= 0;
141#endif
142}
143
144static inline Socket SocketOpenTCP(int port, const struct Address* bindAddress) {
145#ifdef GEKKO
146	Socket sock = net_socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
147#else
148	Socket sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
149#endif
150	if (SOCKET_FAILED(sock)) {
151		return sock;
152	}
153
154	int err;
155	if (!bindAddress) {
156		struct sockaddr_in bindInfo;
157		memset(&bindInfo, 0, sizeof(bindInfo));
158		bindInfo.sin_family = AF_INET;
159		bindInfo.sin_port = htons(port);
160#ifndef _3DS
161		bindInfo.sin_addr.s_addr = INADDR_ANY;
162#else
163		bindInfo.sin_addr.s_addr = gethostid();
164#endif
165#ifdef GEKKO
166		err = net_bind(sock, (struct sockaddr*) &bindInfo, sizeof(bindInfo));
167#else
168		err = bind(sock, (const struct sockaddr*) &bindInfo, sizeof(bindInfo));
169#endif
170	} else if (bindAddress->version == IPV4) {
171		struct sockaddr_in bindInfo;
172		memset(&bindInfo, 0, sizeof(bindInfo));
173		bindInfo.sin_family = AF_INET;
174		bindInfo.sin_port = htons(port);
175		bindInfo.sin_addr.s_addr = htonl(bindAddress->ipv4);
176#ifdef GEKKO
177		err = net_bind(sock, (struct sockaddr*) &bindInfo, sizeof(bindInfo));
178#else
179		err = bind(sock, (const struct sockaddr*) &bindInfo, sizeof(bindInfo));
180#endif
181#if !defined(_3DS) && !defined(GEKKO)
182	} else {
183		struct sockaddr_in6 bindInfo;
184		memset(&bindInfo, 0, sizeof(bindInfo));
185		bindInfo.sin6_family = AF_INET6;
186		bindInfo.sin6_port = htons(port);
187		memcpy(bindInfo.sin6_addr.s6_addr, bindAddress->ipv6, sizeof(bindInfo.sin6_addr.s6_addr));
188		err = bind(sock, (const struct sockaddr*) &bindInfo, sizeof(bindInfo));
189#endif
190	}
191	if (err) {
192		SocketClose(sock);
193		return INVALID_SOCKET;
194	}
195	return sock;
196}
197
198static inline Socket SocketConnectTCP(int port, const struct Address* destinationAddress) {
199#ifdef GEKKO
200	Socket sock = net_socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
201#else
202	Socket sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
203#endif
204	if (SOCKET_FAILED(sock)) {
205		return sock;
206	}
207
208	int err;
209	if (!destinationAddress) {
210		struct sockaddr_in bindInfo;
211		memset(&bindInfo, 0, sizeof(bindInfo));
212		bindInfo.sin_family = AF_INET;
213		bindInfo.sin_port = htons(port);
214#ifdef GEKKO
215		err = net_connect(sock, (struct sockaddr*) &bindInfo, sizeof(bindInfo));
216#else
217		err = connect(sock, (const struct sockaddr*) &bindInfo, sizeof(bindInfo));
218#endif
219	} else if (destinationAddress->version == IPV4) {
220		struct sockaddr_in bindInfo;
221		memset(&bindInfo, 0, sizeof(bindInfo));
222		bindInfo.sin_family = AF_INET;
223		bindInfo.sin_port = htons(port);
224		bindInfo.sin_addr.s_addr = htonl(destinationAddress->ipv4);
225#ifdef GEKKO
226		err = net_connect(sock, (struct sockaddr*) &bindInfo, sizeof(bindInfo));
227#else
228		err = connect(sock, (const struct sockaddr*) &bindInfo, sizeof(bindInfo));
229#endif
230#if !defined(_3DS) && !defined(GEKKO)
231	} else {
232		struct sockaddr_in6 bindInfo;
233		memset(&bindInfo, 0, sizeof(bindInfo));
234		bindInfo.sin6_family = AF_INET6;
235		bindInfo.sin6_port = htons(port);
236		memcpy(bindInfo.sin6_addr.s6_addr, destinationAddress->ipv6, sizeof(bindInfo.sin6_addr.s6_addr));
237		err = connect(sock, (const struct sockaddr*) &bindInfo, sizeof(bindInfo));
238#endif
239	}
240
241	if (err) {
242		SocketClose(sock);
243		return INVALID_SOCKET;
244	}
245	return sock;
246}
247
248static inline Socket SocketListen(Socket socket, int queueLength) {
249#ifdef GEKKO
250	return net_listen(socket, queueLength);
251#else
252	return listen(socket, queueLength);
253#endif
254}
255
256static inline Socket SocketAccept(Socket socket, struct Address* address) {
257	if (!address) {
258#ifdef GEKKO
259		struct sockaddr_in addrInfo;
260		memset(&addrInfo, 0, sizeof(addrInfo));
261		socklen_t len = sizeof(addrInfo);
262		return net_accept(socket, (struct sockaddr*) &addrInfo, &len);
263#else
264		return accept(socket, 0, 0);
265#endif
266	}
267	if (address->version == IPV4) {
268		struct sockaddr_in addrInfo;
269		memset(&addrInfo, 0, sizeof(addrInfo));
270		addrInfo.sin_family = AF_INET;
271		addrInfo.sin_addr.s_addr = address->ipv4;
272		socklen_t len = sizeof(addrInfo);
273#ifdef GEKKO
274		return net_accept(socket, (struct sockaddr*) &addrInfo, &len);
275#else
276		return accept(socket, (struct sockaddr*) &addrInfo, &len);
277#endif
278#if !defined(_3DS) && !defined(GEKKO)
279	} else {
280		struct sockaddr_in6 addrInfo;
281		memset(&addrInfo, 0, sizeof(addrInfo));
282		addrInfo.sin6_family = AF_INET6;
283		memcpy(addrInfo.sin6_addr.s6_addr, address->ipv6, sizeof(addrInfo.sin6_addr.s6_addr));
284		socklen_t len = sizeof(addrInfo);
285		return accept(socket, (struct sockaddr*) &addrInfo, &len);
286#endif
287	}
288	return INVALID_SOCKET;
289}
290
291static inline int SocketSetBlocking(Socket socket, bool blocking) {
292#ifdef _WIN32
293	u_long unblocking = !blocking;
294	return ioctlsocket(socket, FIONBIO, &unblocking) == NO_ERROR;
295#else
296#ifdef GEKKO
297	int flags = net_fcntl(socket, F_GETFL, 0);
298#else
299	int flags = fcntl(socket, F_GETFL);
300#endif
301	if (flags == -1) {
302		return 0;
303	}
304	if (blocking) {
305		flags &= ~O_NONBLOCK;
306	} else {
307		flags |= O_NONBLOCK;
308	}
309#ifdef GEKKO
310	return net_fcntl(socket, F_SETFL, flags) >= 0;
311#else
312	return fcntl(socket, F_SETFL, flags) >= 0;
313#endif
314#endif
315}
316
317static inline int SocketSetTCPPush(Socket socket, int push) {
318#ifdef GEKKO
319	return net_setsockopt(socket, IPPROTO_TCP, TCP_NODELAY, (char*) &push, sizeof(int)) >= 0;
320#else
321	return setsockopt(socket, IPPROTO_TCP, TCP_NODELAY, (char*) &push, sizeof(int)) >= 0;
322#endif
323}
324
325static inline int SocketPoll(size_t nSockets, Socket* reads, Socket* writes, Socket* errors, int64_t timeoutMillis) {
326	fd_set rset;
327	fd_set wset;
328	fd_set eset;
329	FD_ZERO(&rset);
330	FD_ZERO(&wset);
331	FD_ZERO(&eset);
332	size_t i;
333	Socket maxFd = 0;
334	if (reads) {
335		for (i = 0; i < nSockets; ++i) {
336			if (SOCKET_FAILED(reads[i])) {
337				break;
338			}
339			if (reads[i] > maxFd) {
340				maxFd = reads[i];
341			}
342			FD_SET(reads[i], &rset);
343			reads[i] = INVALID_SOCKET;
344		}
345	}
346	if (writes) {
347		for (i = 0; i < nSockets; ++i) {
348			if (SOCKET_FAILED(writes[i])) {
349				break;
350			}
351			if (writes[i] > maxFd) {
352				maxFd = writes[i];
353			}
354			FD_SET(writes[i], &wset);
355			writes[i] = INVALID_SOCKET;
356		}
357	}
358	if (errors) {
359		for (i = 0; i < nSockets; ++i) {
360			if (SOCKET_FAILED(errors[i])) {
361				break;
362			}
363			if (errors[i] > maxFd) {
364				maxFd = errors[i];
365			}
366			FD_SET(errors[i], &eset);
367			errors[i] = INVALID_SOCKET;
368		}
369	}
370	++maxFd;
371	struct timeval tv;
372	tv.tv_sec = timeoutMillis / 1000;
373	tv.tv_usec = (timeoutMillis % 1000) * 1000;
374#ifdef GEKKO
375	int result = net_select(maxFd, &rset, &wset, &eset, timeoutMillis < 0 ? 0 : &tv);
376#else
377	int result = select(maxFd, &rset, &wset, &eset, timeoutMillis < 0 ? 0 : &tv);
378#endif
379	int r = 0;
380	int w = 0;
381	int e = 0;
382	Socket j;
383	for (j = 0; j < maxFd; ++j) {
384		if (reads && FD_ISSET(j, &rset)) {
385			reads[r] = j;
386			++r;
387		}
388		if (writes && FD_ISSET(j, &wset)) {
389			writes[w] = j;
390			++w;
391		}
392		if (errors && FD_ISSET(j, &eset)) {
393			errors[e] = j;
394			++e;
395		}
396	}
397	return result;
398}
399
400CXX_GUARD_END
401
402#endif