all repos — mgba @ 64bdb02eebb551c7e0b425656a046cca3d180777

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#ifdef PSP2
 68#include <psp2/net/net.h>
 69#include <psp2/sysmodule.h>
 70#endif
 71
 72static inline void SocketSubsystemInit() {
 73#ifdef _WIN32
 74	WSADATA data;
 75	WSAStartup(MAKEWORD(2, 2), &data);
 76#elif defined(_3DS)
 77	if (!SOCUBuffer) {
 78		SOCUBuffer = memalign(SOCU_ALIGN, SOCU_BUFFERSIZE);
 79		socInit(SOCUBuffer, SOCU_BUFFERSIZE);
 80	}
 81#elif defined(__SWITCH__)
 82	socketInitializeDefault();
 83#elif defined(GEKKO)
 84	net_init();
 85#elif defined(PSP2)
 86	static uint8_t netMem[1024*1024];
 87	sceSysmoduleLoadModule(SCE_SYSMODULE_NET);
 88	sceNetInit(&(SceNetInitParam) { netMem, sizeof(netMem) });
 89#endif
 90}
 91
 92static inline void SocketSubsystemDeinit() {
 93#ifdef _WIN32
 94	WSACleanup();
 95#elif defined(_3DS)
 96	socExit();
 97	free(SOCUBuffer);
 98	SOCUBuffer = NULL;
 99#elif defined(__SWITCH__)
100	socketExit();
101#elif defined(GEKKO)
102	net_deinit();
103#elif defined(PSP2)
104	sceNetTerm();
105	sceSysmoduleUnloadModule(SCE_SYSMODULE_NET);
106#endif
107}
108
109static inline int SocketError() {
110#ifdef _WIN32
111	return WSAGetLastError();
112#else
113	return errno;
114#endif
115}
116
117static inline bool SocketWouldBlock() {
118#ifdef _WIN32
119	return SocketError() == WSAEWOULDBLOCK;
120#else
121	return SocketError() == EWOULDBLOCK || SocketError() == EAGAIN;
122#endif
123}
124
125static inline ssize_t SocketSend(Socket socket, const void* buffer, size_t size) {
126#ifdef _WIN32
127	return send(socket, (const char*) buffer, size, 0);
128#elif defined(GEKKO)
129	return net_write(socket, buffer, size);
130#else
131	return write(socket, buffer, size);
132#endif
133}
134
135static inline ssize_t SocketRecv(Socket socket, void* buffer, size_t size) {
136#if defined(_WIN32) || defined(__SWITCH__)
137	return recv(socket, (char*) buffer, size, 0);
138#elif defined(GEKKO)
139	return net_read(socket, buffer, size);
140#else
141	return read(socket, buffer, size);
142#endif
143}
144
145static inline int SocketClose(Socket socket) {
146#ifdef _WIN32
147	return closesocket(socket) == 0;
148#elif defined(GEKKO)
149	return net_close(socket) >= 0;
150#else
151	return close(socket) >= 0;
152#endif
153}
154
155static inline Socket SocketOpenTCP(int port, const struct Address* bindAddress) {
156#ifdef GEKKO
157	Socket sock = net_socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
158#else
159	Socket sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
160#endif
161	if (SOCKET_FAILED(sock)) {
162		return sock;
163	}
164
165	int err;
166	if (!bindAddress) {
167		struct sockaddr_in bindInfo;
168		memset(&bindInfo, 0, sizeof(bindInfo));
169		bindInfo.sin_family = AF_INET;
170		bindInfo.sin_port = htons(port);
171#ifndef _3DS
172		bindInfo.sin_addr.s_addr = INADDR_ANY;
173#else
174		bindInfo.sin_addr.s_addr = gethostid();
175#endif
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	} else if (bindAddress->version == IPV4) {
182		struct sockaddr_in bindInfo;
183		memset(&bindInfo, 0, sizeof(bindInfo));
184		bindInfo.sin_family = AF_INET;
185		bindInfo.sin_port = htons(port);
186		bindInfo.sin_addr.s_addr = htonl(bindAddress->ipv4);
187#ifdef GEKKO
188		err = net_bind(sock, (struct sockaddr*) &bindInfo, sizeof(bindInfo));
189#else
190		err = bind(sock, (const struct sockaddr*) &bindInfo, sizeof(bindInfo));
191#endif
192#if !defined(_3DS) && !defined(GEKKO)
193	} else {
194		struct sockaddr_in6 bindInfo;
195		memset(&bindInfo, 0, sizeof(bindInfo));
196		bindInfo.sin6_family = AF_INET6;
197		bindInfo.sin6_port = htons(port);
198		memcpy(bindInfo.sin6_addr.s6_addr, bindAddress->ipv6, sizeof(bindInfo.sin6_addr.s6_addr));
199		err = bind(sock, (const struct sockaddr*) &bindInfo, sizeof(bindInfo));
200#endif
201	}
202	if (err) {
203		SocketClose(sock);
204		return INVALID_SOCKET;
205	}
206	return sock;
207}
208
209static inline Socket SocketConnectTCP(int port, const struct Address* destinationAddress) {
210#ifdef GEKKO
211	Socket sock = net_socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
212#else
213	Socket sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
214#endif
215	if (SOCKET_FAILED(sock)) {
216		return sock;
217	}
218
219	int err;
220	if (!destinationAddress) {
221		struct sockaddr_in bindInfo;
222		memset(&bindInfo, 0, sizeof(bindInfo));
223		bindInfo.sin_family = AF_INET;
224		bindInfo.sin_port = htons(port);
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	} else if (destinationAddress->version == IPV4) {
231		struct sockaddr_in bindInfo;
232		memset(&bindInfo, 0, sizeof(bindInfo));
233		bindInfo.sin_family = AF_INET;
234		bindInfo.sin_port = htons(port);
235		bindInfo.sin_addr.s_addr = htonl(destinationAddress->ipv4);
236#ifdef GEKKO
237		err = net_connect(sock, (struct sockaddr*) &bindInfo, sizeof(bindInfo));
238#else
239		err = connect(sock, (const struct sockaddr*) &bindInfo, sizeof(bindInfo));
240#endif
241#if !defined(_3DS) && !defined(GEKKO)
242	} else {
243		struct sockaddr_in6 bindInfo;
244		memset(&bindInfo, 0, sizeof(bindInfo));
245		bindInfo.sin6_family = AF_INET6;
246		bindInfo.sin6_port = htons(port);
247		memcpy(bindInfo.sin6_addr.s6_addr, destinationAddress->ipv6, sizeof(bindInfo.sin6_addr.s6_addr));
248		err = connect(sock, (const struct sockaddr*) &bindInfo, sizeof(bindInfo));
249#endif
250	}
251
252	if (err) {
253		SocketClose(sock);
254		return INVALID_SOCKET;
255	}
256	return sock;
257}
258
259static inline Socket SocketListen(Socket socket, int queueLength) {
260#ifdef GEKKO
261	return net_listen(socket, queueLength);
262#else
263#ifdef PSP2
264	if (queueLength <= 0) {
265		queueLength = 1;
266	}
267#endif
268	return listen(socket, queueLength);
269#endif
270}
271
272static inline Socket SocketAccept(Socket socket, struct Address* address) {
273	if (!address) {
274#ifdef GEKKO
275		struct sockaddr_in addrInfo;
276		memset(&addrInfo, 0, sizeof(addrInfo));
277		socklen_t len = sizeof(addrInfo);
278		return net_accept(socket, (struct sockaddr*) &addrInfo, &len);
279#else
280		return accept(socket, 0, 0);
281#endif
282	}
283	if (address->version == IPV4) {
284		struct sockaddr_in addrInfo;
285		memset(&addrInfo, 0, sizeof(addrInfo));
286		addrInfo.sin_family = AF_INET;
287		addrInfo.sin_addr.s_addr = address->ipv4;
288		socklen_t len = sizeof(addrInfo);
289#ifdef GEKKO
290		return net_accept(socket, (struct sockaddr*) &addrInfo, &len);
291#else
292		return accept(socket, (struct sockaddr*) &addrInfo, &len);
293#endif
294#if !defined(_3DS) && !defined(GEKKO)
295	} else {
296		struct sockaddr_in6 addrInfo;
297		memset(&addrInfo, 0, sizeof(addrInfo));
298		addrInfo.sin6_family = AF_INET6;
299		memcpy(addrInfo.sin6_addr.s6_addr, address->ipv6, sizeof(addrInfo.sin6_addr.s6_addr));
300		socklen_t len = sizeof(addrInfo);
301		return accept(socket, (struct sockaddr*) &addrInfo, &len);
302#endif
303	}
304	return INVALID_SOCKET;
305}
306
307static inline int SocketSetBlocking(Socket socket, bool blocking) {
308#ifdef _WIN32
309	u_long unblocking = !blocking;
310	return ioctlsocket(socket, FIONBIO, &unblocking) == NO_ERROR;
311#else
312#ifdef GEKKO
313	int flags = net_fcntl(socket, F_GETFL, 0);
314#else
315	int flags = fcntl(socket, F_GETFL);
316#endif
317	if (flags == -1) {
318		return 0;
319	}
320	if (blocking) {
321		flags &= ~O_NONBLOCK;
322	} else {
323		flags |= O_NONBLOCK;
324	}
325#ifdef GEKKO
326	return net_fcntl(socket, F_SETFL, flags) >= 0;
327#else
328	return fcntl(socket, F_SETFL, flags) >= 0;
329#endif
330#endif
331}
332
333static inline int SocketSetTCPPush(Socket socket, int push) {
334#ifdef GEKKO
335	return net_setsockopt(socket, IPPROTO_TCP, TCP_NODELAY, (char*) &push, sizeof(int)) >= 0;
336#else
337	return setsockopt(socket, IPPROTO_TCP, TCP_NODELAY, (char*) &push, sizeof(int)) >= 0;
338#endif
339}
340
341static inline int SocketPoll(size_t nSockets, Socket* reads, Socket* writes, Socket* errors, int64_t timeoutMillis) {
342	fd_set rset;
343	fd_set wset;
344	fd_set eset;
345	FD_ZERO(&rset);
346	FD_ZERO(&wset);
347	FD_ZERO(&eset);
348	size_t i;
349	Socket maxFd = 0;
350	if (reads) {
351		for (i = 0; i < nSockets; ++i) {
352			if (SOCKET_FAILED(reads[i])) {
353				break;
354			}
355			if (reads[i] > maxFd) {
356				maxFd = reads[i];
357			}
358			FD_SET(reads[i], &rset);
359			reads[i] = INVALID_SOCKET;
360		}
361	}
362	if (writes) {
363		for (i = 0; i < nSockets; ++i) {
364			if (SOCKET_FAILED(writes[i])) {
365				break;
366			}
367			if (writes[i] > maxFd) {
368				maxFd = writes[i];
369			}
370			FD_SET(writes[i], &wset);
371			writes[i] = INVALID_SOCKET;
372		}
373	}
374	if (errors) {
375		for (i = 0; i < nSockets; ++i) {
376			if (SOCKET_FAILED(errors[i])) {
377				break;
378			}
379			if (errors[i] > maxFd) {
380				maxFd = errors[i];
381			}
382			FD_SET(errors[i], &eset);
383			errors[i] = INVALID_SOCKET;
384		}
385	}
386	++maxFd;
387	struct timeval tv;
388	tv.tv_sec = timeoutMillis / 1000;
389	tv.tv_usec = (timeoutMillis % 1000) * 1000;
390#ifdef GEKKO
391	int result = net_select(maxFd, &rset, &wset, &eset, timeoutMillis < 0 ? 0 : &tv);
392#else
393	int result = select(maxFd, &rset, &wset, &eset, timeoutMillis < 0 ? 0 : &tv);
394#endif
395	int r = 0;
396	int w = 0;
397	int e = 0;
398	Socket j;
399	for (j = 0; j < maxFd; ++j) {
400		if (reads && FD_ISSET(j, &rset)) {
401			reads[r] = j;
402			++r;
403		}
404		if (writes && FD_ISSET(j, &wset)) {
405			writes[w] = j;
406			++w;
407		}
408		if (errors && FD_ISSET(j, &eset)) {
409			errors[e] = j;
410			++e;
411		}
412	}
413	return result;
414}
415
416CXX_GUARD_END
417
418#endif