1 /**
2  * @file
3  * @note This file should fully support ipv6 and any other protocol that is
4  * compatible with the getaddrinfo interface, with the exception of
5  * NET_DatagramBroadcast() which must be amended for each protocol (and
6  * currently supports only ipv4)
7  */
8 
9 /*
10 Copyright (C) 2002-2013 UFO: Alien Invasion.
11 
12 This program is free software; you can redistribute it and/or
13 modify it under the terms of the GNU General Public License
14 as published by the Free Software Foundation; either version 2
15 of the License, or (at your option) any later version.
16 
17 This program is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
20 
21 See the GNU General Public License for more details.
22 
23 You should have received a copy of the GNU General Public License
24 along with this program; if not, write to the Free Software
25 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
26 
27 */
28 
29 #include "common.h"
30 #include <errno.h>
31 #include <string.h>
32 #include <fcntl.h>
33 #include <unistd.h>
34 #include <SDL_thread.h>
35 #ifdef _WIN32
36 #include "../ports/system.h"
37 #endif
38 #include "../shared/scopedmutex.h"
39 
40 #define MAX_STREAMS 56
41 #define MAX_DATAGRAM_SOCKETS 7
42 
43 #ifdef _WIN32
44 # include <winsock2.h>
45 # include <ws2tcpip.h>
46 # if WINVER < 0x501
47 #  include <wspiapi.h>
48 # else
49 #  include <ws2spi.h>
50 # endif
51 # define netError WSAGetLastError()
52 # define netStringError netStringErrorWin
53 # define netCloseSocket closesocket
54 # define gai_strerrorA netStringErrorWin
55 
56 #else /* WIN32 */
57 
58 # include <sys/ioctl.h>
59 # include <sys/select.h>
60 # include <sys/types.h>
61 # include <sys/socket.h>
62 # include <sys/time.h>
63 # include <netdb.h>
64 # include <arpa/inet.h>
65 # include <netinet/in.h>
66 # include <signal.h>
67 typedef int SOCKET;
68 # define INVALID_SOCKET (-1)
69 # define netError errno
70 # define netStringError strerror
71 # define netCloseSocket close
72 # define ioctlsocket ioctl
73 #endif /* WIN32 */
74 
75 #ifdef EMSCRIPTEN
76 #define NI_NUMERICHOST 0
77 #define NI_NUMERICSERV 0
78 #define NI_DGRAM 0
79 #define AI_PASSIVE 0
80 #define AI_NUMERICHOST 0
81 #define INADDR_BROADCAST 0
82 #endif
83 
84 /**
85  * @todo Move this into the configure script
86  * AI_ADDRCONFIG, AI_ALL, and AI_V4MAPPED are available since glibc 2.3.3.
87  * AI_NUMERICSERV is available since glibc 2.3.4.
88  */
89 #ifndef AI_NUMERICSERV
90 #define AI_NUMERICSERV 0
91 #endif
92 #ifndef AI_ADDRCONFIG
93 #define AI_ADDRCONFIG 0
94 #endif
95 
96 /**
97  * @brief use an admin local address per default so that
98  * network admins can decide on how to handle traffic.
99  */
100 #define NET_MULTICAST_IP6 "ff04::696f:7175:616b:6533"
101 
102 #define dbuffer_len(dbuf) (dbuf ? (dbuf)->length() : 0)
103 
104 static cvar_t* net_ipv4;
105 static SDL_mutex *netMutex;
106 
107 struct net_stream {
108 	void* data;
109 
110 	bool loopback;
111 	bool ready;
112 	bool closed;
113 	bool finished;		/**< finished but maybe not yet closed */
114 	SOCKET socket;
115 	int index;
116 	int family;
117 	int addrlen;
118 
119 	/* these buffers must be used in a thread safe manner
120 	 * (lock netMutex) because the game thread can also write to it */
121 	dbufferptr inbound;
122 	dbufferptr outbound;
123 
124 	stream_onclose_func* onclose;
125 	stream_callback_func* func;
126 	struct net_stream *loopback_peer;
127 };
128 
129 struct datagram {
130 	int len;
131 	char* msg;
132 	char* addr;
133 	struct datagram *next;
134 };
135 
136 struct datagram_socket {
137 	SOCKET socket;
138 	int index;
139 	int family;
140 	int addrlen;
141 	struct datagram *queue;
142 	struct datagram **queue_tail;
143 	datagram_callback_func *func;
144 };
145 
146 static fd_set read_fds;
147 static fd_set write_fds;
148 static SOCKET maxfd;
149 static struct net_stream *streams[MAX_STREAMS];
150 static struct datagram_socket* datagram_sockets[MAX_DATAGRAM_SOCKETS];
151 
152 static bool loopback_ready = false;
153 static bool server_running = false;
154 static stream_callback_func* server_func = nullptr;
155 static SOCKET server_socket = INVALID_SOCKET;
156 static int server_family, server_addrlen;
157 
158 #ifdef _WIN32
netStringErrorWin(int code)159 static const char* netStringErrorWin (int code)
160 {
161 	switch (code) {
162 	case WSAEINTR: return "WSAEINTR";
163 	case WSAEBADF: return "WSAEBADF";
164 	case WSAEACCES: return "WSAEACCES";
165 	case WSAEDISCON: return "WSAEDISCON";
166 	case WSAEFAULT: return "WSAEFAULT";
167 	case WSAEINVAL: return "WSAEINVAL";
168 	case WSAEMFILE: return "WSAEMFILE";
169 	case WSAEWOULDBLOCK: return "WSAEWOULDBLOCK";
170 	case WSAEINPROGRESS: return "WSAEINPROGRESS";
171 	case WSAEALREADY: return "WSAEALREADY";
172 	case WSAENOTSOCK: return "WSAENOTSOCK";
173 	case WSAEDESTADDRREQ: return "WSAEDESTADDRREQ";
174 	case WSAEMSGSIZE: return "WSAEMSGSIZE";
175 	case WSAEPROTOTYPE: return "WSAEPROTOTYPE";
176 	case WSAENOPROTOOPT: return "WSAENOPROTOOPT";
177 	case WSAEPROTONOSUPPORT: return "WSAEPROTONOSUPPORT";
178 	case WSAESOCKTNOSUPPORT: return "WSAESOCKTNOSUPPORT";
179 	case WSAEOPNOTSUPP: return "WSAEOPNOTSUPP";
180 	case WSAEPFNOSUPPORT: return "WSAEPFNOSUPPORT";
181 	case WSAEAFNOSUPPORT: return "WSAEAFNOSUPPORT";
182 	case WSAEADDRINUSE: return "WSAEADDRINUSE";
183 	case WSAEADDRNOTAVAIL: return "WSAEADDRNOTAVAIL";
184 	case WSAENETDOWN: return "WSAENETDOWN";
185 	case WSAENETUNREACH: return "WSAENETUNREACH";
186 	case WSAENETRESET: return "WSAENETRESET";
187 	case WSAEHOSTDOWN: return "WSAEHOSTDOWN";
188 	case WSAEHOSTUNREACH: return "WSAEHOSTUNREACH";
189 	case WSAECONNABORTED: return "WSWSAECONNABORTEDAEINTR";
190 	case WSAECONNRESET: return "WSAECONNRESET";
191 	case WSAENOBUFS: return "WSAENOBUFS";
192 	case WSAEISCONN: return "WSAEISCONN";
193 	case WSAENOTCONN: return "WSAENOTCONN";
194 	case WSAESHUTDOWN: return "WSAESHUTDOWN";
195 	case WSAETOOMANYREFS: return "WSAETOOMANYREFS";
196 	case WSAETIMEDOUT: return "WSAETIMEDOUT";
197 	case WSAECONNREFUSED: return "WSAECONNREFUSED";
198 	case WSAELOOP: return "WSAELOOP";
199 	case WSAENAMETOOLONG: return "WSAENAMETOOLONG";
200 	case WSASYSNOTREADY: return "WSASYSNOTREADY";
201 	case WSAVERNOTSUPPORTED: return "WSAVERNOTSUPPORTED";
202 	case WSANOTINITIALISED: return "WSANOTINITIALISED";
203 	case WSAHOST_NOT_FOUND: return "WSAHOST_NOT_FOUND";
204 	case WSATRY_AGAIN: return "WSATRY_AGAIN";
205 	case WSANO_RECOVERY: return "WSANO_RECOVERY";
206 	case WSANO_DATA: return "WSANO_DATA";
207 	default: return "NO ERROR";
208 	}
209 }
210 #endif
211 
NET_StreamGetLength(struct net_stream * s)212 static inline int NET_StreamGetLength (struct net_stream *s)
213 {
214 	return s ? dbuffer_len(s->inbound) : 0;
215 }
216 
217 /**
218  * @brief
219  * @sa NET_StreamNew
220  * @sa NET_StreamClose
221  * @sa NET_DatagramFindFreeSocket
222  */
NET_StreamGetFree(void)223 static int NET_StreamGetFree (void)
224 {
225 	static int start = 0;
226 	int i;
227 
228 	for (i = 0; i < MAX_STREAMS; i++) {
229 		const int pos = (i + start) % MAX_STREAMS;
230 		if (streams[pos] == nullptr) {
231 			start = (pos + 1) % MAX_STREAMS;
232 			Com_DPrintf(DEBUG_SERVER, "New stream at index: %i\n", pos);
233 			return pos;
234 		}
235 	}
236 	return -1;
237 }
238 
239 /**
240  * @sa NET_StreamNew
241  */
NET_DatagramFindFreeSocket(void)242 static int NET_DatagramFindFreeSocket (void)
243 {
244 	static int start = 0;
245 	int i;
246 
247 	for (i = 0; i < MAX_DATAGRAM_SOCKETS; i++) {
248 		const int pos = (i + start) % MAX_DATAGRAM_SOCKETS;
249 		if (datagram_sockets[pos] == nullptr) {
250 			start = (pos + 1) % MAX_DATAGRAM_SOCKETS;
251 			Com_DPrintf(DEBUG_SERVER, "New datagram at index: %i\n", pos);
252 			return pos;
253 		}
254 	}
255 	return -1;
256 }
257 
258 /**
259  * @sa NET_StreamGetFree
260  * @sa NET_StreamClose
261  */
NET_StreamNew(int index)262 static struct net_stream *NET_StreamNew (int index)
263 {
264 	net_stream* const s = Mem_PoolAllocType(net_stream, com_networkPool);
265 	s->data = nullptr;
266 	s->loopback_peer = nullptr;
267 	s->loopback = false;
268 	s->closed = false;
269 	s->finished = false;
270 	s->ready = false;
271 	s->socket = INVALID_SOCKET;
272 	s->inbound = dbufferptr();
273 	s->outbound = dbufferptr();
274 	s->index = index;
275 	s->family = 0;
276 	s->addrlen = 0;
277 	s->func = nullptr;
278 	if (streams[index])
279 		NET_StreamFree(streams[index]);
280 	streams[index] = s;
281 	return s;
282 }
283 
NET_ShowStreams_f(void)284 static void NET_ShowStreams_f (void)
285 {
286 	int i;
287 	char buf[256];
288 	int cnt = 0;
289 
290 	for (i = 0; i < MAX_STREAMS; i++) {
291 		if (streams[i] == nullptr)
292 			continue;
293 		Com_Printf("Steam %i is opened: %s on socket %i (closed: %i, finished: %i, outbound: " UFO_SIZE_T ", inbound: " UFO_SIZE_T ")\n", i,
294 			NET_StreamPeerToName(streams[i], buf, sizeof(buf), true),
295 			streams[i]->socket, streams[i]->closed, streams[i]->finished,
296 			dbuffer_len(streams[i]->outbound), dbuffer_len(streams[i]->inbound));
297 		cnt++;
298 	}
299 	Com_Printf("%i/%i streams opened\n", cnt, MAX_STREAMS);
300 }
301 
302 /**
303  * @sa NET_Shutdown
304  * @sa Qcommon_Init
305  */
NET_Init(void)306 void NET_Init (void)
307 {
308 	int i;
309 #ifdef _WIN32
310 	WSADATA winsockdata;
311 #endif
312 
313 	Com_Printf("\n----- network initialization -------\n");
314 
315 #ifdef _WIN32
316 	if (WSAStartup(MAKEWORD(2, 0), &winsockdata) != 0)
317 		Com_Error(ERR_FATAL, "Winsock initialization failed.");
318 #endif
319 
320 	maxfd = 0;
321 	FD_ZERO(&read_fds);
322 	FD_ZERO(&write_fds);
323 
324 	for (i = 0; i < MAX_STREAMS; i++)
325 		streams[i] = nullptr;
326 	for (i = 0; i < MAX_DATAGRAM_SOCKETS; i++)
327 		datagram_sockets[i] = nullptr;
328 
329 #ifndef _WIN32
330 	signal(SIGPIPE, SIG_IGN);
331 #endif
332 
333 	net_ipv4 = Cvar_Get("net_ipv4", "1", CVAR_ARCHIVE, "Only use ipv4");
334 	Cmd_AddCommand("net_showstreams", NET_ShowStreams_f, "Show opened streams");
335 
336 	netMutex = SDL_CreateMutex();
337 }
338 
339 /**
340  * @sa NET_Init
341  */
NET_Shutdown(void)342 void NET_Shutdown (void)
343 {
344 #ifdef _WIN32
345 	WSACleanup();
346 #endif
347 	SDL_DestroyMutex(netMutex);
348 	netMutex = nullptr;
349 }
350 
351 /**
352  * @sa NET_StreamFinished
353  * @sa NET_StreamNew
354  */
NET_StreamClose(struct net_stream * s)355 static void NET_StreamClose (struct net_stream *s)
356 {
357 	if (!s || s->closed)
358 		return;
359 
360 	if (s->socket != INVALID_SOCKET) {
361 		if (dbuffer_len(s->outbound))
362 			Com_Printf("The outbound buffer for this socket (%d) is not empty\n", s->socket);
363 		else if (dbuffer_len(s->inbound))
364 			Com_Printf("The inbound buffer for this socket (%d) is not empty\n", s->socket);
365 
366 		FD_CLR(s->socket, &read_fds);
367 		FD_CLR(s->socket, &write_fds);
368 		netCloseSocket(s->socket);
369 		s->socket = INVALID_SOCKET;
370 	}
371 	if (s->index >= 0)
372 		streams[s->index] = nullptr;
373 
374 	if (s->loopback_peer) {
375 		/* Detach the peer, so that it won't send us anything more */
376 		s->loopback_peer->outbound = dbufferptr();
377 		s->loopback_peer->loopback_peer = nullptr;
378 	}
379 
380 	s->closed = true;
381 	Com_DPrintf(DEBUG_SERVER, "Close stream at index: %i\n", s->index);
382 
383 	s->outbound = dbufferptr();
384 	s->socket = INVALID_SOCKET;
385 
386 	/* Note that this is potentially invalid after the callback returns */
387 	if (s->finished) {
388 		s->inbound = dbufferptr();
389 		if (s->onclose != nullptr)
390 			s->onclose();
391 		Mem_Free(s);
392 		s = nullptr;
393 	} else if (s->func) {
394 		s->func(s);
395 	}
396 
397 	if (s != nullptr && s->onclose != nullptr)
398 		s->onclose();
399 }
400 
do_accept(SOCKET sock)401 static void do_accept (SOCKET sock)
402 {
403 	const int index = NET_StreamGetFree();
404 	struct net_stream *s;
405 	if (index == -1) {
406 		Com_Printf("Too many streams open, rejecting inbound connection\n");
407 		netCloseSocket(sock);
408 		return;
409 	}
410 
411 	s = NET_StreamNew(index);
412 	s->socket = sock;
413 	s->inbound = dbufferptr(new dbuffer(4096));
414 	s->outbound = dbufferptr(new dbuffer(4096));
415 	s->family = server_family;
416 	s->addrlen = server_addrlen;
417 	s->func = server_func;
418 
419 	maxfd = std::max(sock + 1, maxfd);
420 	FD_SET(sock, &read_fds);
421 
422 	server_func(s);
423 	/** @todo close stream? */
424 }
425 
426 /**
427  * @sa Qcommon_Frame
428  */
NET_Wait(int timeout)429 void NET_Wait (int timeout)
430 {
431 	struct timeval tv;
432 	int ready;
433 	int i;
434 
435 	fd_set read_fds_out;
436 	fd_set write_fds_out;
437 
438 	memcpy(&read_fds_out, &read_fds, sizeof(read_fds_out));
439 	memcpy(&write_fds_out, &write_fds, sizeof(write_fds_out));
440 
441 	/* select() won't notice that loopback streams are ready, so we'll
442 	 * eliminate the delay directly */
443 	if (loopback_ready)
444 		timeout = 0;
445 
446 	tv.tv_sec = timeout / 1000;
447 	tv.tv_usec = 1000 * (timeout % 1000);
448 #ifdef _WIN32
449 	if (read_fds_out.fd_count == 0) {
450 		Sys_Sleep(timeout);
451 		ready = 0;
452 	} else
453 #endif
454 		ready = select(maxfd, &read_fds_out, &write_fds_out, nullptr, &tv);
455 
456 	if (ready == -1) {
457 		Com_Printf("select failed: %s\n", netStringError(netError));
458 		return;
459 	}
460 
461 	if (ready == 0 && !loopback_ready)
462 		return;
463 
464 	if (server_socket != INVALID_SOCKET && FD_ISSET(server_socket, &read_fds_out)) {
465 		const SOCKET client_socket = accept(server_socket, nullptr, 0);
466 		if (client_socket == INVALID_SOCKET) {
467 			if (errno != EAGAIN)
468 				Com_Printf("accept on socket %d failed: %s\n", server_socket, netStringError(netError));
469 		} else
470 			do_accept(client_socket);
471 	}
472 
473 	for (i = 0; i < MAX_STREAMS; i++) {
474 		struct net_stream *s = streams[i];
475 
476 		if (!s)
477 			continue;
478 
479 		if (s->loopback) {
480 			/* If the peer is gone and the buffer is empty, close the stream */
481 			if (!s->loopback_peer && NET_StreamGetLength(s) == 0) {
482 				NET_StreamClose(s);
483 			}
484 			/* Note that s is potentially invalid after the callback returns - we'll close dead streams on the next pass */
485 			else if (s->ready && s->func) {
486 				s->func(s);
487 			}
488 
489 			continue;
490 		}
491 
492 		if (s->socket == INVALID_SOCKET)
493 			continue;
494 
495 		if (FD_ISSET(s->socket, &write_fds_out)) {
496 			char buf[4096];
497 			int len;
498 
499 			if (dbuffer_len(s->outbound) == 0) {
500 				FD_CLR(s->socket, &write_fds);
501 
502 				/* Finished streams are closed when their outbound queues empty */
503 				if (s->finished)
504 					NET_StreamClose(s);
505 
506 				continue;
507 			}
508 
509 			{
510 				const ScopedMutex scopedMutex(netMutex);
511 				len = s->outbound->get(buf, sizeof(buf));
512 				len = send(s->socket, buf, len, 0);
513 
514 				s->outbound->remove(len);
515 			}
516 
517 			if (len < 0) {
518 				Com_Printf("write on socket %d failed: %s\n", s->socket, netStringError(netError));
519 				NET_StreamClose(s);
520 				continue;
521 			}
522 
523 			Com_DPrintf(DEBUG_SERVER, "wrote %d bytes to stream %d (%s)\n", len, i, NET_StreamPeerToName(s, buf, sizeof(buf), true));
524 		}
525 
526 		if (FD_ISSET(s->socket, &read_fds_out)) {
527 			char buf[4096];
528 			const int len = recv(s->socket, buf, sizeof(buf), 0);
529 			if (len <= 0) {
530 				if (len == -1)
531 					Com_Printf("read on socket %d failed: %s\n", s->socket, netStringError(netError));
532 				NET_StreamClose(s);
533 				continue;
534 			} else {
535 				if (s->inbound) {
536 					SDL_LockMutex(netMutex);
537 					s->inbound->add(buf, len);
538 					SDL_UnlockMutex(netMutex);
539 
540 					Com_DPrintf(DEBUG_SERVER, "read %d bytes from stream %d (%s)\n", len, i, NET_StreamPeerToName(s, buf, sizeof(buf), true));
541 
542 					/* Note that s is potentially invalid after the callback returns */
543 					if (s->func)
544 						s->func(s);
545 
546 					continue;
547 				}
548 			}
549 		}
550 	}
551 
552 	for (i = 0; i < MAX_DATAGRAM_SOCKETS; i++) {
553 		struct datagram_socket* s = datagram_sockets[i];
554 
555 		if (!s)
556 			continue;
557 
558 		if (FD_ISSET(s->socket, &write_fds_out)) {
559 			if (s->queue) {
560 				struct datagram *dgram = s->queue;
561 				const int len = sendto(s->socket, dgram->msg, dgram->len, 0, (struct sockaddr* )dgram->addr, s->addrlen);
562 				if (len == -1)
563 					Com_Printf("sendto on socket %d failed: %s\n", s->socket, netStringError(netError));
564 				/* Regardless of whether it worked, we don't retry datagrams */
565 				s->queue = dgram->next;
566 				Mem_Free(dgram->msg);
567 				Mem_Free(dgram->addr);
568 				Mem_Free(dgram);
569 				if (!s->queue)
570 					s->queue_tail = &s->queue;
571 			} else {
572 				FD_CLR(s->socket, &write_fds);
573 			}
574 		}
575 
576 		if (FD_ISSET(s->socket, &read_fds_out)) {
577 			char buf[256];
578 			char addrbuf[256];
579 			socklen_t addrlen = sizeof(addrbuf);
580 			const int len = recvfrom(s->socket, buf, sizeof(buf), 0, (struct sockaddr* )addrbuf, &addrlen);
581 			if (len == -1)
582 				Com_Printf("recvfrom on socket %d failed: %s\n", s->socket, netStringError(netError));
583 			else
584 				s->func(s, buf, len, (struct sockaddr* )addrbuf);
585 		}
586 	}
587 
588 	loopback_ready = false;
589 }
590 
NET_SocketSetNonBlocking(SOCKET socketNum)591 static bool NET_SocketSetNonBlocking (SOCKET socketNum)
592 {
593 	unsigned long t = 1;
594 	if (ioctlsocket(socketNum, FIONBIO, &t) == -1) {
595 		Com_Printf("ioctl FIONBIO failed: %s\n", strerror(errno));
596 		return false;
597 	}
598 	return true;
599 }
600 
NET_DoConnect(const char * node,const char * service,const struct addrinfo * addr,int i,stream_onclose_func * onclose)601 static struct net_stream *NET_DoConnect (const char* node, const char* service, const struct addrinfo *addr, int i, stream_onclose_func* onclose)
602 {
603 	struct net_stream *s;
604 	SOCKET sock = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
605 	if (sock == INVALID_SOCKET) {
606 		Com_Printf("Failed to create socket: %s\n", netStringError(netError));
607 		return nullptr;
608 	}
609 
610 	if (!NET_SocketSetNonBlocking(sock)) {
611 		netCloseSocket(sock);
612 		return nullptr;
613 	}
614 
615 	if (connect(sock, addr->ai_addr, addr->ai_addrlen) != 0) {
616 		const int err = netError;
617 #ifdef _WIN32
618 		if (err != WSAEWOULDBLOCK) {
619 #else
620 		if (err != EINPROGRESS) {
621 #endif
622 			Com_Printf("Failed to start connection to %s:%s: %s\n", node, service, netStringError(err));
623 			netCloseSocket(sock);
624 			return nullptr;
625 		}
626 	}
627 
628 	s = NET_StreamNew(i);
629 	s->socket = sock;
630 	s->inbound = dbufferptr(new dbuffer(4096));
631 	s->outbound = dbufferptr(new dbuffer(4096));
632 	s->family = addr->ai_family;
633 	s->addrlen = addr->ai_addrlen;
634 	s->onclose = onclose;
635 
636 	maxfd = std::max(sock + 1, maxfd);
637 	FD_SET(sock, &read_fds);
638 
639 	return s;
640 }
641 
642 /**
643  * @brief Try to connect to a given host on a given port
644  * @param[in] node The host to connect to
645  * @param[in] service The port to connect to
646  * @param[in] onclose The callback that is called on closing the returned stream. This is useful if
647  * you hold the pointer for the returned stream anywhere else and would like to get notified once
648  * this pointer is invalid.
649  * @sa NET_DoConnect
650  * @sa NET_ConnectToLoopBack
651  * @todo What about a timeout
652  */
653 struct net_stream *NET_Connect (const char* node, const char* service, stream_onclose_func* onclose)
654 {
655 	struct addrinfo *res;
656 	struct addrinfo hints;
657 	int rc;
658 	struct net_stream *s = nullptr;
659 	int index;
660 
661 	OBJZERO(hints);
662 	hints.ai_flags = AI_ADDRCONFIG | AI_NUMERICSERV;
663 	hints.ai_socktype = SOCK_STREAM;
664 	/* force ipv4 */
665 	if (net_ipv4->integer)
666 		hints.ai_family = AF_INET;
667 
668 	rc = getaddrinfo(node, service, &hints, &res);
669 	if (rc != 0) {
670 		Com_Printf("Failed to resolve host %s:%s: %s\n", node, service, gai_strerror(rc));
671 		return nullptr;
672 	}
673 
674 	index = NET_StreamGetFree();
675 	if (index == -1) {
676 		Com_Printf("Failed to connect to host %s:%s, too many streams open\n", node, service);
677 		freeaddrinfo(res);
678 		return nullptr;
679 	}
680 
681 	s = NET_DoConnect(node, service, res, index, onclose);
682 
683 	freeaddrinfo(res);
684 	return s;
685 }
686 
687 /**
688  * @param[in] onclose The callback that is called on closing the returned stream. This is useful if
689  * you hold the pointer for the returned stream anywhere else and would like to get notified once
690  * this pointer is invalid.
691  * @sa NET_Connect
692  */
693 struct net_stream *NET_ConnectToLoopBack (stream_onclose_func* onclose)
694 {
695 	struct net_stream *client, *server;
696 	int server_index, client_index;
697 
698 	if (!server_running)
699 		return nullptr;
700 
701 	server_index = NET_StreamGetFree();
702 	client_index = NET_StreamGetFree();
703 
704 	if (server_index == -1 || client_index == -1 || server_index == client_index) {
705 		Com_Printf("Failed to connect to loopback server, too many streams open\n");
706 		return nullptr;
707 	}
708 
709 	client = NET_StreamNew(client_index);
710 	client->loopback = true;
711 	client->inbound = dbufferptr(new dbuffer(4096));
712 	client->outbound = dbufferptr(new dbuffer(4096));
713 	client->onclose = onclose;
714 
715 	server = NET_StreamNew(server_index);
716 	server->loopback = true;
717 	server->inbound = client->outbound;
718 	server->outbound = client->inbound;
719 	server->func = server_func;
720 	server->onclose = nullptr;
721 
722 	client->loopback_peer = server;
723 	server->loopback_peer = client;
724 
725 	server_func(server);
726 
727 	return client;
728 }
729 
730 /**
731  * @brief Enqueue a network message into a stream
732  * @sa NET_StreamDequeue
733  */
734 void NET_StreamEnqueue (struct net_stream *s, const char* data, int len)
735 {
736 	if (len <= 0 || !s || s->closed || s->finished)
737 		return;
738 
739 	if (s->outbound) {
740 		const ScopedMutex scopedMutex(netMutex);
741 		s->outbound->add(data, len);
742 	}
743 
744 	/* on linux, socket is int, and INVALID_SOCKET -1
745 	 * on windows it is unsigned and  INVALID_SOCKET (~0)
746 	 * Let's hope that checking for INVALID_SOCKET is good enough for linux. */
747 	//if (s->socket >= 0)
748 	if (s->socket != INVALID_SOCKET)
749 		FD_SET(s->socket, &write_fds);
750 
751 	if (s->loopback_peer) {
752 		loopback_ready = true;
753 		s->loopback_peer->ready = true;
754 	}
755 }
756 
757 /**
758  * @brief Returns the length of the waiting inbound buffer
759  */
760 static int NET_StreamPeek (struct net_stream *s, char* data, int len)
761 {
762 	if (len <= 0 || !s)
763 		return 0;
764 
765 	dbufferptr &dbuf = s->inbound;
766 	if ((s->closed || s->finished) && dbuffer_len(dbuf) == 0)
767 		return 0;
768 
769 	return dbuf->get(data, len);
770 }
771 
772 /**
773  * @sa NET_StreamEnqueue
774  */
775 int NET_StreamDequeue (struct net_stream *s, char* data, int len)
776 {
777 	if (len <= 0 || !s || s->finished)
778 		return 0;
779 
780 	return s->inbound->extract(data, len);
781 }
782 
783 /**
784  * @brief Reads messages from the network channel and adds them to the dbuffer
785  * where you can use the NET_Read* functions to get the values in the correct
786  * order
787  * @sa NET_StreamDequeue
788  */
789 dbuffer* NET_ReadMsg (struct net_stream *s)
790 {
791 	unsigned int v;
792 	const ScopedMutex scopedMutex(netMutex);
793 
794 	if (NET_StreamPeek(s, (char*)&v, 4) < 4)
795 		return nullptr;
796 
797 	int len = LittleLong(v);
798 	if (NET_StreamGetLength(s) < (4 + len))
799 		return nullptr;
800 
801 	char tmp[256];
802 	const int size = sizeof(tmp);
803 	NET_StreamDequeue(s, tmp, 4);
804 
805 	dbuffer* buf = new dbuffer();
806 	while (len > 0) {
807 		const int x = NET_StreamDequeue(s, tmp, std::min(len, size));
808 		buf->add(tmp, x);
809 		len -= x;
810 	}
811 
812 	return buf;
813 }
814 
815 void* NET_StreamGetData (struct net_stream *s)
816 {
817 	return s ? s->data : nullptr;
818 }
819 
820 void NET_StreamSetData (struct net_stream *s, void* data)
821 {
822 	if (!s)
823 		return;
824 	s->data = data;
825 }
826 
827 /**
828  * @brief Call NET_StreamFree to dump the whole thing right now
829  * @sa NET_StreamClose
830  * @sa NET_StreamFinished
831  */
832 void NET_StreamFree (struct net_stream *s)
833 {
834 	if (!s)
835 		return;
836 	s->finished = true;
837 	NET_StreamClose(s);
838 }
839 
840 /**
841  * @brief Call NET_StreamFinished to mark the stream as uninteresting, but to
842  * finish sending any data in the buffer. The stream will appear
843  * closed after this call, and at some unspecified point in the future
844  * s will become an invalid pointer, so it should not be further
845  * referenced.
846  */
847 void NET_StreamFinished (struct net_stream *s)
848 {
849 	if (!s)
850 		return;
851 
852 	s->finished = true;
853 
854 	if (s->socket != INVALID_SOCKET)
855 		FD_CLR(s->socket, &read_fds);
856 
857 	/* Stop the loopback peer from queueing stuff up in here */
858 	if (s->loopback_peer)
859 		s->loopback_peer->outbound = dbufferptr();
860 
861 	const ScopedMutex scopedMutex(netMutex);
862 	s->inbound = dbufferptr();
863 
864 	/* If there's nothing in the outbound buffer, any finished stream is
865 	 * ready to be closed */
866 	if (dbuffer_len(s->outbound) == 0)
867 		NET_StreamClose(s);
868 }
869 
870 /**
871  * @brief Returns the numerical representation of a @c net_stream
872  * @note Not thread safe!
873  */
874 const char* NET_StreamToString (struct net_stream *s)
875 {
876 	static char node[64];
877 	NET_StreamPeerToName(s, node, sizeof(node), false);
878 	return node;
879 }
880 
881 /**
882  * @param[in] s The network stream to get the name for
883  * @param[out] dst The target buffer to store the ip and port in
884  * @param[in] len The length of the target buffer
885  * @param[in] appendPort Also append the port number to the target buffer
886  */
887 const char* NET_StreamPeerToName (struct net_stream *s, char* dst, int len, bool appendPort)
888 {
889 	if (!s)
890 		return "(null)";
891 
892 	if (NET_StreamIsLoopback(s))
893 		return "loopback connection";
894 
895 	char buf[128];
896 	socklen_t addrlen = s->addrlen;
897 	if (getpeername(s->socket, (struct sockaddr* )buf, &addrlen) != 0)
898 		return "(error)";
899 
900 	char node[64];
901 	char service[64];
902 	const int rc = getnameinfo((struct sockaddr* )buf, addrlen, node, sizeof(node), service, sizeof(service),
903 			NI_NUMERICHOST | NI_NUMERICSERV);
904 	if (rc != 0) {
905 		Com_Printf("Failed to convert sockaddr to string: %s\n", gai_strerror(rc));
906 		return "(error)";
907 	}
908 	if (!appendPort) {
909 		Q_strncpyz(dst, node, len);
910 	} else {
911 		node[sizeof(node) - 1] = '\0';
912 		service[sizeof(service) - 1] = '\0';
913 		Com_sprintf(dst, len, "%s %s", node, service);
914 	}
915 	return dst;
916 }
917 
918 void NET_StreamSetCallback (struct net_stream *s, stream_callback_func* func)
919 {
920 	if (!s)
921 		return;
922 	s->func = func;
923 }
924 
925 bool NET_StreamIsLoopback (struct net_stream *s)
926 {
927 	return s && s->loopback;
928 }
929 
930 static int NET_DoStartServer (const struct addrinfo *addr)
931 {
932 	SOCKET sock = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
933 	int t = 1;
934 
935 	if (sock == INVALID_SOCKET) {
936 		Com_Printf("Failed to create socket: %s\n", netStringError(netError));
937 		return INVALID_SOCKET;
938 	}
939 
940 	if (!NET_SocketSetNonBlocking(sock)) {
941 		netCloseSocket(sock);
942 		return INVALID_SOCKET;
943 	}
944 
945 #ifdef _WIN32
946 	if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char*) &t, sizeof(t)) != 0) {
947 #else
948 	if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &t, sizeof(t)) != 0) {
949 #endif
950 		Com_Printf("Failed to set SO_REUSEADDR on socket: %s\n", netStringError(netError));
951 		netCloseSocket(sock);
952 		return INVALID_SOCKET;
953 	}
954 
955 	if (bind(sock, addr->ai_addr, addr->ai_addrlen) != 0) {
956 		Com_Printf("Failed to bind socket: %s\n", netStringError(netError));
957 		netCloseSocket(sock);
958 		return INVALID_SOCKET;
959 	}
960 
961 	if (listen(sock, SOMAXCONN) != 0) {
962 		Com_Printf("Failed to listen on socket: %s\n", netStringError(netError));
963 		netCloseSocket(sock);
964 		return INVALID_SOCKET;
965 	}
966 
967 	maxfd = std::max(sock + 1, maxfd);
968 	FD_SET(sock, &read_fds);
969 	server_family = addr->ai_family;
970 	server_addrlen = addr->ai_addrlen;
971 
972 	return sock;
973 }
974 
975 static struct addrinfo* NET_GetAddrinfoForNode (const char* node, const char* service)
976 {
977 	struct addrinfo *res;
978 	struct addrinfo hints;
979 	int rc;
980 
981 	OBJZERO(hints);
982 	hints.ai_flags = AI_ADDRCONFIG | AI_PASSIVE;
983 	hints.ai_socktype = SOCK_STREAM;
984 	/* force ipv4 */
985 	if (net_ipv4->integer)
986 		hints.ai_family = AF_INET;
987 
988 	rc = getaddrinfo(node, service, &hints, &res);
989 	if (rc != 0) {
990 		Com_Printf("Failed to resolve host %s:%s: %s\n", node ? node : "*", service, gai_strerror(rc));
991 		return nullptr;
992 	}
993 
994 	return res;
995 }
996 
997 /**
998  * @sa NET_DoStartServer
999  * @param[in] node The node to start the server with
1000  * @param[in] service If this is nullptr we are in single player mode
1001  * @param[in] func The server callback function to read the packets
1002  * @sa SV_ReadPacket
1003  * @sa server_func
1004  * @sa SV_Stop
1005  */
1006 bool SV_Start (const char* node, const char* service, stream_callback_func* func)
1007 {
1008 	if (!func)
1009 		return false;
1010 
1011 	if (server_running) {
1012 		Com_Printf("SV_Start: Server is still running - call SV_Stop before\n");
1013 		return false;
1014 	}
1015 
1016 	if (service) {
1017 		struct addrinfo *res = NET_GetAddrinfoForNode(node, service);
1018 
1019 		server_socket = NET_DoStartServer(res);
1020 		if (server_socket == INVALID_SOCKET) {
1021 			Com_Printf("Failed to start server on %s:%s\n", node ? node : "*", service);
1022 		} else {
1023 			server_running = true;
1024 			server_func = func;
1025 		}
1026 		freeaddrinfo(res);
1027 	} else {
1028 		/* Loopback server only */
1029 		server_running = true;
1030 		server_func = func;
1031 	}
1032 
1033 	return server_running;
1034 }
1035 
1036 /**
1037  * @sa SV_Start
1038  */
1039 void SV_Stop (void)
1040 {
1041 	server_running = false;
1042 	server_func = nullptr;
1043 	if (server_socket != INVALID_SOCKET) {
1044 		FD_CLR(server_socket, &read_fds);
1045 		netCloseSocket(server_socket);
1046 	}
1047 	server_socket = INVALID_SOCKET;
1048 }
1049 
1050 /**
1051  * @sa NET_DatagramSocketNew
1052  */
1053 static struct datagram_socket* NET_DatagramSocketDoNew (const struct addrinfo *addr)
1054 {
1055 	SOCKET sock = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
1056 	int t = 1;
1057 	const int index = NET_DatagramFindFreeSocket();
1058 
1059 	if (index == -1) {
1060 		Com_Printf("Too many datagram sockets open\n");
1061 		return nullptr;
1062 	}
1063 
1064 	if (sock == INVALID_SOCKET) {
1065 		Com_Printf("Failed to create socket: %s\n", netStringError(netError));
1066 		return nullptr;
1067 	}
1068 
1069 	if (!NET_SocketSetNonBlocking(sock)) {
1070 		netCloseSocket(sock);
1071 		return nullptr;
1072 	}
1073 
1074 	if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char*) &t, sizeof(t)) != 0) {
1075 		Com_Printf("Failed to set SO_REUSEADDR on socket: %s\n", netStringError(netError));
1076 		netCloseSocket(sock);
1077 		return nullptr;
1078 	}
1079 
1080 	if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (char*) &t, sizeof(t)) != 0) {
1081 		Com_Printf("Failed to set SO_BROADCAST on socket: %s\n", netStringError(netError));
1082 		netCloseSocket(sock);
1083 		return nullptr;
1084 	}
1085 
1086 	if (bind(sock, addr->ai_addr, addr->ai_addrlen) != 0) {
1087 		Com_Printf("Failed to bind socket: %s\n", netStringError(netError));
1088 		netCloseSocket(sock);
1089 		return nullptr;
1090 	}
1091 
1092 	maxfd = std::max(sock + 1, maxfd);
1093 	FD_SET(sock, &read_fds);
1094 
1095 	datagram_socket* const s = Mem_PoolAllocType(datagram_socket, com_networkPool);
1096 	s->family = addr->ai_family;
1097 	s->addrlen = addr->ai_addrlen;
1098 	s->socket = sock;
1099 	s->index = index;
1100 	s->queue = nullptr;
1101 	s->queue_tail = &s->queue;
1102 	s->func = nullptr;
1103 	datagram_sockets[index] = s;
1104 
1105 	return s;
1106 }
1107 
1108 /**
1109  * @brief Opens a datagram socket (UDP)
1110  * @sa NET_DatagramSocketDoNew
1111  * @param[in] node The numeric address to resolv (might be nullptr)
1112  * @param[in] service The port number
1113  * @param[in] func Callback function for data handling
1114  */
1115 struct datagram_socket* NET_DatagramSocketNew (const char* node, const char* service, datagram_callback_func *func)
1116 {
1117 	struct datagram_socket* s;
1118 	struct addrinfo *res;
1119 	struct addrinfo hints;
1120 	int rc;
1121 
1122 	if (!service || !func)
1123 		return nullptr;
1124 
1125 	OBJZERO(hints);
1126 	hints.ai_flags = AI_NUMERICHOST | AI_ADDRCONFIG | AI_NUMERICSERV | AI_PASSIVE;
1127 	hints.ai_socktype = SOCK_DGRAM;
1128 	/* force ipv4 */
1129 	if (net_ipv4->integer)
1130 		hints.ai_family = AF_INET;
1131 
1132 	rc = getaddrinfo(node, service, &hints, &res);
1133 
1134 	if (rc != 0) {
1135 		Com_Printf("Failed to resolve host %s:%s: %s\n", node ? node : "*", service, gai_strerror(rc));
1136 		return nullptr;
1137 	}
1138 
1139 	s = NET_DatagramSocketDoNew(res);
1140 	if (s)
1141 		s->func = func;
1142 
1143 	freeaddrinfo(res);
1144 	return s;
1145 }
1146 
1147 /**
1148  * @sa NET_DatagramSocketNew
1149  */
1150 void NET_DatagramSend (struct datagram_socket* s, const char* buf, int len, struct sockaddr* to)
1151 {
1152 	if (!s || len <= 0 || !buf || !to)
1153 		return;
1154 
1155 	datagram* const dgram = Mem_PoolAllocType(datagram, com_networkPool);
1156 	dgram->msg  = Mem_PoolAllocTypeN(char, len,        com_networkPool);
1157 	dgram->addr = Mem_PoolAllocTypeN(char, s->addrlen, com_networkPool);
1158 	memcpy(dgram->msg, buf, len);
1159 	memcpy(dgram->addr, to, len);
1160 	dgram->len = len;
1161 	dgram->next = nullptr;
1162 
1163 	*s->queue_tail = dgram;
1164 	s->queue_tail = &dgram->next;
1165 
1166 	FD_SET(s->socket, &write_fds);
1167 }
1168 
1169 /**
1170  * @sa NET_DatagramSend
1171  * @sa NET_DatagramSocketNew
1172  * @todo This is only sending on the first available device, what if we have several devices?
1173  */
1174 void NET_DatagramBroadcast (struct datagram_socket* s, const char* buf, int len, int port)
1175 {
1176 	if (s->family == AF_INET) {
1177 		struct sockaddr_in addr;
1178 		addr.sin_family = AF_INET;
1179 		addr.sin_port = htons(port);
1180 		addr.sin_addr.s_addr = INADDR_BROADCAST;
1181 		NET_DatagramSend(s, buf, len, (struct sockaddr* )&addr);
1182 	} else if (s->family == AF_INET6) {
1183 		struct sockaddr_in addr;
1184 		addr.sin_family = AF_INET6;
1185 		addr.sin_port = htons(port);
1186 		addr.sin_addr.s_addr = INADDR_BROADCAST;
1187 		NET_DatagramSend(s, buf, len, (struct sockaddr* )&addr);
1188 	} else {
1189 		Com_Error(ERR_DROP, "Broadcast unsupported on address family %d\n", s->family);
1190 	}
1191 }
1192 
1193 /**
1194  * @sa NET_DatagramSocketNew
1195  * @sa NET_DatagramSocketDoNew
1196  */
1197 void NET_DatagramSocketClose (struct datagram_socket* s)
1198 {
1199 	if (!s)
1200 		return;
1201 
1202 	FD_CLR(s->socket, &read_fds);
1203 	FD_CLR(s->socket, &write_fds);
1204 	netCloseSocket(s->socket);
1205 
1206 	while (s->queue) {
1207 		struct datagram *dgram = s->queue;
1208 		s->queue = dgram->next;
1209 		Mem_Free(dgram->msg);
1210 		Mem_Free(dgram->addr);
1211 		Mem_Free(dgram);
1212 	}
1213 
1214 	datagram_sockets[s->index] = nullptr;
1215 	Mem_Free(s);
1216 }
1217 
1218 /**
1219  * @brief Convert sockaddr to string
1220  * @param[in] s The datagram socket type to get the addrlen from
1221  * @param[in] addr The socket address to convert into a string
1222  * @param[out] node The target node name buffer
1223  * @param[in] nodelen The length of the node name buffer
1224  * @param[out] service The target service name buffer
1225  * @param[in] servicelen The length of the service name buffer
1226  */
1227 void NET_SockaddrToStrings (struct datagram_socket* s, struct sockaddr* addr, char* node, size_t nodelen, char* service, size_t servicelen)
1228 {
1229 	const int rc = getnameinfo(addr, s->addrlen, node, nodelen, service, servicelen,
1230 			NI_NUMERICHOST | NI_NUMERICSERV | NI_DGRAM);
1231 	if (rc != 0) {
1232 		Com_Printf("Failed to convert sockaddr to string: %s\n", gai_strerror(rc));
1233 		Q_strncpyz(node, "(error)", nodelen);
1234 		Q_strncpyz(service, "(error)", servicelen);
1235 	}
1236 }
1237 
1238 static void NET_AddrinfoToString (const struct addrinfo *addr, char* buf, size_t bufLength)
1239 {
1240 	char* service = inet_ntoa(((struct sockaddr_in *)addr->ai_addr)->sin_addr);
1241 	Q_strncpyz(buf, service, bufLength);
1242 }
1243 
1244 void NET_ResolvNode (const char* node, char* buf, size_t bufLength)
1245 {
1246 	struct addrinfo* addrinfo = NET_GetAddrinfoForNode(node, nullptr);
1247 	if (addrinfo == nullptr) {
1248 		buf[0] = '\0';
1249 		return;
1250 	}
1251 	NET_AddrinfoToString(addrinfo, buf, bufLength);
1252 	freeaddrinfo(addrinfo);
1253 }
1254