UFO: Alien Invasion
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
net.cpp
Go to the documentation of this file.
1 
9 /*
10 Copyright (C) 2002-2020 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 #ifndef _MSC_VER
34 #include <unistd.h>
35 #endif
36 #include <SDL_thread.h>
37 #ifdef _WIN32
38 #include "../ports/system.h"
39 #endif
40 #include "../shared/scopedmutex.h"
41 
42 #define MAX_STREAMS 56
43 #define MAX_DATAGRAM_SOCKETS 7
44 
45 #ifdef _WIN32
46 # include <winsock2.h>
47 # include <ws2tcpip.h>
48 # if WINVER < 0x501
49 # include <wspiapi.h>
50 # else
51 # include <ws2spi.h>
52 # endif
53 # define netError WSAGetLastError()
54 # define netStringError netStringErrorWin
55 # define netCloseSocket closesocket
56 # define gai_strerrorA netStringErrorWin
57 
58 #else /* WIN32 */
59 
60 # include <sys/ioctl.h>
61 # include <sys/select.h>
62 # include <sys/types.h>
63 # include <sys/socket.h>
64 # include <sys/time.h>
65 # include <netdb.h>
66 # include <arpa/inet.h>
67 # include <netinet/in.h>
68 # include <signal.h>
69 typedef int SOCKET;
70 # define INVALID_SOCKET (-1)
71 # define netError errno
72 # define netStringError strerror
73 # define netCloseSocket close
74 # define ioctlsocket ioctl
75 #endif /* WIN32 */
76 
77 #ifdef EMSCRIPTEN
78 #define NI_NUMERICHOST 0
79 #define NI_NUMERICSERV 0
80 #define NI_DGRAM 0
81 #define AI_PASSIVE 0
82 #define AI_NUMERICHOST 0
83 #define INADDR_BROADCAST 0
84 #endif
85 
91 #ifndef AI_NUMERICSERV
92 #define AI_NUMERICSERV 0
93 #endif
94 #ifndef AI_ADDRCONFIG
95 #define AI_ADDRCONFIG 0
96 #endif
97 
102 #define NET_MULTICAST_IP6 "ff04::696f:7175:616b:6533"
103 
104 #define dbuffer_len(dbuf) (dbuf ? (dbuf)->length() : 0)
105 
106 static cvar_t* net_ipv4;
107 static SDL_mutex* netMutex;
108 
109 struct net_stream {
110  void* data;
111 
112  bool loopback;
113  bool ready;
114  bool closed;
115  bool finished;
117  int index;
118  int family;
119  int addrlen;
120 
121  /* these buffers must be used in a thread safe manner
122  * (lock netMutex) because the game thread can also write to it */
125 
129 };
130 
131 struct datagram {
132  int len;
133  char* msg;
134  char* addr;
135  struct datagram* next;
136 };
137 
140  int index;
141  int family;
142  int addrlen;
143  struct datagram* queue;
146 };
147 
148 static fd_set read_fds;
149 static fd_set write_fds;
150 static SOCKET maxfd;
153 
154 static bool loopback_ready = false;
155 static bool server_running = false;
159 
160 #ifdef _WIN32
161 static const char* netStringErrorWin (int code)
162 {
163  switch (code) {
164  case WSAEINTR: return "WSAEINTR";
165  case WSAEBADF: return "WSAEBADF";
166  case WSAEACCES: return "WSAEACCES";
167  case WSAEDISCON: return "WSAEDISCON";
168  case WSAEFAULT: return "WSAEFAULT";
169  case WSAEINVAL: return "WSAEINVAL";
170  case WSAEMFILE: return "WSAEMFILE";
171  case WSAEWOULDBLOCK: return "WSAEWOULDBLOCK";
172  case WSAEINPROGRESS: return "WSAEINPROGRESS";
173  case WSAEALREADY: return "WSAEALREADY";
174  case WSAENOTSOCK: return "WSAENOTSOCK";
175  case WSAEDESTADDRREQ: return "WSAEDESTADDRREQ";
176  case WSAEMSGSIZE: return "WSAEMSGSIZE";
177  case WSAEPROTOTYPE: return "WSAEPROTOTYPE";
178  case WSAENOPROTOOPT: return "WSAENOPROTOOPT";
179  case WSAEPROTONOSUPPORT: return "WSAEPROTONOSUPPORT";
180  case WSAESOCKTNOSUPPORT: return "WSAESOCKTNOSUPPORT";
181  case WSAEOPNOTSUPP: return "WSAEOPNOTSUPP";
182  case WSAEPFNOSUPPORT: return "WSAEPFNOSUPPORT";
183  case WSAEAFNOSUPPORT: return "WSAEAFNOSUPPORT";
184  case WSAEADDRINUSE: return "WSAEADDRINUSE";
185  case WSAEADDRNOTAVAIL: return "WSAEADDRNOTAVAIL";
186  case WSAENETDOWN: return "WSAENETDOWN";
187  case WSAENETUNREACH: return "WSAENETUNREACH";
188  case WSAENETRESET: return "WSAENETRESET";
189  case WSAEHOSTDOWN: return "WSAEHOSTDOWN";
190  case WSAEHOSTUNREACH: return "WSAEHOSTUNREACH";
191  case WSAECONNABORTED: return "WSWSAECONNABORTEDAEINTR";
192  case WSAECONNRESET: return "WSAECONNRESET";
193  case WSAENOBUFS: return "WSAENOBUFS";
194  case WSAEISCONN: return "WSAEISCONN";
195  case WSAENOTCONN: return "WSAENOTCONN";
196  case WSAESHUTDOWN: return "WSAESHUTDOWN";
197  case WSAETOOMANYREFS: return "WSAETOOMANYREFS";
198  case WSAETIMEDOUT: return "WSAETIMEDOUT";
199  case WSAECONNREFUSED: return "WSAECONNREFUSED";
200  case WSAELOOP: return "WSAELOOP";
201  case WSAENAMETOOLONG: return "WSAENAMETOOLONG";
202  case WSASYSNOTREADY: return "WSASYSNOTREADY";
203  case WSAVERNOTSUPPORTED: return "WSAVERNOTSUPPORTED";
204  case WSANOTINITIALISED: return "WSANOTINITIALISED";
205  case WSAHOST_NOT_FOUND: return "WSAHOST_NOT_FOUND";
206  case WSATRY_AGAIN: return "WSATRY_AGAIN";
207  case WSANO_RECOVERY: return "WSANO_RECOVERY";
208  case WSANO_DATA: return "WSANO_DATA";
209  default: return "NO ERROR";
210  }
211 }
212 #endif
213 
214 static inline int NET_StreamGetLength (struct net_stream* s)
215 {
216  return s ? dbuffer_len(s->inbound) : 0;
217 }
218 
225 static int NET_StreamGetFree (void)
226 {
227  static int start = 0;
228 
229  for (int i = 0; i < MAX_STREAMS; i++) {
230  const int pos = (i + start) % MAX_STREAMS;
231  if (streams[pos] == nullptr) {
232  start = (pos + 1) % MAX_STREAMS;
233  Com_DPrintf(DEBUG_SERVER, "New stream at index: %i\n", pos);
234  return pos;
235  }
236  }
237  return -1;
238 }
239 
243 static int NET_DatagramFindFreeSocket (void)
244 {
245  static int start = 0;
246 
247  for (int 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 
262 static struct net_stream* NET_StreamNew (int index)
263 {
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 
284 static void NET_ShowStreams_f (void)
285 {
286  char buf[256];
287  int cnt = 0;
288 
289  for (int i = 0; i < MAX_STREAMS; i++) {
290  if (streams[i] == nullptr)
291  continue;
292  Com_Printf("Steam %i is opened: %s on socket %i (closed: %i, finished: %i, outbound: " UFO_SIZE_T ", inbound: " UFO_SIZE_T ")\n", i,
293  NET_StreamPeerToName(streams[i], buf, sizeof(buf), true),
294  streams[i]->socket, streams[i]->closed, streams[i]->finished,
295  dbuffer_len(streams[i]->outbound), dbuffer_len(streams[i]->inbound));
296  cnt++;
297  }
298  Com_Printf("%i/%i streams opened\n", cnt, MAX_STREAMS);
299 }
300 
305 void NET_Init (void)
306 {
307  Com_Printf("\n----- network initialization -------\n");
308 
309 #ifdef _WIN32
310  WSADATA winsockdata;
311  if (WSAStartup(MAKEWORD(2, 0), &winsockdata) != 0)
312  Com_Error(ERR_FATAL, "Winsock initialization failed.");
313 #endif
314 
315  maxfd = 0;
316  FD_ZERO(&read_fds);
317  FD_ZERO(&write_fds);
318 
319  for (int i = 0; i < MAX_STREAMS; i++)
320  streams[i] = nullptr;
321  for (int i = 0; i < MAX_DATAGRAM_SOCKETS; i++)
322  datagram_sockets[i] = nullptr;
323 
324 #ifndef _WIN32
325  signal(SIGPIPE, SIG_IGN);
326 #endif
327 
328  net_ipv4 = Cvar_Get("net_ipv4", "1", CVAR_ARCHIVE, "Only use ipv4");
329  Cmd_AddCommand("net_showstreams", NET_ShowStreams_f, "Show opened streams");
330 
331  netMutex = SDL_CreateMutex();
332 }
333 
337 void NET_Shutdown (void)
338 {
339 #ifdef _WIN32
340  WSACleanup();
341 #endif
342  SDL_DestroyMutex(netMutex);
343  netMutex = nullptr;
344 }
345 
350 static void NET_StreamClose (struct net_stream* s)
351 {
352  if (!s || s->closed)
353  return;
354 
355  if (s->socket != INVALID_SOCKET) {
356  if (dbuffer_len(s->outbound))
357  Com_Printf("The outbound buffer for this socket (%d) is not empty\n", s->socket);
358  else if (dbuffer_len(s->inbound))
359  Com_Printf("The inbound buffer for this socket (%d) is not empty\n", s->socket);
360 
361  FD_CLR(s->socket, &read_fds);
362  FD_CLR(s->socket, &write_fds);
364  s->socket = INVALID_SOCKET;
365  }
366  if (s->index >= 0)
367  streams[s->index] = nullptr;
368 
369  if (s->loopback_peer) {
370  /* Detach the peer, so that it won't send us anything more */
372  s->loopback_peer->loopback_peer = nullptr;
373  }
374 
375  s->closed = true;
376  Com_DPrintf(DEBUG_SERVER, "Close stream at index: %i\n", s->index);
377 
378  s->outbound = dbufferptr();
379  s->socket = INVALID_SOCKET;
380 
381  /* Note that this is potentially invalid after the callback returns */
382  if (s->finished) {
383  s->inbound = dbufferptr();
384  if (s->onclose != nullptr)
385  s->onclose();
386  Mem_Free(s);
387  s = nullptr;
388  } else if (s->func) {
389  s->func(s);
390  }
391 
392  if (s != nullptr && s->onclose != nullptr)
393  s->onclose();
394 }
395 
396 static void do_accept (SOCKET sock)
397 {
398  const int index = NET_StreamGetFree();
399  if (index == -1) {
400  Com_Printf("Too many streams open, rejecting inbound connection\n");
401  netCloseSocket(sock);
402  return;
403  }
404 
405  struct net_stream* s = NET_StreamNew(index);
406  s->socket = sock;
407  s->inbound = dbufferptr(new dbuffer(4096));
408  s->outbound = dbufferptr(new dbuffer(4096));
409  s->family = server_family;
410  s->addrlen = server_addrlen;
411  s->func = server_func;
412 
413  maxfd = std::max(sock + 1, maxfd);
414  FD_SET(sock, &read_fds);
415 
416  server_func(s);
418 }
419 
423 void NET_Wait (int timeout)
424 {
425  struct timeval tv;
426  int ready;
427 
428  fd_set read_fds_out;
429  fd_set write_fds_out;
430 
431  memcpy(&read_fds_out, &read_fds, sizeof(read_fds_out));
432  memcpy(&write_fds_out, &write_fds, sizeof(write_fds_out));
433 
434  /* select() won't notice that loopback streams are ready, so we'll
435  * eliminate the delay directly */
436  if (loopback_ready)
437  timeout = 0;
438 
439  tv.tv_sec = timeout / 1000;
440  tv.tv_usec = 1000 * (timeout % 1000);
441 #ifdef _WIN32
442  if (read_fds_out.fd_count == 0) {
443  Sys_Sleep(timeout);
444  ready = 0;
445  } else
446 #endif
447  ready = select(maxfd, &read_fds_out, &write_fds_out, nullptr, &tv);
448 
449  if (ready == -1) {
450  Com_Printf("select failed: %s\n", netStringError(netError));
451  return;
452  }
453 
454  if (ready == 0 && !loopback_ready)
455  return;
456 
457  if (server_socket != INVALID_SOCKET && FD_ISSET(server_socket, &read_fds_out)) {
458  const SOCKET client_socket = accept(server_socket, nullptr, 0);
459  if (client_socket == INVALID_SOCKET) {
460  if (errno != EAGAIN)
461  Com_Printf("accept on socket %d failed: %s\n", server_socket, netStringError(netError));
462  } else
463  do_accept(client_socket);
464  }
465 
466  for (int i = 0; i < MAX_STREAMS; i++) {
467  struct net_stream* s = streams[i];
468 
469  if (!s)
470  continue;
471 
472  if (s->loopback) {
473  /* If the peer is gone and the buffer is empty, close the stream */
474  if (!s->loopback_peer && NET_StreamGetLength(s) == 0) {
475  NET_StreamClose(s);
476  }
477  /* Note that s is potentially invalid after the callback returns - we'll close dead streams on the next pass */
478  else if (s->ready && s->func) {
479  s->func(s);
480  }
481 
482  continue;
483  }
484 
485  if (s->socket == INVALID_SOCKET)
486  continue;
487 
488  if (FD_ISSET(s->socket, &write_fds_out)) {
489  if (dbuffer_len(s->outbound) == 0) {
490  FD_CLR(s->socket, &write_fds);
491 
492  /* Finished streams are closed when their outbound queues empty */
493  if (s->finished)
494  NET_StreamClose(s);
495 
496  continue;
497  }
498 
499  char buf[4096];
500  int len;
501  {
502  const ScopedMutex scopedMutex(netMutex);
503  len = s->outbound->get(buf, sizeof(buf));
504  len = send(s->socket, buf, len, 0);
505 
506  s->outbound->remove(len);
507  }
508 
509  if (len < 0) {
510  Com_Printf("write on socket %d failed: %s\n", s->socket, netStringError(netError));
511  NET_StreamClose(s);
512  continue;
513  }
514 
515  Com_DPrintf(DEBUG_SERVER, "wrote %d bytes to stream %d (%s)\n", len, i, NET_StreamPeerToName(s, buf, sizeof(buf), true));
516  }
517 
518  if (FD_ISSET(s->socket, &read_fds_out)) {
519  char buf[4096];
520  const int len = recv(s->socket, buf, sizeof(buf), 0);
521  if (len <= 0) {
522  if (len == -1)
523  Com_Printf("read on socket %d failed: %s\n", s->socket, netStringError(netError));
524  NET_StreamClose(s);
525  continue;
526  } else {
527  if (s->inbound) {
528  SDL_LockMutex(netMutex);
529  s->inbound->add(buf, len);
530  SDL_UnlockMutex(netMutex);
531 
532  Com_DPrintf(DEBUG_SERVER, "read %d bytes from stream %d (%s)\n", len, i, NET_StreamPeerToName(s, buf, sizeof(buf), true));
533 
534  /* Note that s is potentially invalid after the callback returns */
535  if (s->func)
536  s->func(s);
537 
538  continue;
539  }
540  }
541  }
542  }
543 
544  for (int i = 0; i < MAX_DATAGRAM_SOCKETS; i++) {
545  struct datagram_socket* s = datagram_sockets[i];
546 
547  if (!s)
548  continue;
549 
550  if (FD_ISSET(s->socket, &write_fds_out)) {
551  if (s->queue) {
552  struct datagram* dgram = s->queue;
553  const int len = sendto(s->socket, dgram->msg, dgram->len, 0, (struct sockaddr* )dgram->addr, s->addrlen);
554  if (len == -1)
555  Com_Printf("sendto on socket %d failed: %s\n", s->socket, netStringError(netError));
556  /* Regardless of whether it worked, we don't retry datagrams */
557  s->queue = dgram->next;
558  Mem_Free(dgram->msg);
559  Mem_Free(dgram->addr);
560  Mem_Free(dgram);
561  if (!s->queue)
562  s->queue_tail = &s->queue;
563  } else {
564  FD_CLR(s->socket, &write_fds);
565  }
566  }
567 
568  if (FD_ISSET(s->socket, &read_fds_out)) {
569  char buf[256];
570  char addrbuf[256];
571  socklen_t addrlen = sizeof(addrbuf);
572  const int len = recvfrom(s->socket, buf, sizeof(buf), 0, (struct sockaddr* )addrbuf, &addrlen);
573  if (len == -1)
574  Com_Printf("recvfrom on socket %d failed: %s\n", s->socket, netStringError(netError));
575  else
576  s->func(s, buf, len, (struct sockaddr* )addrbuf);
577  }
578  }
579 
580  loopback_ready = false;
581 }
582 
583 static bool NET_SocketSetNonBlocking (SOCKET socketNum)
584 {
585  unsigned long t = 1;
586  if (ioctlsocket(socketNum, FIONBIO, &t) == -1) {
587  Com_Printf("ioctl FIONBIO failed: %s\n", strerror(errno));
588  return false;
589  }
590  return true;
591 }
592 
593 static struct net_stream* NET_DoConnect (const char* node, const char* service, const struct addrinfo* addr, int i, stream_onclose_func* onclose)
594 {
595  SOCKET sock = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
596  if (sock == INVALID_SOCKET) {
597  Com_Printf("Failed to create socket: %s\n", netStringError(netError));
598  return nullptr;
599  }
600 
601  if (!NET_SocketSetNonBlocking(sock)) {
602  netCloseSocket(sock);
603  return nullptr;
604  }
605 
606  if (connect(sock, addr->ai_addr, addr->ai_addrlen) != 0) {
607  const int err = netError;
608 #ifdef _WIN32
609  if (err != WSAEWOULDBLOCK) {
610 #else
611  if (err != EINPROGRESS) {
612 #endif
613  Com_Printf("Failed to start connection to %s:%s: %s\n", node, service, netStringError(err));
614  netCloseSocket(sock);
615  return nullptr;
616  }
617  }
618 
619  struct net_stream* s = NET_StreamNew(i);
620  s->socket = sock;
621  s->inbound = dbufferptr(new dbuffer(4096));
622  s->outbound = dbufferptr(new dbuffer(4096));
623  s->family = addr->ai_family;
624  s->addrlen = addr->ai_addrlen;
625  s->onclose = onclose;
626 
627  maxfd = std::max(sock + 1, maxfd);
628  FD_SET(sock, &read_fds);
629 
630  return s;
631 }
632 
644 struct net_stream* NET_Connect (const char* node, const char* service, stream_onclose_func* onclose)
645 {
646  struct addrinfo* res;
647  struct addrinfo hints;
648 
649  OBJZERO(hints);
650  hints.ai_flags = AI_ADDRCONFIG | AI_NUMERICSERV;
651  hints.ai_socktype = SOCK_STREAM;
652  /* force ipv4 */
653  if (net_ipv4->integer)
654  hints.ai_family = AF_INET;
655 
656  const int rc = getaddrinfo(node, service, &hints, &res);
657  if (rc != 0) {
658  Com_Printf("Failed to resolve host %s:%s: %s\n", node, service, gai_strerror(rc));
659  return nullptr;
660  }
661 
662  const int index = NET_StreamGetFree();
663  if (index == -1) {
664  Com_Printf("Failed to connect to host %s:%s, too many streams open\n", node, service);
665  freeaddrinfo(res);
666  return nullptr;
667  }
668 
669  struct net_stream* s = NET_DoConnect(node, service, res, index, onclose);
670 
671  freeaddrinfo(res);
672  return s;
673 }
674 
682 {
683  if (!server_running)
684  return nullptr;
685 
686  const int server_index = NET_StreamGetFree();
687  const int client_index = NET_StreamGetFree();
688 
689  if (server_index == -1 || client_index == -1 || server_index == client_index) {
690  Com_Printf("Failed to connect to loopback server, too many streams open\n");
691  return nullptr;
692  }
693 
694  struct net_stream* client = NET_StreamNew(client_index);
695  client->loopback = true;
696  client->inbound = dbufferptr(new dbuffer(4096));
697  client->outbound = dbufferptr(new dbuffer(4096));
698  client->onclose = onclose;
699 
700  struct net_stream* server = NET_StreamNew(server_index);
701  server->loopback = true;
702  server->inbound = client->outbound;
703  server->outbound = client->inbound;
704  server->func = server_func;
705  server->onclose = nullptr;
706 
707  client->loopback_peer = server;
708  server->loopback_peer = client;
709 
710  server_func(server);
711 
712  return client;
713 }
714 
719 void NET_StreamEnqueue (struct net_stream* s, const char* data, int len)
720 {
721  if (len <= 0 || !s || s->closed || s->finished)
722  return;
723 
724  if (s->outbound) {
725  const ScopedMutex scopedMutex(netMutex);
726  s->outbound->add(data, len);
727  }
728 
729  /* on linux, socket is int, and INVALID_SOCKET -1
730  * on windows it is unsigned and INVALID_SOCKET (~0)
731  * Let's hope that checking for INVALID_SOCKET is good enough for linux. */
732  //if (s->socket >= 0)
733  if (s->socket != INVALID_SOCKET)
734  FD_SET(s->socket, &write_fds);
735 
736  if (s->loopback_peer) {
737  loopback_ready = true;
738  s->loopback_peer->ready = true;
739  }
740 }
741 
745 static int NET_StreamPeek (struct net_stream* s, char* data, int len)
746 {
747  if (len <= 0 || !s)
748  return 0;
749 
750  const dbufferptr& dbuf = s->inbound;
751  if ((s->closed || s->finished) && dbuffer_len(dbuf) == 0)
752  return 0;
753 
754  return dbuf->get(data, len);
755 }
756 
760 int NET_StreamDequeue (struct net_stream* s, char* data, int len)
761 {
762  if (len <= 0 || !s || s->finished)
763  return 0;
764 
765  return s->inbound->extract(data, len);
766 }
767 
775 {
776  unsigned int v;
777  const ScopedMutex scopedMutex(netMutex);
778 
779  if (NET_StreamPeek(s, (char*)&v, 4) < 4)
780  return nullptr;
781 
782  int len = LittleLong(v);
783  if (NET_StreamGetLength(s) < (4 + len))
784  return nullptr;
785 
786  char tmp[256];
787  const int size = sizeof(tmp);
788  NET_StreamDequeue(s, tmp, 4);
789 
790  dbuffer* buf = new dbuffer();
791  while (len > 0) {
792  const int x = NET_StreamDequeue(s, tmp, std::min(len, size));
793  buf->add(tmp, x);
794  len -= x;
795  }
796 
797  return buf;
798 }
799 
800 void* NET_StreamGetData (struct net_stream* s)
801 {
802  return s ? s->data : nullptr;
803 }
804 
805 void NET_StreamSetData (struct net_stream* s, void* data)
806 {
807  if (!s)
808  return;
809  s->data = data;
810 }
811 
817 void NET_StreamFree (struct net_stream* s)
818 {
819  if (!s)
820  return;
821  s->finished = true;
822  NET_StreamClose(s);
823 }
824 
833 {
834  if (!s)
835  return;
836 
837  s->finished = true;
838 
839  if (s->socket != INVALID_SOCKET)
840  FD_CLR(s->socket, &read_fds);
841 
842  /* Stop the loopback peer from queueing stuff up in here */
843  if (s->loopback_peer)
845 
846  const ScopedMutex scopedMutex(netMutex);
847  s->inbound = dbufferptr();
848 
849  /* If there's nothing in the outbound buffer, any finished stream is
850  * ready to be closed */
851  if (dbuffer_len(s->outbound) == 0)
852  NET_StreamClose(s);
853 }
854 
859 const char* NET_StreamToString (struct net_stream* s)
860 {
861  static char node[64];
862  NET_StreamPeerToName(s, node, sizeof(node), false);
863  return node;
864 }
865 
872 const char* NET_StreamPeerToName (struct net_stream* s, char* dst, int len, bool appendPort)
873 {
874  if (!s)
875  return "(null)";
876 
877  if (NET_StreamIsLoopback(s))
878  return "loopback connection";
879 
880  char buf[128];
881  socklen_t addrlen = s->addrlen;
882  if (getpeername(s->socket, (struct sockaddr* )buf, &addrlen) != 0)
883  return "(error)";
884 
885  char node[64];
886  char service[64];
887  const int rc = getnameinfo((struct sockaddr* )buf, addrlen, node, sizeof(node), service, sizeof(service),
888  NI_NUMERICHOST | NI_NUMERICSERV);
889  if (rc != 0) {
890  Com_Printf("Failed to convert sockaddr to string: %s\n", gai_strerror(rc));
891  return "(error)";
892  }
893  if (!appendPort) {
894  Q_strncpyz(dst, node, len);
895  } else {
896  node[sizeof(node) - 1] = '\0';
897  service[sizeof(service) - 1] = '\0';
898  Com_sprintf(dst, len, "%s %s", node, service);
899  }
900  return dst;
901 }
902 
904 {
905  if (!s)
906  return;
907  s->func = func;
908 }
909 
911 {
912  return s && s->loopback;
913 }
914 
915 static int NET_DoStartServer (const struct addrinfo* addr)
916 {
917  SOCKET sock = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
918  int t = 1;
919 
920  if (sock == INVALID_SOCKET) {
921  Com_Printf("Failed to create socket: %s\n", netStringError(netError));
922  return INVALID_SOCKET;
923  }
924 
925  if (!NET_SocketSetNonBlocking(sock)) {
926  netCloseSocket(sock);
927  return INVALID_SOCKET;
928  }
929 
930 #ifdef _WIN32
931  if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char*) &t, sizeof(t)) != 0) {
932 #else
933  if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &t, sizeof(t)) != 0) {
934 #endif
935  Com_Printf("Failed to set SO_REUSEADDR on socket: %s\n", netStringError(netError));
936  netCloseSocket(sock);
937  return INVALID_SOCKET;
938  }
939 
940  if (bind(sock, addr->ai_addr, addr->ai_addrlen) != 0) {
941  Com_Printf("Failed to bind socket: %s\n", netStringError(netError));
942  netCloseSocket(sock);
943  return INVALID_SOCKET;
944  }
945 
946  if (listen(sock, SOMAXCONN) != 0) {
947  Com_Printf("Failed to listen on socket: %s\n", netStringError(netError));
948  netCloseSocket(sock);
949  return INVALID_SOCKET;
950  }
951 
952  maxfd = std::max(sock + 1, maxfd);
953  FD_SET(sock, &read_fds);
954  server_family = addr->ai_family;
955  server_addrlen = addr->ai_addrlen;
956 
957  return sock;
958 }
959 
960 static struct addrinfo* NET_GetAddrinfoForNode (const char* node, const char* service)
961 {
962  struct addrinfo* res;
963  struct addrinfo hints;
964 
965  OBJZERO(hints);
966  hints.ai_flags = AI_ADDRCONFIG | AI_PASSIVE;
967  hints.ai_socktype = SOCK_STREAM;
968  /* force ipv4 */
969  if (net_ipv4->integer)
970  hints.ai_family = AF_INET;
971 
972  const int rc = getaddrinfo(node, service, &hints, &res);
973  if (rc != 0) {
974  Com_Printf("Failed to resolve host %s:%s: %s\n", node ? node : "*", service, gai_strerror(rc));
975  return nullptr;
976  }
977 
978  return res;
979 }
980 
990 bool SV_Start (const char* node, const char* service, stream_callback_func* func)
991 {
992  if (!func)
993  return false;
994 
995  if (server_running) {
996  Com_Printf("SV_Start: Server is still running - call SV_Stop before\n");
997  return false;
998  }
999 
1000  if (service) {
1001  struct addrinfo* res = NET_GetAddrinfoForNode(node, service);
1002 
1003  if (!res)
1004  return false;
1005 
1007  if (server_socket == INVALID_SOCKET) {
1008  Com_Printf("Failed to start server on %s:%s\n", node ? node : "*", service);
1009  } else {
1010  server_running = true;
1011  server_func = func;
1012  }
1013  freeaddrinfo(res);
1014  } else {
1015  /* Loopback server only */
1016  server_running = true;
1017  server_func = func;
1018  }
1019 
1020  return server_running;
1021 }
1022 
1026 void SV_Stop (void)
1027 {
1028  server_running = false;
1029  server_func = nullptr;
1030  if (server_socket != INVALID_SOCKET) {
1031  FD_CLR(server_socket, &read_fds);
1033  }
1035 }
1036 
1040 static struct datagram_socket* NET_DatagramSocketDoNew (const struct addrinfo* addr)
1041 {
1042  const int index = NET_DatagramFindFreeSocket();
1043 
1044  if (index == -1) {
1045  Com_Printf("Too many datagram sockets open\n");
1046  return nullptr;
1047  }
1048 
1049  SOCKET sock = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
1050  if (sock == INVALID_SOCKET) {
1051  Com_Printf("Failed to create socket: %s\n", netStringError(netError));
1052  return nullptr;
1053  }
1054 
1055  if (!NET_SocketSetNonBlocking(sock)) {
1056  netCloseSocket(sock);
1057  return nullptr;
1058  }
1059 
1060  int socketOptTrue = 1;
1061  if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char*) &socketOptTrue, sizeof(socketOptTrue)) != 0) {
1062  Com_Printf("Failed to set SO_REUSEADDR on socket: %s\n", netStringError(netError));
1063  netCloseSocket(sock);
1064  return nullptr;
1065  }
1066 
1067  if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (char*) &socketOptTrue, sizeof(socketOptTrue)) != 0) {
1068  Com_Printf("Failed to set SO_BROADCAST on socket: %s\n", netStringError(netError));
1069  netCloseSocket(sock);
1070  return nullptr;
1071  }
1072 
1073  if (bind(sock, addr->ai_addr, addr->ai_addrlen) != 0) {
1074  Com_Printf("Failed to bind socket: %s\n", netStringError(netError));
1075  netCloseSocket(sock);
1076  return nullptr;
1077  }
1078 
1079  maxfd = std::max(sock + 1, maxfd);
1080  FD_SET(sock, &read_fds);
1081 
1083  s->family = addr->ai_family;
1084  s->addrlen = addr->ai_addrlen;
1085  s->socket = sock;
1086  s->index = index;
1087  s->queue = nullptr;
1088  s->queue_tail = &s->queue;
1089  s->func = nullptr;
1090  datagram_sockets[index] = s;
1091 
1092  return s;
1093 }
1094 
1102 struct datagram_socket* NET_DatagramSocketNew (const char* node, const char* service, datagram_callback_func* func)
1103 {
1104  struct addrinfo* res;
1105  struct addrinfo hints;
1106 
1107  if (!service || !func)
1108  return nullptr;
1109 
1110  OBJZERO(hints);
1111  hints.ai_flags = AI_NUMERICHOST | AI_ADDRCONFIG | AI_NUMERICSERV | AI_PASSIVE;
1112  hints.ai_socktype = SOCK_DGRAM;
1113  /* force ipv4 */
1114  if (net_ipv4->integer)
1115  hints.ai_family = AF_INET;
1116 
1117  const int rc = getaddrinfo(node, service, &hints, &res);
1118 
1119  if (rc != 0) {
1120  Com_Printf("Failed to resolve host %s:%s: %s\n", node ? node : "*", service, gai_strerror(rc));
1121  return nullptr;
1122  }
1123 
1124  struct datagram_socket* s = NET_DatagramSocketDoNew(res);
1125  if (s)
1126  s->func = func;
1127 
1128  freeaddrinfo(res);
1129  return s;
1130 }
1131 
1135 void NET_DatagramSend (struct datagram_socket* s, const char* buf, int len, struct sockaddr* to)
1136 {
1137  if (!s || len <= 0 || !buf || !to)
1138  return;
1139 
1141  dgram->msg = Mem_PoolAllocTypeN(char, len, com_networkPool);
1142  dgram->addr = Mem_PoolAllocTypeN(char, s->addrlen, com_networkPool);
1143  memcpy(dgram->msg, buf, len);
1144  memcpy(dgram->addr, to, len);
1145  dgram->len = len;
1146  dgram->next = nullptr;
1147 
1148  *s->queue_tail = dgram;
1149  s->queue_tail = &dgram->next;
1150 
1151  FD_SET(s->socket, &write_fds);
1152 }
1153 
1159 void NET_DatagramBroadcast (struct datagram_socket* s, const char* buf, int len, int port)
1160 {
1161  if (s->family == AF_INET) {
1162  struct sockaddr_in addr;
1163  addr.sin_family = AF_INET;
1164  addr.sin_port = htons(port);
1165  addr.sin_addr.s_addr = INADDR_BROADCAST;
1166  NET_DatagramSend(s, buf, len, (struct sockaddr* )&addr);
1167  } else if (s->family == AF_INET6) {
1168  struct sockaddr_in addr;
1169  addr.sin_family = AF_INET6;
1170  addr.sin_port = htons(port);
1171  addr.sin_addr.s_addr = INADDR_BROADCAST;
1172  NET_DatagramSend(s, buf, len, (struct sockaddr* )&addr);
1173  } else {
1174  Com_Error(ERR_DROP, "Broadcast unsupported on address family %d\n", s->family);
1175  }
1176 }
1177 
1183 {
1184  if (!s)
1185  return;
1186 
1187  FD_CLR(s->socket, &read_fds);
1188  FD_CLR(s->socket, &write_fds);
1189  netCloseSocket(s->socket);
1190 
1191  while (s->queue) {
1192  struct datagram* dgram = s->queue;
1193  s->queue = dgram->next;
1194  Mem_Free(dgram->msg);
1195  Mem_Free(dgram->addr);
1196  Mem_Free(dgram);
1197  }
1198 
1199  datagram_sockets[s->index] = nullptr;
1200  Mem_Free(s);
1201 }
1202 
1212 void NET_SockaddrToStrings (struct datagram_socket* s, struct sockaddr* addr, char* node, size_t nodelen, char* service, size_t servicelen)
1213 {
1214  const int rc = getnameinfo(addr, s->addrlen, node, nodelen, service, servicelen,
1215  NI_NUMERICHOST | NI_NUMERICSERV | NI_DGRAM);
1216  if (rc != 0) {
1217  Com_Printf("Failed to convert sockaddr to string: %s\n", gai_strerror(rc));
1218  Q_strncpyz(node, "(error)", nodelen);
1219  Q_strncpyz(service, "(error)", servicelen);
1220  }
1221 }
1222 
1223 static void NET_AddrinfoToString (const struct addrinfo* addr, char* buf, size_t bufLength)
1224 {
1225  char* service = inet_ntoa(((struct sockaddr_in*)addr->ai_addr)->sin_addr);
1226  Q_strncpyz(buf, service, bufLength);
1227 }
1228 
1229 bool NET_ResolvNode (const char* node, char* buf, size_t bufLength)
1230 {
1231  struct addrinfo* addrinfo = NET_GetAddrinfoForNode(node, nullptr);
1232  if (addrinfo == nullptr) {
1233  buf[0] = '\0';
1234  return false;
1235  }
1236  NET_AddrinfoToString(addrinfo, buf, bufLength);
1237  freeaddrinfo(addrinfo);
1238  return true;
1239 }
static cvar_t * net_ipv4
Definition: net.cpp:106
int NET_StreamDequeue(struct net_stream *s, char *data, int len)
Definition: net.cpp:760
static SOCKET server_socket
Definition: net.cpp:157
void NET_StreamFinished(struct net_stream *s)
Call NET_StreamFinished to mark the stream as uninteresting, but to finish sending any data in the bu...
Definition: net.cpp:832
void Cmd_AddCommand(const char *cmdName, xcommand_t function, const char *desc)
Add a new command to the script interface.
Definition: cmd.cpp:744
#define netStringError
Definition: net.cpp:72
bool loopback
Definition: net.cpp:112
void NET_SockaddrToStrings(struct datagram_socket *s, struct sockaddr *addr, char *node, size_t nodelen, char *service, size_t servicelen)
Convert sockaddr to string.
Definition: net.cpp:1212
static struct net_stream * NET_StreamNew(int index)
Definition: net.cpp:262
struct net_stream * NET_Connect(const char *node, const char *service, stream_onclose_func *onclose)
Try to connect to a given host on a given port.
Definition: net.cpp:644
void NET_Shutdown(void)
Definition: net.cpp:337
#define DEBUG_SERVER
Definition: defines.h:60
void NET_Init(void)
Definition: net.cpp:305
stream_callback_func * func
Definition: net.cpp:127
struct datagram_socket * NET_DatagramSocketNew(const char *node, const char *service, datagram_callback_func *func)
Opens a datagram socket (UDP)
Definition: net.cpp:1102
char * addr
Definition: net.cpp:134
This is a cvar definition. Cvars can be user modified and used in our menus e.g.
Definition: cvar.h:71
static void NET_ShowStreams_f(void)
Definition: net.cpp:284
void NET_Wait(int timeout)
Definition: net.cpp:423
void SV_Stop(void)
Definition: net.cpp:1026
bool SV_Start(const char *node, const char *service, stream_callback_func *func)
Definition: net.cpp:990
#define AI_NUMERICSERV
Definition: net.cpp:92
bool Com_sprintf(char *dest, size_t size, const char *fmt,...)
copies formatted string with buffer-size checking
Definition: shared.cpp:494
struct datagram * next
Definition: net.cpp:135
static int server_family
Definition: net.cpp:158
struct net_stream * NET_ConnectToLoopBack(stream_onclose_func *onclose)
Definition: net.cpp:681
void * data
Definition: net.cpp:110
struct net_stream * loopback_peer
Definition: net.cpp:128
static struct datagram_socket * NET_DatagramSocketDoNew(const struct addrinfo *addr)
Definition: net.cpp:1040
static stream_callback_func * server_func
Definition: net.cpp:156
#define dbuffer_len(dbuf)
Definition: net.cpp:104
dbufferptr outbound
Definition: net.cpp:124
void NET_StreamFree(struct net_stream *s)
Call NET_StreamFree to dump the whole thing right now.
Definition: net.cpp:817
#define netCloseSocket
Definition: net.cpp:73
void Com_Printf(const char *const fmt,...)
Definition: common.cpp:386
const char * NET_StreamToString(struct net_stream *s)
Returns the numerical representation of a net_stream.
Definition: net.cpp:859
stream_onclose_func * onclose
Definition: net.cpp:126
static int NET_DoStartServer(const struct addrinfo *addr)
Definition: net.cpp:915
static int NET_DatagramFindFreeSocket(void)
Definition: net.cpp:243
static int NET_StreamGetFree(void)
Definition: net.cpp:225
static struct net_stream * streams[MAX_STREAMS]
Definition: net.cpp:151
int integer
Definition: cvar.h:81
struct datagram ** queue_tail
Definition: net.cpp:144
#define MAX_DATAGRAM_SOCKETS
Definition: net.cpp:43
voidpf void * buf
Definition: ioapi.h:42
#define ERR_FATAL
Definition: common.h:210
#define CVAR_ARCHIVE
Definition: cvar.h:40
static void NET_StreamClose(struct net_stream *s)
Definition: net.cpp:350
#define netError
Definition: net.cpp:71
static SOCKET maxfd
Definition: net.cpp:150
void * NET_StreamGetData(struct net_stream *s)
Definition: net.cpp:800
void Com_Error(int code, const char *fmt,...)
Definition: common.cpp:417
#define INVALID_SOCKET
Definition: net.cpp:70
void NET_DatagramSend(struct datagram_socket *s, const char *buf, int len, struct sockaddr *to)
Definition: net.cpp:1135
int index
Definition: net.cpp:117
void Sys_Sleep(int milliseconds)
Calls the win32 sleep function.
Definition: unix_shared.cpp:68
void Q_strncpyz(char *dest, const char *src, size_t destsize)
Safe strncpy that ensures a trailing zero.
Definition: shared.cpp:457
void add(const char *, size_t)
Definition: dbuffer.cpp:42
static int server_addrlen
Definition: net.cpp:158
#define AI_ADDRCONFIG
Definition: net.cpp:95
void stream_callback_func(struct net_stream *s)
Definition: net.h:32
#define ERR_DROP
Definition: common.h:211
int family
Definition: net.cpp:118
cvar_t * Cvar_Get(const char *var_name, const char *var_value, int flags, const char *desc)
Init or return a cvar.
Definition: cvar.cpp:342
GLsizei size
Definition: r_gl.h:152
void NET_StreamEnqueue(struct net_stream *s, const char *data, int len)
Enqueue a network message into a stream.
Definition: net.cpp:719
int addrlen
Definition: net.cpp:119
#define OBJZERO(obj)
Definition: shared.h:178
struct datagram * queue
Definition: net.cpp:143
SharedPtr< dbuffer > dbufferptr
Definition: dbuffer.h:46
#define MAX_STREAMS
Definition: net.cpp:42
dbufferptr inbound
Definition: net.cpp:123
size_t extract(char *, size_t)
Read and delete data from a dbuffer.
Definition: dbuffer.cpp:136
static struct net_stream * NET_DoConnect(const char *node, const char *service, const struct addrinfo *addr, int i, stream_onclose_func *onclose)
Definition: net.cpp:593
SOCKET socket
Definition: net.cpp:116
void stream_onclose_func()
Definition: net.h:31
SOCKET socket
Definition: net.cpp:139
static fd_set write_fds
Definition: net.cpp:149
void Com_DPrintf(int level, const char *fmt,...)
A Com_Printf that only shows up if the "developer" cvar is set.
Definition: common.cpp:398
void datagram_callback_func(struct datagram_socket *s, const char *buf, int len, struct sockaddr *from)
Definition: net.h:33
bool closed
Definition: net.cpp:114
QGL_EXTERN GLuint index
Definition: r_gl.h:110
int SOCKET
Definition: net.cpp:69
static bool loopback_ready
Definition: net.cpp:154
static struct datagram_socket * datagram_sockets[MAX_DATAGRAM_SOCKETS]
Definition: net.cpp:152
#define Mem_PoolAllocTypeN(type, n, pool)
Definition: mem.h:42
char * msg
Definition: net.cpp:133
void NET_StreamSetData(struct net_stream *s, void *data)
Definition: net.cpp:805
static struct addrinfo * NET_GetAddrinfoForNode(const char *node, const char *service)
Definition: net.cpp:960
static int NET_StreamPeek(struct net_stream *s, char *data, int len)
Returns the length of the waiting inbound buffer.
Definition: net.cpp:745
size_t get(char *, size_t) const
Read data from a dbuffer.
Definition: dbuffer.cpp:61
memPool_t * com_networkPool
Definition: common.cpp:74
QGL_EXTERN GLint i
Definition: r_gl.h:113
QGL_EXTERN GLuint GLchar GLuint * len
Definition: r_gl.h:99
void NET_DatagramBroadcast(struct datagram_socket *s, const char *buf, int len, int port)
Definition: net.cpp:1159
void NET_DatagramSocketClose(struct datagram_socket *s)
Definition: net.cpp:1182
static void do_accept(SOCKET sock)
Definition: net.cpp:396
bool finished
Definition: net.cpp:115
#define Mem_Free(ptr)
Definition: mem.h:35
cvar_t * port
Definition: common.cpp:58
#define UFO_SIZE_T
Definition: ufotypes.h:89
size_t remove(size_t)
Deletes data from a dbuffer.
Definition: dbuffer.cpp:104
definitions common between client and server, but not game lib
bool NET_StreamIsLoopback(struct net_stream *s)
Definition: net.cpp:910
#define ioctlsocket
Definition: net.cpp:74
dbuffer * NET_ReadMsg(struct net_stream *s)
Reads messages from the network channel and adds them to the dbuffer where you can use the NET_Read* ...
Definition: net.cpp:774
GLsizei const GLvoid * data
Definition: r_gl.h:152
const char * NET_StreamPeerToName(struct net_stream *s, char *dst, int len, bool appendPort)
Definition: net.cpp:872
#define Mem_PoolAllocType(type, pool)
Definition: mem.h:43
static SDL_mutex * netMutex
Definition: net.cpp:107
void NET_StreamSetCallback(struct net_stream *s, stream_callback_func *func)
Definition: net.cpp:903
datagram_callback_func * func
Definition: net.cpp:145
static bool NET_SocketSetNonBlocking(SOCKET socketNum)
Definition: net.cpp:583
bool ready
Definition: net.cpp:113
QGL_EXTERN int GLboolean GLfloat * v
Definition: r_gl.h:120
static fd_set read_fds
Definition: net.cpp:148
static bool server_running
Definition: net.cpp:155
int len
Definition: net.cpp:132
static void NET_AddrinfoToString(const struct addrinfo *addr, char *buf, size_t bufLength)
Definition: net.cpp:1223
#define LittleLong(X)
Definition: byte.h:37
bool NET_ResolvNode(const char *node, char *buf, size_t bufLength)
Definition: net.cpp:1229
static int NET_StreamGetLength(struct net_stream *s)
Definition: net.cpp:214