Quake II RTX doxygen  1.0 dev
net.c
Go to the documentation of this file.
1 /*
2 Copyright (C) 1997-2001 Id Software, Inc.
3 
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
8 
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13 
14 You should have received a copy of the GNU General Public License along
15 with this program; if not, write to the Free Software Foundation, Inc.,
16 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 */
18 
19 //
20 // net.c
21 //
22 
23 #include "shared/shared.h"
24 #include "common/common.h"
25 #include "common/cvar.h"
26 #include "common/fifo.h"
27 #ifdef _DEBUG
28 #include "common/files.h"
29 #endif
30 #include "common/msg.h"
31 #include "common/net/net.h"
32 #include "common/protocol.h"
33 #include "common/zone.h"
34 #include "client/client.h"
35 #include "server/server.h"
36 #include "system/system.h"
37 
38 #ifdef _WIN32
39 #define WIN32_LEAN_AND_MEAN
40 #include <windows.h>
41 #include <winsock2.h>
42 #include <ws2tcpip.h>
43 #else // _WIN32
44 #include <unistd.h>
45 #include <sys/types.h>
46 #include <sys/socket.h>
47 #include <netinet/in.h>
48 #include <netdb.h>
49 #include <sys/param.h>
50 #include <sys/ioctl.h>
51 #include <arpa/inet.h>
52 #include <errno.h>
53 #ifdef __linux__
54 #include <linux/types.h>
55 #if USE_ICMP
56 #include <linux/errqueue.h>
57 #else
58 #undef IP_RECVERR
59 #undef IPV6_RECVERR
60 #endif
61 #endif // __linux__
62 #endif // !_WIN32
63 
64 // prevents infinite retry loops caused by broken TCP/IP stacks
65 #define MAX_ERROR_RETRIES 64
66 
67 #if USE_CLIENT
68 
69 #define MAX_LOOPBACK 4
70 
71 typedef struct {
72  byte data[MAX_PACKETLEN];
73  size_t datalen;
74 } loopmsg_t;
75 
76 typedef struct {
77  loopmsg_t msgs[MAX_LOOPBACK];
78  unsigned long get;
79  unsigned long send;
80 } loopback_t;
81 
82 static loopback_t loopbacks[NS_COUNT];
83 
84 #endif // USE_CLIENT
85 
86 cvar_t *net_ip;
87 cvar_t *net_ip6;
88 cvar_t *net_port;
89 
90 netadr_t net_from;
91 
92 #if USE_CLIENT
93 static cvar_t *net_clientport;
94 static cvar_t *net_dropsim;
95 #endif
96 
97 #ifdef _DEBUG
98 static cvar_t *net_log_enable;
99 static cvar_t *net_log_name;
100 static cvar_t *net_log_flush;
101 #endif
102 
103 static cvar_t *net_enable_ipv6;
104 
105 #if USE_ICMP
106 static cvar_t *net_ignore_icmp;
107 #endif
108 
109 static netflag_t net_active;
110 static int net_error;
111 
112 static qsocket_t udp_sockets[NS_COUNT] = { -1, -1 };
113 static qsocket_t tcp_socket = -1;
114 
115 static qsocket_t udp6_sockets[NS_COUNT] = { -1, -1 };
116 static qsocket_t tcp6_socket = -1;
117 
118 #ifdef _DEBUG
119 static qhandle_t net_logFile;
120 #endif
121 
122 static ioentry_t io_entries[FD_SETSIZE];
123 static int io_numfds;
124 
125 // current rate measurement
126 static unsigned net_rate_time;
127 static size_t net_rate_rcvd;
128 static size_t net_rate_sent;
129 static size_t net_rate_dn;
130 static size_t net_rate_up;
131 
132 // lifetime statistics
133 static uint64_t net_recv_errors;
134 static uint64_t net_send_errors;
135 #if USE_ICMP
136 static uint64_t net_icmp_errors;
137 #endif
138 static uint64_t net_bytes_rcvd;
139 static uint64_t net_bytes_sent;
140 static uint64_t net_packets_rcvd;
141 static uint64_t net_packets_sent;
142 
143 //=============================================================================
144 
145 static size_t NET_NetadrToSockadr(const netadr_t *a, struct sockaddr_storage *s)
146 {
147  struct sockaddr_in *s4 = (struct sockaddr_in *)s;
148  struct sockaddr_in6 *s6 = (struct sockaddr_in6 *)s;
149 
150  memset(s, 0, sizeof(*s));
151 
152  switch (a->type) {
153  case NA_BROADCAST:
154  s4->sin_family = AF_INET;
155  s4->sin_addr.s_addr = INADDR_BROADCAST;
156  s4->sin_port = a->port;
157  return sizeof(*s4);
158  case NA_IP:
159  s4->sin_family = AF_INET;
160  memcpy(&s4->sin_addr, &a->ip, 4);
161  s4->sin_port = a->port;
162  return sizeof(*s4);
163  case NA_IP6:
164  s6->sin6_family = AF_INET6;
165  memcpy(&s6->sin6_addr, &a->ip, 16);
166  s6->sin6_port = a->port;
167  s6->sin6_scope_id = a->scope_id;
168  return sizeof(*s6);
169  default:
170  break;
171  }
172 
173  return 0;
174 }
175 
176 static void NET_SockadrToNetadr(const struct sockaddr_storage *s, netadr_t *a)
177 {
178  const struct sockaddr_in *s4 = (const struct sockaddr_in *)s;
179  const struct sockaddr_in6 *s6 = (const struct sockaddr_in6 *)s;
180 
181  memset(a, 0, sizeof(*a));
182 
183  switch (s->ss_family) {
184  case AF_INET:
185  a->type = NA_IP;
186  memcpy(&a->ip, &s4->sin_addr, 4);
187  a->port = s4->sin_port;
188  break;
189  case AF_INET6:
190  if (IN6_IS_ADDR_V4MAPPED(&s6->sin6_addr)) {
191  a->type = NA_IP;
192  memcpy(&a->ip, &s6->sin6_addr.s6_addr[12], 4);
193  } else {
194  a->type = NA_IP6;
195  memcpy(&a->ip, &s6->sin6_addr, 16);
196  a->scope_id = s6->sin6_scope_id;
197  }
198  a->port = s6->sin6_port;
199  break;
200  default:
201  break;
202  }
203 }
204 
205 #ifdef _WIN32
206 #define NS_INT16SZ 2
207 #define NS_INADDRSZ 4
208 #define NS_IN6ADDRSZ 16
209 #include "inet_ntop.h"
210 #include "inet_pton.h"
211 #else
212 #define os_inet_ntop inet_ntop
213 #define os_inet_pton inet_pton
214 #endif
215 
216 char *NET_BaseAdrToString(const netadr_t *a)
217 {
218  static char s[MAX_QPATH];
219 
220  switch (a->type) {
221  case NA_UNSPECIFIED:
222  return strcpy(s, "<unspecified>");
223  case NA_LOOPBACK:
224  return strcpy(s, "loopback");
225  case NA_IP:
226  case NA_BROADCAST:
227  if (os_inet_ntop(AF_INET, &a->ip, s, sizeof(s)))
228  return s;
229  else
230  return strcpy(s, "<invalid>");
231  case NA_IP6:
232  if (a->scope_id) {
233  struct sockaddr_storage addr;
234  size_t addrlen;
235 
236  addrlen = NET_NetadrToSockadr(a, &addr);
237  if (getnameinfo((struct sockaddr *)&addr, addrlen,
238  s, sizeof(s), NULL, 0, NI_NUMERICHOST) == 0)
239  return s;
240  }
241  if (os_inet_ntop(AF_INET6, &a->ip, s, sizeof(s)))
242  return s;
243  else
244  return strcpy(s, "<invalid>");
245  default:
246  Com_Error(ERR_FATAL, "%s: bad address type", __func__);
247  }
248 
249  return NULL;
250 }
251 
252 /*
253 ===================
254 NET_AdrToString
255 ===================
256 */
257 char *NET_AdrToString(const netadr_t *a)
258 {
259  static char s[MAX_QPATH];
260 
261  switch (a->type) {
262  case NA_UNSPECIFIED:
263  return strcpy(s, "<unspecified>");
264  case NA_LOOPBACK:
265  return strcpy(s, "loopback");
266  default:
267  Q_snprintf(s, sizeof(s), (a->type == NA_IP6) ? "[%s]:%u" : "%s:%u",
268  NET_BaseAdrToString(a), BigShort(a->port));
269  }
270  return s;
271 }
272 
273 static struct addrinfo *NET_SearchAdrrInfo(struct addrinfo *rp, int family)
274 {
275  while (rp) {
276  if (rp->ai_family == family)
277  return rp;
278  rp = rp->ai_next;
279  }
280 
281  return NULL;
282 }
283 
284 qboolean NET_StringPairToAdr(const char *host, const char *port, netadr_t *a)
285 {
286  byte buf[128];
287  struct addrinfo hints, *res, *rp;
288  int err;
289 
290  memset(&hints, 0, sizeof(hints));
291 
292  if (net_enable_ipv6->integer < 1)
293  hints.ai_family = AF_INET;
294 
295  if (os_inet_pton(AF_INET, host, buf) == 1 ||
296  os_inet_pton(AF_INET6, host, buf) == 1)
297  hints.ai_flags |= AI_NUMERICHOST;
298 
299 #ifdef AI_NUMERICSERV
300  if (port && COM_IsUint(port))
301  hints.ai_flags |= AI_NUMERICSERV;
302 #endif
303 
304  err = getaddrinfo(host, port, &hints, &res);
305  if (err)
306  return qfalse;
307 
308  rp = res;
309  if (net_enable_ipv6->integer < 2) {
310  rp = NET_SearchAdrrInfo(res, AF_INET);
311  if (!rp)
312  rp = res;
313  }
314 
315  NET_SockadrToNetadr((struct sockaddr_storage *)rp->ai_addr, a);
316 
317  freeaddrinfo(res);
318  return qtrue;
319 }
320 
321 /*
322 =============
323 NET_StringToAdr
324 
325 localhost
326 idnewt
327 idnewt:28000
328 192.246.40.70
329 192.246.40.70:28000
330 =============
331 */
332 qboolean NET_StringToAdr(const char *s, netadr_t *a, int default_port)
333 {
334  char copy[MAX_STRING_CHARS], *h, *p;
335  size_t len;
336 
337  len = Q_strlcpy(copy, s, sizeof(copy));
338  if (len >= sizeof(copy))
339  return qfalse;
340 
341  // parse IPv6 address in square brackets
342  h = p = copy;
343  if (*h == '[') {
344  h++;
345  p = strchr(h, ']');
346  if (!p)
347  return qfalse;
348  *p++ = 0;
349  }
350 
351  // strip off a trailing :port if present
352  p = strchr(p, ':');
353  if (p)
354  *p++ = 0;
355 
356  if (!NET_StringPairToAdr(h, p, a))
357  return qfalse;
358 
359  if (!a->port)
360  a->port = BigShort(default_port);
361 
362  return qtrue;
363 }
364 
365 //=============================================================================
366 
367 #ifdef _DEBUG
368 
369 static void logfile_close(void)
370 {
371  if (!net_logFile) {
372  return;
373  }
374 
375  Com_Printf("Closing network log.\n");
376 
377  FS_FCloseFile(net_logFile);
378  net_logFile = 0;
379 }
380 
381 static void logfile_open(void)
382 {
383  char buffer[MAX_OSPATH];
384  unsigned mode;
385  qhandle_t f;
386 
387  mode = net_log_enable->integer > 1 ? FS_MODE_APPEND : FS_MODE_WRITE;
388  if (net_log_flush->integer > 0) {
389  if (net_log_flush->integer > 1) {
390  mode |= FS_BUF_NONE;
391  } else {
392  mode |= FS_BUF_LINE;
393  }
394  }
395 
396  f = FS_EasyOpenFile(buffer, sizeof(buffer), mode | FS_FLAG_TEXT,
397  "logs/", net_log_name->string, ".log");
398  if (!f) {
399  Cvar_Set("net_log_enable", "0");
400  return;
401  }
402 
403  net_logFile = f;
404  Com_Printf("Logging network packets to %s\n", buffer);
405 }
406 
407 static void net_log_enable_changed(cvar_t *self)
408 {
409  logfile_close();
410  if (self->integer) {
411  logfile_open();
412  }
413 }
414 
415 static void net_log_param_changed(cvar_t *self)
416 {
417  if (net_log_enable->integer) {
418  logfile_close();
419  logfile_open();
420  }
421 }
422 
423 /*
424 =============
425 NET_LogPacket
426 =============
427 */
428 static void NET_LogPacket(const netadr_t *address, const char *prefix,
429  const byte *data, size_t length)
430 {
431  int numRows;
432  int i, j, c;
433 
434  if (!net_logFile) {
435  return;
436  }
437 
438  FS_FPrintf(net_logFile, "%u : %s : %s : %"PRIz" bytes\n",
439  com_localTime, prefix, NET_AdrToString(address), length);
440 
441  numRows = (length + 15) / 16;
442  for (i = 0; i < numRows; i++) {
443  FS_FPrintf(net_logFile, "%04x : ", i * 16);
444  for (j = 0; j < 16; j++) {
445  if (i * 16 + j < length) {
446  FS_FPrintf(net_logFile, "%02x ", data[i * 16 + j]);
447  } else {
448  FS_FPrintf(net_logFile, " ");
449  }
450  }
451  FS_FPrintf(net_logFile, ": ");
452  for (j = 0; j < 16; j++) {
453  if (i * 16 + j < length) {
454  c = data[i * 16 + j];
455  FS_FPrintf(net_logFile, "%c", Q_isprint(c) ? c : '.');
456  } else {
457  FS_FPrintf(net_logFile, " ");
458  }
459  }
460  FS_FPrintf(net_logFile, "\n");
461  }
462 
463  FS_FPrintf(net_logFile, "\n");
464 }
465 
466 #endif
467 
468 //=============================================================================
469 
470 #define RATE_SECS 3
471 
472 void NET_UpdateStats(void)
473 {
474  unsigned diff;
475 
478  }
480  if (diff < RATE_SECS * 1000) {
481  return;
482  }
484 
487  net_rate_sent = 0;
488  net_rate_rcvd = 0;
489 }
490 
491 /*
492 ====================
493 NET_Stats_f
494 ====================
495 */
496 static void NET_Stats_f(void)
497 {
498  time_t diff, now = time(NULL);
499  char buffer[MAX_QPATH];
500 
501  if (com_startTime > now) {
502  com_startTime = now;
503  }
504  diff = now - com_startTime;
505  if (diff < 1) {
506  diff = 1;
507  }
508 
509  Com_FormatTime(buffer, sizeof(buffer), diff);
510  Com_Printf("Network uptime: %s\n", buffer);
511  Com_Printf("Bytes sent: %"PRIu64" (%"PRIu64" bytes/sec)\n",
513  Com_Printf("Bytes rcvd: %"PRIu64" (%"PRIu64" bytes/sec)\n",
515  Com_Printf("Packets sent: %"PRIu64" (%"PRIu64" packets/sec)\n",
517  Com_Printf("Packets rcvd: %"PRIu64" (%"PRIu64" packets/sec)\n",
519 #if USE_ICMP
520  Com_Printf("Total errors: %"PRIu64"/%"PRIu64"/%"PRIu64" (send/recv/icmp)\n",
521  net_send_errors, net_recv_errors, net_icmp_errors);
522 #else
523  Com_Printf("Total errors: %"PRIu64"/%"PRIu64" (send/recv)\n",
525 #endif
526  Com_Printf("Current upload rate: %"PRIz" bytes/sec\n", net_rate_up);
527  Com_Printf("Current download rate: %"PRIz" bytes/sec\n", net_rate_dn);
528 }
529 
530 static size_t NET_UpRate_m(char *buffer, size_t size)
531 {
532  return Q_scnprintf(buffer, size, "%"PRIz, net_rate_up);
533 }
534 
535 static size_t NET_DnRate_m(char *buffer, size_t size)
536 {
537  return Q_scnprintf(buffer, size, "%"PRIz, net_rate_dn);
538 }
539 
540 //=============================================================================
541 
542 #if USE_CLIENT
543 
544 static void NET_GetLoopPackets(netsrc_t sock, void (*packet_cb)(void))
545 {
546  loopback_t *loop;
547  loopmsg_t *loopmsg;
548 
549  loop = &loopbacks[sock];
550 
551  if (loop->send - loop->get > MAX_LOOPBACK - 1) {
552  loop->get = loop->send - MAX_LOOPBACK + 1;
553  }
554 
555  while (loop->get < loop->send) {
556  loopmsg = &loop->msgs[loop->get & (MAX_LOOPBACK - 1)];
557  loop->get++;
558 
559  memcpy(msg_read_buffer, loopmsg->data, loopmsg->datalen);
560 
561 #ifdef _DEBUG
562  if (net_log_enable->integer > 1) {
563  NET_LogPacket(&net_from, "LP recv", loopmsg->data, loopmsg->datalen);
564  }
565 #endif
566  if (sock == NS_CLIENT) {
567  net_rate_rcvd += loopmsg->datalen;
568  }
569 
571  msg_read.cursize = loopmsg->datalen;
572 
573  (*packet_cb)();
574  }
575 }
576 
577 static qboolean NET_SendLoopPacket(netsrc_t sock, const void *data,
578  size_t len, const netadr_t *to)
579 {
580  loopback_t *loop;
581  loopmsg_t *msg;
582 
583  if (net_dropsim->integer > 0 && (rand() % 100) < net_dropsim->integer) {
584  return qfalse;
585  }
586 
587  loop = &loopbacks[sock ^ 1];
588 
589  msg = &loop->msgs[loop->send & (MAX_LOOPBACK - 1)];
590  loop->send++;
591 
592  memcpy(msg->data, data, len);
593  msg->datalen = len;
594 
595 #ifdef _DEBUG
596  if (net_log_enable->integer > 1) {
597  NET_LogPacket(to, "LP send", data, len);
598  }
599 #endif
600  if (sock == NS_CLIENT) {
601  net_rate_sent += len;
602  }
603 
604  return qtrue;
605 }
606 
607 #endif // USE_CLIENT
608 
609 //=============================================================================
610 
611 #if USE_ICMP
612 
613 static const char *os_error_string(int err);
614 
615 static void NET_ErrorEvent(qsocket_t sock, netadr_t *from,
616  int ee_errno, int ee_info)
617 {
618  if (net_ignore_icmp->integer > 0) {
619  return;
620  }
621 
622  if (from->type == NA_UNSPECIFIED) {
623  return;
624  }
625 
626  Com_DPrintf("%s: %s from %s\n", __func__,
627  os_error_string(ee_errno), NET_AdrToString(from));
628  net_icmp_errors++;
629 
630  if (sock == udp_sockets[NS_SERVER] ||
631  sock == udp6_sockets[NS_SERVER]) {
632  SV_ErrorEvent(from, ee_errno, ee_info);
633  return;
634  }
635 
636  if (sock == udp_sockets[NS_CLIENT] ||
637  sock == udp6_sockets[NS_CLIENT]) {
638  CL_ErrorEvent(from);
639  return;
640  }
641 }
642 
643 #endif // USE_ICMP
644 
645 //=============================================================================
646 
647 // include our wrappers to hide platfrom-specific details
648 #ifdef _WIN32
649 #include "win.h"
650 #else
651 #include "unix.h"
652 #endif
653 
654 /*
655 =============
656 NET_ErrorString
657 =============
658 */
659 const char *NET_ErrorString(void)
660 {
661  return os_error_string(net_error);
662 }
663 
664 /*
665 =============
666 NET_AddFd
667 
668 Adds file descriptor to the list of monitored descriptors
669 =============
670 */
671 ioentry_t *NET_AddFd(qsocket_t fd)
672 {
673  ioentry_t *e = os_add_io(fd);
674 
675  e->inuse = qtrue;
676  return e;
677 }
678 
679 /*
680 =============
681 NET_RemoveFd
682 
683 Removes file descriptor from the list of monitored descriptors
684 =============
685 */
686 void NET_RemoveFd(qsocket_t fd)
687 {
688  ioentry_t *e = os_get_io(fd);
689  int i;
690 
691  memset(e, 0, sizeof(*e));
692 
693  for (i = io_numfds - 1; i >= 0; i--) {
694  e = &io_entries[i];
695  if (e->inuse) {
696  break;
697  }
698  }
699 
700  io_numfds = i + 1;
701 }
702 
703 /*
704 =============
705 NET_Sleep
706 
707 Sleeps msec or until some file descriptor is ready. Implementation is not
708 terribly efficient, but that's fine for a small number of descriptors we
709 typically have.
710 =============
711 */
712 int NET_Sleep(int msec)
713 {
714  struct timeval tv;
715  fd_set rfds, wfds, efds;
716  ioentry_t *e;
717  qsocket_t fd;
718  int i, ret;
719 
720  if (!io_numfds) {
721  // don't bother with select()
722  Sys_Sleep(msec);
723  return 0;
724  }
725 
726  FD_ZERO(&rfds);
727  FD_ZERO(&wfds);
728  FD_ZERO(&efds);
729 
730  for (i = 0, e = io_entries; i < io_numfds; i++, e++) {
731  if (!e->inuse) {
732  continue;
733  }
734  fd = os_get_fd(e);
735  e->canread = qfalse;
736  e->canwrite = qfalse;
737  e->canexcept = qfalse;
738  if (e->wantread) FD_SET(fd, &rfds);
739  if (e->wantwrite) FD_SET(fd, &wfds);
740  if (e->wantexcept) FD_SET(fd, &efds);
741  }
742 
743  tv.tv_sec = msec / 1000;
744  tv.tv_usec = (msec % 1000) * 1000;
745 
746  ret = os_select(io_numfds, &rfds, &wfds, &efds, &tv);
747  if (ret == -1) {
748  Com_EPrintf("%s: %s\n", __func__, NET_ErrorString());
749  return ret;
750  }
751 
752  if (ret == 0)
753  return ret;
754 
755  for (i = 0; i < io_numfds; i++) {
756  e = &io_entries[i];
757  if (!e->inuse) {
758  continue;
759  }
760  fd = os_get_fd(e);
761  if (FD_ISSET(fd, &rfds)) e->canread = qtrue;
762  if (FD_ISSET(fd, &wfds)) e->canwrite = qtrue;
763  if (FD_ISSET(fd, &efds)) e->canexcept = qtrue;
764  }
765 
766  return ret;
767 }
768 
769 #if USE_AC_SERVER
770 
771 /*
772 =============
773 NET_Sleepv
774 
775 Sleeps msec or until some file descriptor from a given subset is ready
776 =============
777 */
778 int NET_Sleepv(int msec, ...)
779 {
780  va_list argptr;
781  struct timeval tv;
782  fd_set rfds, wfds, efds;
783  ioentry_t *e;
784  qsocket_t fd;
785  int ret;
786 
787  FD_ZERO(&rfds);
788  FD_ZERO(&wfds);
789  FD_ZERO(&efds);
790 
791  va_start(argptr, msec);
792  while (1) {
793  fd = va_arg(argptr, qsocket_t);
794  if (fd == -1) {
795  break;
796  }
797  e = os_get_io(fd);
798  if (!e->inuse) {
799  continue;
800  }
801  e->canread = qfalse;
802  e->canwrite = qfalse;
803  e->canexcept = qfalse;
804  if (e->wantread) FD_SET(fd, &rfds);
805  if (e->wantwrite) FD_SET(fd, &wfds);
806  if (e->wantexcept) FD_SET(fd, &efds);
807  }
808  va_end(argptr);
809 
810  tv.tv_sec = msec / 1000;
811  tv.tv_usec = (msec % 1000) * 1000;
812 
813  ret = os_select(io_numfds, &rfds, &wfds, &efds, &tv);
814  if (ret == -1) {
815  Com_EPrintf("%s: %s\n", __func__, NET_ErrorString());
816  return ret;
817  }
818 
819  if (ret == 0)
820  return ret;
821 
822  va_start(argptr, msec);
823  while (1) {
824  fd = va_arg(argptr, qsocket_t);
825  if (fd == -1) {
826  break;
827  }
828  e = os_get_io(fd);
829  if (!e->inuse) {
830  continue;
831  }
832  if (FD_ISSET(fd, &rfds)) e->canread = qtrue;
833  if (FD_ISSET(fd, &wfds)) e->canwrite = qtrue;
834  if (FD_ISSET(fd, &efds)) e->canexcept = qtrue;
835  }
836  va_end(argptr);
837 
838  return ret;
839 }
840 
841 #endif // USE_AC_SERVER
842 
843 //=============================================================================
844 
845 static void NET_GetUdpPackets(qsocket_t sock, void (*packet_cb)(void))
846 {
847  ioentry_t *e;
848  ssize_t ret;
849 
850  if (sock == -1)
851  return;
852 
853  e = os_get_io(sock);
854  if (!e->canread)
855  return;
856 
857  while (1) {
858  ret = os_udp_recv(sock, msg_read_buffer, MAX_PACKETLEN, &net_from);
859  if (ret == NET_AGAIN) {
860  e->canread = qfalse;
861  break;
862  }
863 
864  if (ret == NET_ERROR) {
865  Com_DPrintf("%s: %s from %s\n", __func__,
867  net_recv_errors++;
868  break;
869  }
870 
871 #ifdef _DEBUG
872  if (net_log_enable->integer)
873  NET_LogPacket(&net_from, "UDP recv", msg_read_buffer, ret);
874 #endif
875 
876  net_rate_rcvd += ret;
877  net_bytes_rcvd += ret;
879 
881  msg_read.cursize = ret;
882 
883  (*packet_cb)();
884  }
885 }
886 
887 /*
888 =============
889 NET_GetPackets
890 
891 Fills msg_read_buffer with packet contents,
892 net_from variable receives source address.
893 =============
894 */
895 void NET_GetPackets(netsrc_t sock, void (*packet_cb)(void))
896 {
897 #if USE_CLIENT
898  memset(&net_from, 0, sizeof(net_from));
899  net_from.type = NA_LOOPBACK;
900 
901  // process loopback packets
902  NET_GetLoopPackets(sock, packet_cb);
903 #endif
904 
905  // process UDP packets
906  NET_GetUdpPackets(udp_sockets[sock], packet_cb);
907 
908  // process UDP6 packets
909  NET_GetUdpPackets(udp6_sockets[sock], packet_cb);
910 }
911 
912 /*
913 =============
914 NET_SendPacket
915 
916 =============
917 */
918 qboolean NET_SendPacket(netsrc_t sock, const void *data,
919  size_t len, const netadr_t *to)
920 {
921  ssize_t ret;
922  qsocket_t s;
923 
924  if (len == 0)
925  return qfalse;
926 
927  if (len > MAX_PACKETLEN) {
928  Com_EPrintf("%s: oversize packet to %s\n", __func__,
929  NET_AdrToString(to));
930  return qfalse;
931  }
932 
933  switch (to->type) {
934  case NA_UNSPECIFIED:
935  return qfalse;
936 #if USE_CLIENT
937  case NA_LOOPBACK:
938  return NET_SendLoopPacket(sock, data, len, to);
939 #endif
940  case NA_IP:
941  case NA_BROADCAST:
942  s = udp_sockets[sock];
943  break;
944  case NA_IP6:
945  s = udp6_sockets[sock];
946  break;
947  default:
948  Com_Error(ERR_FATAL, "%s: bad address type", __func__);
949  }
950 
951  if (s == -1)
952  return qfalse;
953 
954  ret = os_udp_send(s, data, len, to);
955  if (ret == NET_AGAIN)
956  return qfalse;
957 
958  if (ret == NET_ERROR) {
959  Com_DPrintf("%s: %s to %s\n", __func__,
961  net_send_errors++;
962  return qfalse;
963  }
964 
965  if (ret < len)
966  Com_WPrintf("%s: short send to %s\n", __func__,
967  NET_AdrToString(to));
968 
969 #ifdef _DEBUG
970  if (net_log_enable->integer)
971  NET_LogPacket(to, "UDP send", data, ret);
972 #endif
973 
974  net_rate_sent += ret;
975  net_bytes_sent += ret;
977 
978  return qtrue;
979 }
980 
981 //=============================================================================
982 
983 static qsocket_t UDP_OpenSocket(const char *iface, int port, int family)
984 {
985  qsocket_t s, newsocket;
986  struct addrinfo hints, *res, *rp;
987  char buf[MAX_QPATH];
988  const char *node, *service;
989  int err;
990 
991  Com_DPrintf("Opening UDP%s socket: %s:%d\n",
992  (family == AF_INET6) ? "6" : "", iface, port);
993 
994  memset(&hints, 0, sizeof(hints));
995  hints.ai_flags = AI_PASSIVE;
996  hints.ai_family = family;
997  hints.ai_socktype = SOCK_DGRAM;
998  hints.ai_protocol = IPPROTO_UDP;
999 
1000  // empty string binds to all interfaces
1001  if (!*iface) {
1002  node = NULL;
1003  } else {
1004  node = iface;
1005  }
1006 
1007  if (port == PORT_ANY) {
1008  service = "0";
1009  } else {
1010  Q_snprintf(buf, sizeof(buf), "%d", port);
1011  service = buf;
1012  }
1013 
1014 #ifdef AI_NUMERICSERV
1015  hints.ai_flags |= AI_NUMERICSERV;
1016 #endif
1017 
1018  // resolve iface addr
1019  err = getaddrinfo(node, service, &hints, &res);
1020  if (err) {
1021  Com_EPrintf("%s: %s:%d: bad interface address: %s\n",
1022  __func__, iface, port, gai_strerror(err));
1023  return -1;
1024  }
1025 
1026  newsocket = -1;
1027  for (rp = res; rp; rp = rp->ai_next) {
1028  s = os_socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
1029  if (s == -1) {
1030  Com_EPrintf("%s: %s:%d: can't create socket: %s\n",
1031  __func__, iface, port, NET_ErrorString());
1032  continue;
1033  }
1034 
1035  // make it non-blocking
1036  if (os_make_nonblock(s, 1)) {
1037  Com_EPrintf("%s: %s:%d: can't make socket non-blocking: %s\n",
1038  __func__, iface, port, NET_ErrorString());
1039  os_closesocket(s);
1040  continue;
1041  }
1042 
1043  if (rp->ai_family == AF_INET) {
1044  // make it broadcast capable
1045  if (os_setsockopt(s, SOL_SOCKET, SO_BROADCAST, 1)) {
1046  Com_WPrintf("%s: %s:%d: can't make socket broadcast capable: %s\n",
1047  __func__, iface, port, NET_ErrorString());
1048  }
1049 
1050 #ifdef IP_RECVERR
1051  // enable ICMP error queue
1052  if (os_setsockopt(s, IPPROTO_IP, IP_RECVERR, 1)) {
1053  Com_WPrintf("%s: %s:%d: can't enable ICMP error queue: %s\n",
1054  __func__, iface, port, NET_ErrorString());
1055  }
1056 #endif
1057 
1058 #ifdef IP_MTU_DISCOVER
1059  // allow IP fragmentation by disabling path MTU discovery
1060  if (os_setsockopt(s, IPPROTO_IP, IP_MTU_DISCOVER, IP_PMTUDISC_DONT)) {
1061  Com_WPrintf("%s: %s:%d: can't disable path MTU discovery: %s\n",
1062  __func__, iface, port, NET_ErrorString());
1063  }
1064 #endif
1065  }
1066 
1067  if (rp->ai_family == AF_INET6) {
1068 #ifdef IPV6_RECVERR
1069  // enable ICMP6 error queue
1070  if (os_setsockopt(s, IPPROTO_IPV6, IPV6_RECVERR, 1)) {
1071  Com_WPrintf("%s: %s:%d: can't enable ICMP6 error queue: %s\n",
1072  __func__, iface, port, NET_ErrorString());
1073  }
1074 #endif
1075 
1076 #ifdef IPV6_V6ONLY
1077  // disable IPv4-mapped addresses
1078  if (os_setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, 1)) {
1079  Com_WPrintf("%s: %s:%d: can't make socket IPv6-only: %s\n",
1080  __func__, iface, port, NET_ErrorString());
1081  }
1082 #endif
1083  }
1084 
1085  if (os_bind(s, rp->ai_addr, rp->ai_addrlen)) {
1086  Com_EPrintf("%s: %s:%d: can't bind socket: %s\n",
1087  __func__, iface, port, NET_ErrorString());
1088  os_closesocket(s);
1089  continue;
1090  }
1091 
1092  newsocket = s;
1093  break;
1094  }
1095 
1096  freeaddrinfo(res);
1097 
1098  return newsocket;
1099 }
1100 
1101 static qsocket_t TCP_OpenSocket(const char *iface, int port, int family, netsrc_t who)
1102 {
1103  qsocket_t s, newsocket;
1104  struct addrinfo hints, *res, *rp;
1105  char buf[MAX_QPATH];
1106  const char *node, *service;
1107  int err;
1108 
1109  Com_DPrintf("Opening TCP%s socket: %s:%d\n",
1110  (family == AF_INET6) ? "6" : "", iface, port);
1111 
1112  memset(&hints, 0, sizeof(hints));
1113  hints.ai_flags = AI_PASSIVE;
1114  hints.ai_family = family;
1115  hints.ai_socktype = SOCK_STREAM;
1116  hints.ai_protocol = IPPROTO_TCP;
1117 
1118  // empty string binds to all interfaces
1119  if (!*iface) {
1120  node = NULL;
1121  } else {
1122  node = iface;
1123  }
1124 
1125  if (port == PORT_ANY) {
1126  service = "0";
1127  } else {
1128  Q_snprintf(buf, sizeof(buf), "%d", port);
1129  service = buf;
1130  }
1131 
1132 #ifdef AI_NUMERICSERV
1133  hints.ai_flags |= AI_NUMERICSERV;
1134 #endif
1135 
1136  // resolve iface addr
1137  err = getaddrinfo(node, service, &hints, &res);
1138  if (err) {
1139  Com_EPrintf("%s: %s:%d: bad interface address: %s\n",
1140  __func__, iface, port, gai_strerror(err));
1141  return -1;
1142  }
1143 
1144  newsocket = -1;
1145  for (rp = res; rp; rp = rp->ai_next) {
1146  s = os_socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
1147  if (s == -1) {
1148  Com_EPrintf("%s: %s:%d: can't create socket: %s\n",
1149  __func__, iface, port, NET_ErrorString());
1150  continue;
1151  }
1152 
1153  // make it non-blocking
1154  if (os_make_nonblock(s, 1)) {
1155  Com_EPrintf("%s: %s:%d: can't make socket non-blocking: %s\n",
1156  __func__, iface, port, NET_ErrorString());
1157  os_closesocket(s);
1158  continue;
1159  }
1160 
1161  if (who == NS_SERVER) {
1162  // give it a chance to reuse previous port
1163  if (os_setsockopt(s, SOL_SOCKET, SO_REUSEADDR, 1)) {
1164  Com_WPrintf("%s: %s:%d: can't force socket to reuse address: %s\n",
1165  __func__, iface, port, NET_ErrorString());
1166  }
1167  }
1168 
1169  if (rp->ai_family == AF_INET6) {
1170 #ifdef IPV6_V6ONLY
1171  // disable IPv4-mapped addresses
1172  if (os_setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, 1)) {
1173  Com_WPrintf("%s: %s:%d: can't make socket IPv6-only: %s\n",
1174  __func__, iface, port, NET_ErrorString());
1175  }
1176 #endif
1177  }
1178 
1179  if (os_bind(s, rp->ai_addr, rp->ai_addrlen)) {
1180  Com_EPrintf("%s: %s:%d: can't bind socket: %s\n",
1181  __func__, iface, port, NET_ErrorString());
1182  os_closesocket(s);
1183  continue;
1184  }
1185 
1186  newsocket = s;
1187  break;
1188  }
1189 
1190  freeaddrinfo(res);
1191 
1192  return newsocket;
1193 }
1194 
1195 static void NET_OpenServer(void)
1196 {
1197  static int saved_port;
1198  ioentry_t *e;
1199  qsocket_t s;
1200 
1201  if (udp_sockets[NS_SERVER] != -1)
1202  return;
1203 
1204  s = UDP_OpenSocket(net_ip->string, net_port->integer, AF_INET);
1205  if (s != -1) {
1206  saved_port = net_port->integer;
1207  udp_sockets[NS_SERVER] = s;
1208  e = NET_AddFd(s);
1209  e->wantread = qtrue;
1210  return;
1211  }
1212 
1213  if (saved_port && saved_port != net_port->integer) {
1214  // revert to the last valid port
1215  Com_Printf("Reverting to the last valid port %d...\n", saved_port);
1216  Cbuf_AddText(&cmd_buffer, va("set net_port %d\n", saved_port));
1217  return;
1218  }
1219 
1220 #if USE_CLIENT
1221  if (!dedicated->integer) {
1222  Com_WPrintf("Couldn't open server UDP port.\n");
1223  return;
1224  }
1225 #endif
1226 
1227  Com_Error(ERR_FATAL, "Couldn't open dedicated server UDP port");
1228 }
1229 
1230 static void NET_OpenServer6(void)
1231 {
1232  ioentry_t *e;
1233  qsocket_t s;
1234 
1235  if (net_enable_ipv6->integer < 2)
1236  return;
1237 
1238  if (udp6_sockets[NS_SERVER] != -1)
1239  return;
1240 
1241  s = UDP_OpenSocket(net_ip6->string, net_port->integer, AF_INET6);
1242  if (s == -1)
1243  return;
1244 
1245  udp6_sockets[NS_SERVER] = s;
1246  e = NET_AddFd(s);
1247  e->wantread = qtrue;
1248 }
1249 
1250 #if USE_CLIENT
1251 static void NET_OpenClient(void)
1252 {
1253  ioentry_t *e;
1254  qsocket_t s;
1255  netadr_t adr;
1256 
1257  if (udp_sockets[NS_CLIENT] != -1)
1258  return;
1259 
1260  s = UDP_OpenSocket(net_ip->string, net_clientport->integer, AF_INET);
1261  if (s == -1) {
1262  // now try with random port
1263  if (net_clientport->integer != PORT_ANY)
1264  s = UDP_OpenSocket(net_ip->string, PORT_ANY, AF_INET);
1265 
1266  if (s == -1) {
1267  Com_WPrintf("Couldn't open client UDP port.\n");
1268  return;
1269  }
1270 
1271  if (os_getsockname(s, &adr)) {
1272  Com_EPrintf("Couldn't get client UDP socket name: %s\n", NET_ErrorString());
1273  os_closesocket(s);
1274  return;
1275  }
1276 
1277  Com_WPrintf("Client UDP socket bound to %s.\n", NET_AdrToString(&adr));
1278  Cvar_SetByVar(net_clientport, va("%d", PORT_ANY), FROM_CODE);
1279  }
1280 
1281  udp_sockets[NS_CLIENT] = s;
1282  e = NET_AddFd(s);
1283  e->wantread = qtrue;
1284 }
1285 
1286 static void NET_OpenClient6(void)
1287 {
1288  ioentry_t *e;
1289  qsocket_t s;
1290 
1291  if (net_enable_ipv6->integer < 1)
1292  return;
1293 
1294  if (udp6_sockets[NS_CLIENT] != -1)
1295  return;
1296 
1297  s = UDP_OpenSocket(net_ip6->string, net_clientport->integer, AF_INET6);
1298  if (s == -1)
1299  return;
1300 
1301  udp6_sockets[NS_CLIENT] = s;
1302  e = NET_AddFd(s);
1303  e->wantread = qtrue;
1304 }
1305 #endif
1306 
1307 /*
1308 ====================
1309 NET_Config
1310 ====================
1311 */
1312 void NET_Config(netflag_t flag)
1313 {
1314  netsrc_t sock;
1315 
1316  if (flag == net_active) {
1317  return;
1318  }
1319 
1320  if (flag == NET_NONE) {
1321  // shut down any existing sockets
1322  for (sock = 0; sock < NS_COUNT; sock++) {
1323  if (udp_sockets[sock] != -1) {
1324  NET_RemoveFd(udp_sockets[sock]);
1325  os_closesocket(udp_sockets[sock]);
1326  udp_sockets[sock] = -1;
1327  }
1328  if (udp6_sockets[sock] != -1) {
1329  NET_RemoveFd(udp6_sockets[sock]);
1331  udp6_sockets[sock] = -1;
1332  }
1333  }
1334  net_active = NET_NONE;
1335  return;
1336  }
1337 
1338 #if USE_CLIENT
1339  if (flag & NET_CLIENT) {
1340  NET_OpenClient();
1341  NET_OpenClient6();
1342  }
1343 #endif
1344 
1345  if (flag & NET_SERVER) {
1346  NET_OpenServer();
1347  NET_OpenServer6();
1348  }
1349 
1350  net_active |= flag;
1351 }
1352 
1353 /*
1354 ====================
1355 NET_GetAddress
1356 ====================
1357 */
1358 qboolean NET_GetAddress(netsrc_t sock, netadr_t *adr)
1359 {
1360  if (udp_sockets[sock] == -1)
1361  return qfalse;
1362 
1363  if (os_getsockname(udp_sockets[sock], adr))
1364  return qfalse;
1365 
1366  return qtrue;
1367 }
1368 
1369 //=============================================================================
1370 
1371 void NET_CloseStream(netstream_t *s)
1372 {
1373  if (!s->state) {
1374  return;
1375  }
1376 
1377  NET_RemoveFd(s->socket);
1378  os_closesocket(s->socket);
1379  s->socket = -1;
1380  s->state = NS_DISCONNECTED;
1381 }
1382 
1383 static neterr_t NET_Listen4(qboolean arg)
1384 {
1385  qsocket_t s;
1386  ioentry_t *e;
1387  neterr_t ret;
1388 
1389  if (!arg) {
1390  if (tcp_socket != -1) {
1393  tcp_socket = -1;
1394  }
1395  return NET_OK;
1396  }
1397 
1398  if (tcp_socket != -1) {
1399  return NET_AGAIN;
1400  }
1401 
1402  s = TCP_OpenSocket(net_ip->string, net_port->integer, AF_INET, NS_SERVER);
1403  if (s == -1) {
1404  return NET_ERROR;
1405  }
1406 
1407  ret = os_listen(s, 16);
1408  if (ret) {
1409  os_closesocket(s);
1410  return ret;
1411  }
1412 
1413  tcp_socket = s;
1414 
1415  // initialize io entry
1416  e = NET_AddFd(s);
1417  e->wantread = qtrue;
1418 
1419  return NET_OK;
1420 }
1421 
1422 static neterr_t NET_Listen6(qboolean arg)
1423 {
1424  qsocket_t s;
1425  ioentry_t *e;
1426  neterr_t ret;
1427 
1428  if (!arg) {
1429  if (tcp6_socket != -1) {
1432  tcp6_socket = -1;
1433  }
1434  return NET_OK;
1435  }
1436 
1437 
1438  if (tcp6_socket != -1) {
1439  return NET_AGAIN;
1440  }
1441 
1442  if (net_enable_ipv6->integer < 2) {
1443  return NET_AGAIN;
1444  }
1445 
1446  s = TCP_OpenSocket(net_ip6->string, net_port->integer, AF_INET6, NS_SERVER);
1447  if (s == -1) {
1448  return NET_ERROR;
1449  }
1450 
1451  ret = os_listen(s, 16);
1452  if (ret) {
1453  os_closesocket(s);
1454  return ret;
1455  }
1456 
1457  tcp6_socket = s;
1458 
1459  // initialize io entry
1460  e = NET_AddFd(s);
1461  e->wantread = qtrue;
1462 
1463  return NET_OK;
1464 }
1465 
1466 neterr_t NET_Listen(qboolean arg)
1467 {
1468  neterr_t ret4, ret6;
1469 
1470  ret4 = NET_Listen4(arg);
1471  ret6 = NET_Listen6(arg);
1472 
1473  if (ret4 == NET_OK || ret6 == NET_OK)
1474  return NET_OK;
1475 
1476  if (ret4 == NET_ERROR || ret6 == NET_ERROR)
1477  return NET_ERROR;
1478 
1479  return NET_AGAIN;
1480 }
1481 
1482 static neterr_t NET_AcceptSocket(netstream_t *s, qsocket_t sock)
1483 {
1484  ioentry_t *e;
1485  qsocket_t newsocket;
1486  neterr_t ret;
1487 
1488  if (sock == -1) {
1489  return NET_AGAIN;
1490  }
1491 
1492  e = os_get_io(sock);
1493  if (!e->canread) {
1494  return NET_AGAIN;
1495  }
1496 
1497  ret = os_accept(sock, &newsocket, &net_from);
1498  if (ret) {
1499  e->canread = qfalse;
1500  return ret;
1501  }
1502 
1503  // make it non-blocking
1504  ret = os_make_nonblock(newsocket, 1);
1505  if (ret) {
1506  os_closesocket(newsocket);
1507  return ret;
1508  }
1509 
1510  // initialize stream
1511  memset(s, 0, sizeof(*s));
1512  s->socket = newsocket;
1513  s->address = net_from;
1514  s->state = NS_CONNECTED;
1515 
1516  // initialize io entry
1517  e = NET_AddFd(newsocket);
1518  //e->wantwrite = qtrue;
1519  e->wantread = qtrue;
1520 
1521  return NET_OK;
1522 }
1523 
1524 // net_from variable receives source address
1525 neterr_t NET_Accept(netstream_t *s)
1526 {
1527  neterr_t ret;
1528 
1529  ret = NET_AcceptSocket(s, tcp_socket);
1530  if (ret == NET_AGAIN)
1531  ret = NET_AcceptSocket(s, tcp6_socket);
1532 
1533  return ret;
1534 }
1535 
1536 neterr_t NET_Connect(const netadr_t *peer, netstream_t *s)
1537 {
1538  qsocket_t socket;
1539  ioentry_t *e;
1540  neterr_t ret;
1541 
1542  // always bind to `net_ip' for outgoing TCP connections
1543  // to avoid problems with AC or MVD/GTV auth on a multi IP system
1544  switch (peer->type) {
1545  case NA_IP:
1546  socket = TCP_OpenSocket(net_ip->string, PORT_ANY, AF_INET, NS_CLIENT);
1547  break;
1548  case NA_IP6:
1549  socket = TCP_OpenSocket(net_ip6->string, PORT_ANY, AF_INET6, NS_CLIENT);
1550  break;
1551  default:
1552  return NET_ERROR;
1553  }
1554 
1555  if (socket == -1) {
1556  return NET_ERROR;
1557  }
1558 
1559  ret = os_connect(socket, peer);
1560  if (ret) {
1561  os_closesocket(socket);
1562  return NET_ERROR;
1563  }
1564 
1565  // initialize stream
1566  memset(s, 0, sizeof(*s));
1567  s->state = NS_CONNECTING;
1568  s->address = *peer;
1569  s->socket = socket;
1570 
1571  // initialize io entry
1572  e = NET_AddFd(socket);
1573  e->wantwrite = qtrue;
1574 #ifdef _WIN32
1575  e->wantexcept = qtrue;
1576 #endif
1577 
1578  return NET_OK;
1579 }
1580 
1581 neterr_t NET_RunConnect(netstream_t *s)
1582 {
1583  ioentry_t *e;
1584  neterr_t ret;
1585  int err;
1586 
1587  if (s->state != NS_CONNECTING) {
1588  return NET_AGAIN;
1589  }
1590 
1591  e = os_get_io(s->socket);
1592  if (!e->canwrite
1593 #ifdef _WIN32
1594  && !e->canexcept
1595 #endif
1596  ) {
1597  return NET_AGAIN;
1598  }
1599 
1600  ret = os_getsockopt(s->socket, SOL_SOCKET, SO_ERROR, &err);
1601  if (ret) {
1602  goto fail;
1603  }
1604  if (err) {
1605  net_error = err;
1606  goto fail;
1607  }
1608 
1609  s->state = NS_CONNECTED;
1610  e->wantwrite = qfalse;
1611  e->wantread = qtrue;
1612 #ifdef _WIN32
1613  e->wantexcept = qfalse;
1614 #endif
1615  return NET_OK;
1616 
1617 fail:
1618  s->state = NS_BROKEN;
1619  e->wantwrite = qfalse;
1620  e->wantread = qfalse;
1621 #ifdef _WIN32
1622  e->wantexcept = qfalse;
1623 #endif
1624  return NET_ERROR;
1625 }
1626 
1627 // updates wantread/wantwrite
1628 void NET_UpdateStream(netstream_t *s)
1629 {
1630  size_t len;
1631  ioentry_t *e;
1632 
1633  if (s->state != NS_CONNECTED) {
1634  return;
1635  }
1636 
1637  e = os_get_io(s->socket);
1638 
1639  FIFO_Reserve(&s->recv, &len);
1640  e->wantread = len ? qtrue : qfalse;
1641 
1642  FIFO_Peek(&s->send, &len);
1643  e->wantwrite = len ? qtrue : qfalse;
1644 }
1645 
1646 // returns NET_OK only when there was some data read
1647 neterr_t NET_RunStream(netstream_t *s)
1648 {
1649  ssize_t ret;
1650  size_t len;
1651  void *data;
1652  neterr_t result = NET_AGAIN;
1653  ioentry_t *e;
1654 
1655  if (s->state != NS_CONNECTED) {
1656  return result;
1657  }
1658 
1659  e = os_get_io(s->socket);
1660  if (e->wantread && e->canread) {
1661  // read as much as we can
1662  data = FIFO_Reserve(&s->recv, &len);
1663  if (len) {
1664  ret = os_recv(s->socket, data, len, 0);
1665  if (!ret) {
1666  goto closed;
1667  }
1668  if (ret == NET_ERROR) {
1669  goto error;
1670  }
1671  if (ret == NET_AGAIN) {
1672  // wouldblock is silent
1673  e->canread = qfalse;
1674  } else {
1675  FIFO_Commit(&s->recv, ret);
1676 #if _DEBUG
1677  if (net_log_enable->integer) {
1678  NET_LogPacket(&s->address, "TCP recv", data, ret);
1679  }
1680 #endif
1681  net_rate_rcvd += ret;
1682  net_bytes_rcvd += ret;
1683 
1684  result = NET_OK;
1685 
1686  // now see if there's more space to read
1687  FIFO_Reserve(&s->recv, &len);
1688  if (!len) {
1689  e->wantread = qfalse;
1690  }
1691  }
1692  }
1693  }
1694 
1695  if (e->wantwrite && e->canwrite) {
1696  // write as much as we can
1697  data = FIFO_Peek(&s->send, &len);
1698  if (len) {
1699  ret = os_send(s->socket, data, len, 0);
1700  if (!ret) {
1701  goto closed;
1702  }
1703  if (ret == NET_ERROR) {
1704  goto error;
1705  }
1706  if (ret == NET_AGAIN) {
1707  // wouldblock is silent
1708  e->canwrite = qfalse;
1709  } else {
1710  FIFO_Decommit(&s->send, ret);
1711 #if _DEBUG
1712  if (net_log_enable->integer) {
1713  NET_LogPacket(&s->address, "TCP send", data, ret);
1714  }
1715 #endif
1716  net_rate_sent += ret;
1717  net_bytes_sent += ret;
1718 
1719  //result = NET_OK;
1720 
1721  // now see if there's more data to write
1722  FIFO_Peek(&s->send, &len);
1723  if (!len) {
1724  e->wantwrite = qfalse;
1725  }
1726 
1727  }
1728  }
1729  }
1730 
1731  return result;
1732 
1733 closed:
1734  s->state = NS_CLOSED;
1735  e->wantread = qfalse;
1736  return NET_CLOSED;
1737 
1738 error:
1739  s->state = NS_BROKEN;
1740  e->wantread = qfalse;
1741  e->wantwrite = qfalse;
1742  return NET_ERROR;
1743 }
1744 
1745 //===================================================================
1746 
1747 static void dump_addrinfo(struct addrinfo *ai)
1748 {
1749  char buf1[MAX_QPATH], buf2[MAX_STRING_CHARS];
1750  char *fa = (ai->ai_addr->sa_family == AF_INET6) ? "6" : "";
1751 
1752  getnameinfo(ai->ai_addr, ai->ai_addrlen,
1753  buf1, sizeof(buf1), NULL, 0, NI_NUMERICHOST);
1754  if (getnameinfo(ai->ai_addr, ai->ai_addrlen,
1755  buf2, sizeof(buf2), NULL, 0, NI_NAMEREQD) == 0)
1756  Com_Printf("IP%1s : %s (%s)\n", fa, buf1, buf2);
1757  else
1758  Com_Printf("IP%1s : %s\n", fa, buf1);
1759 }
1760 
1761 static void dump_socket(qsocket_t s, const char *s1, const char *s2)
1762 {
1763  netadr_t adr;
1764 
1765  if (s == -1)
1766  return;
1767 
1768  if (os_getsockname(s, &adr)) {
1769  Com_EPrintf("Couldn't get %s %s socket name: %s\n",
1770  s1, s2, NET_ErrorString());
1771  return;
1772  }
1773 
1774  Com_Printf("%s %s socket bound to %s\n",
1775  s1, s2, NET_AdrToString(&adr));
1776 }
1777 
1778 /*
1779 ====================
1780 NET_ShowIP_f
1781 ====================
1782 */
1783 static void NET_ShowIP_f(void)
1784 {
1785  char buffer[MAX_STRING_CHARS];
1786  struct addrinfo hints, *res, *rp;
1787  int err;
1788 
1789  if (gethostname(buffer, sizeof(buffer)) == -1) {
1790  Com_EPrintf("Couldn't get system host name\n");
1791  return;
1792  }
1793 
1794  memset(&hints, 0, sizeof(hints));
1795  hints.ai_flags = AI_CANONNAME;
1796  hints.ai_socktype = SOCK_STREAM;
1797 
1798  if (net_enable_ipv6->integer < 1)
1799  hints.ai_family = AF_INET;
1800 
1801  err = getaddrinfo(buffer, NULL, &hints, &res);
1802  if (err) {
1803  Com_Printf("Couldn't resolve %s: %s\n", buffer, gai_strerror(err));
1804  return;
1805  }
1806 
1807  if (res->ai_canonname)
1808  Com_Printf("Hostname: %s\n", res->ai_canonname);
1809 
1810  for (rp = res; rp; rp = rp->ai_next)
1811  dump_addrinfo(rp);
1812 
1813  freeaddrinfo(res);
1814 
1815  // dump listening IP sockets
1816  dump_socket(udp_sockets[NS_CLIENT], "Client", "UDP");
1817  dump_socket(udp_sockets[NS_SERVER], "Server", "UDP");
1818  dump_socket(tcp_socket, "Server", "TCP");
1819 
1820  // dump listening IPv6 sockets
1821  dump_socket(udp6_sockets[NS_CLIENT], "Client", "UDP6");
1822  dump_socket(udp6_sockets[NS_SERVER], "Server", "UDP6");
1823  dump_socket(tcp6_socket, "Server", "TCP6");
1824 }
1825 
1826 /*
1827 ====================
1828 NET_Dns_f
1829 ====================
1830 */
1831 static void NET_Dns_f(void)
1832 {
1833  char buffer[MAX_STRING_CHARS], *h, *p;
1834  struct addrinfo hints, *res, *rp;
1835  int err;
1836 
1837  if (Cmd_Argc() != 2) {
1838  Com_Printf("Usage: %s <address>\n", Cmd_Argv(0));
1839  return;
1840  }
1841 
1842  Cmd_ArgvBuffer(1, buffer, sizeof(buffer));
1843 
1844  // parse IPv6 address square brackets
1845  h = p = buffer;
1846  if (*h == '[') {
1847  h++;
1848  p = strchr(h, ']');
1849  if (!p) {
1850  Com_Printf("Bad IPv6 address\n");
1851  return;
1852  }
1853  *p++ = 0;
1854  }
1855 
1856  // strip off a trailing :port if present
1857  p = strchr(p, ':');
1858  if (p)
1859  *p++ = 0;
1860 
1861  memset(&hints, 0, sizeof(hints));
1862  hints.ai_flags = AI_CANONNAME;
1863  hints.ai_socktype = SOCK_STREAM;
1864 
1865  if (net_enable_ipv6->integer < 1)
1866  hints.ai_family = AF_INET;
1867 
1868  err = getaddrinfo(h, NULL, &hints, &res);
1869  if (err) {
1870  Com_Printf("Couldn't resolve %s: %s\n", h, gai_strerror(err));
1871  return;
1872  }
1873 
1874  if (res->ai_canonname)
1875  Com_Printf("Hostname: %s\n", res->ai_canonname);
1876 
1877  for (rp = res; rp; rp = rp->ai_next)
1878  dump_addrinfo(rp);
1879 
1880  freeaddrinfo(res);
1881 }
1882 
1883 /*
1884 ====================
1885 NET_Restart_f
1886 ====================
1887 */
1888 static void NET_Restart_f(void)
1889 {
1890  netflag_t flag = net_active;
1891  qboolean listen4 = (tcp_socket != -1);
1892  qboolean listen6 = (tcp6_socket != -1);
1893 
1894  Com_DPrintf("%s\n", __func__);
1895 
1896  NET_Listen4(qfalse);
1897  NET_Listen6(qfalse);
1898  NET_Config(NET_NONE);
1899 
1900  listen6 |= listen4;
1901  listen6 &= net_enable_ipv6->integer > 1;
1902 
1903  NET_Config(flag);
1904  NET_Listen4(listen4);
1905  NET_Listen6(listen6);
1906 
1907 #if USE_SYSCON
1908  SV_SetConsoleTitle();
1909 #endif
1910 }
1911 
1912 static void net_udp_param_changed(cvar_t *self)
1913 {
1914  NET_Restart_f();
1915 }
1916 
1917 static const char *NET_EnableIP6(void)
1918 {
1919  qsocket_t s = os_socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP);
1920 
1921  if (s == -1)
1922  return "0";
1923 
1924  os_closesocket(s);
1925  return "1";
1926 }
1927 
1928 /*
1929 ====================
1930 NET_Init
1931 ====================
1932 */
1933 void NET_Init(void)
1934 {
1935  os_net_init();
1936 
1937  net_ip = Cvar_Get("net_ip", "", 0);
1938  net_ip->changed = net_udp_param_changed;
1939  net_ip6 = Cvar_Get("net_ip6", "", 0);
1940  net_ip6->changed = net_udp_param_changed;
1941  net_port = Cvar_Get("net_port", STRINGIFY(PORT_SERVER), 0);
1942  net_port->changed = net_udp_param_changed;
1943 
1944 #if USE_CLIENT
1945  net_clientport = Cvar_Get("net_clientport", STRINGIFY(PORT_ANY), 0);
1946  net_clientport->changed = net_udp_param_changed;
1947  net_dropsim = Cvar_Get("net_dropsim", "0", 0);
1948 #endif
1949 
1950 #if _DEBUG
1951  net_log_enable = Cvar_Get("net_log_enable", "0", 0);
1952  net_log_enable->changed = net_log_enable_changed;
1953  net_log_name = Cvar_Get("net_log_name", "network", 0);
1954  net_log_name->changed = net_log_param_changed;
1955  net_log_flush = Cvar_Get("net_log_flush", "0", 0);
1956  net_log_flush->changed = net_log_param_changed;
1957 #endif
1958 
1959  net_enable_ipv6 = Cvar_Get("net_enable_ipv6", NET_EnableIP6(), 0);
1961 
1962 #if USE_ICMP
1963  net_ignore_icmp = Cvar_Get("net_ignore_icmp", "0", 0);
1964 #endif
1965 
1966 #if _DEBUG
1967  net_log_enable_changed(net_log_enable);
1968 #endif
1969 
1971 
1972  Cmd_AddCommand("net_restart", NET_Restart_f);
1973  Cmd_AddCommand("net_stats", NET_Stats_f);
1974  Cmd_AddCommand("showip", NET_ShowIP_f);
1975  Cmd_AddCommand("dns", NET_Dns_f);
1976 
1977  Cmd_AddMacro("net_uprate", NET_UpRate_m);
1978  Cmd_AddMacro("net_dnrate", NET_DnRate_m);
1979 }
1980 
1981 /*
1982 ====================
1983 NET_Shutdown
1984 ====================
1985 */
1986 void NET_Shutdown(void)
1987 {
1988 #if _DEBUG
1989  logfile_close();
1990 #endif
1991 
1992  NET_Listen(qfalse);
1993  NET_Config(NET_NONE);
1994  os_net_shutdown();
1995 
1996  Cmd_RemoveCommand("net_restart");
1997  Cmd_RemoveCommand("net_stats");
1998  Cmd_RemoveCommand("showip");
1999  Cmd_RemoveCommand("dns");
2000 }
2001 
os_get_fd
static qsocket_t os_get_fd(ioentry_t *e)
Definition: unix.h:341
net_enable_ipv6
static cvar_t * net_enable_ipv6
Definition: net.c:103
NET_Listen4
static neterr_t NET_Listen4(qboolean arg)
Definition: net.c:1383
Cvar_Set
cvar_t * Cvar_Set(const char *var_name, const char *value)
Definition: cvar.c:466
FS_EasyOpenFile
qhandle_t FS_EasyOpenFile(char *buf, size_t size, unsigned mode, const char *dir, const char *name, const char *ext)
Definition: files.c:1846
os_recv
static ssize_t os_recv(qsocket_t sock, void *data, size_t len, int flags)
Definition: unix.h:175
NET_Init
void NET_Init(void)
Definition: net.c:1933
msg_read
sizebuf_t msg_read
Definition: msg.c:37
os_bind
static neterr_t os_bind(qsocket_t sock, const struct sockaddr *addr, size_t addrlen)
Definition: unix.h:276
NET_Connect
neterr_t NET_Connect(const netadr_t *peer, netstream_t *s)
Definition: net.c:1536
msg_read_buffer
byte msg_read_buffer[MAX_MSGLEN]
Definition: msg.c:38
NET_AdrToString
char * NET_AdrToString(const netadr_t *a)
Definition: net.c:257
os_getsockname
static neterr_t os_getsockname(qsocket_t sock, netadr_t *name)
Definition: unix.h:286
Q_snprintf
size_t Q_snprintf(char *dest, size_t size, const char *fmt,...)
Definition: shared.c:846
net_error
static int net_error
Definition: net.c:110
net_packets_rcvd
static uint64_t net_packets_rcvd
Definition: net.c:140
os_connect
static neterr_t os_connect(qsocket_t sock, const netadr_t *to)
Definition: unix.h:226
NET_EnableIP6
static const char * NET_EnableIP6(void)
Definition: net.c:1917
Cmd_AddCommand
void Cmd_AddCommand(const char *name, xcommand_t function)
Definition: cmd.c:1562
TCP_OpenSocket
static qsocket_t TCP_OpenSocket(const char *iface, int port, int family, netsrc_t who)
Definition: net.c:1101
unix.h
NET_RemoveFd
void NET_RemoveFd(qsocket_t fd)
Definition: net.c:686
NET_Dns_f
static void NET_Dns_f(void)
Definition: net.c:1831
Cvar_Get
cvar_t * Cvar_Get(const char *var_name, const char *var_value, int flags)
Definition: cvar.c:257
os_udp_recv
static ssize_t os_udp_recv(qsocket_t sock, void *data, size_t len, netadr_t *from)
Definition: unix.h:105
net_rate_sent
static size_t net_rate_sent
Definition: net.c:128
net_ip6
cvar_t * net_ip6
Definition: net.c:87
os_accept
static neterr_t os_accept(qsocket_t sock, qsocket_t *newsock, netadr_t *from)
Definition: unix.h:205
inet_pton.h
tcp6_socket
static qsocket_t tcp6_socket
Definition: net.c:116
net_bytes_rcvd
static uint64_t net_bytes_rcvd
Definition: net.c:138
os_closesocket
static void os_closesocket(qsocket_t sock)
Definition: unix.h:302
FS_FPrintf
ssize_t FS_FPrintf(qhandle_t f, const char *format,...)
Definition: files.c:2039
NET_UpdateStream
void NET_UpdateStream(netstream_t *s)
Definition: net.c:1628
NET_UpRate_m
static size_t NET_UpRate_m(char *buffer, size_t size)
Definition: net.c:530
os_get_io
static ioentry_t * os_get_io(qsocket_t fd)
Definition: unix.h:336
NET_RunConnect
neterr_t NET_RunConnect(netstream_t *s)
Definition: net.c:1581
NET_OpenServer6
static void NET_OpenServer6(void)
Definition: net.c:1230
tv
float * tv(float x, float y, float z)
Definition: g_utils.c:248
udp_sockets
static qsocket_t udp_sockets[NS_COUNT]
Definition: net.c:112
os_add_io
static ioentry_t * os_add_io(qsocket_t fd)
Definition: unix.h:327
NET_CloseStream
void NET_CloseStream(netstream_t *s)
Definition: net.c:1371
NET_DnRate_m
static size_t NET_DnRate_m(char *buffer, size_t size)
Definition: net.c:535
Cmd_Argv
char * Cmd_Argv(int arg)
Definition: cmd.c:899
os_error_string
static const char * os_error_string(int err)
Definition: unix.h:23
SZ_Init
void SZ_Init(sizebuf_t *buf, void *data, size_t size)
Definition: sizebuf.c:31
net_recv_errors
static uint64_t net_recv_errors
Definition: net.c:133
Cmd_Argc
int Cmd_Argc(void)
Definition: cmd.c:889
NET_Listen6
static neterr_t NET_Listen6(qboolean arg)
Definition: net.c:1422
net_from
netadr_t net_from
Definition: net.c:90
os_inet_pton
static int os_inet_pton(int af, const char *src, void *dst)
Definition: inet_pton.h:41
cmd_buffer
cmdbuf_t cmd_buffer
Definition: cmd.c:49
NET_Accept
neterr_t NET_Accept(netstream_t *s)
Definition: net.c:1525
NET_GetPackets
void NET_GetPackets(netsrc_t sock, void(*packet_cb)(void))
Definition: net.c:895
UDP_OpenSocket
static qsocket_t UDP_OpenSocket(const char *iface, int port, int family)
Definition: net.c:983
os_inet_ntop
static const char * os_inet_ntop(int af, const void *src, char *dst, size_t size)
Definition: inet_ntop.h:40
com_startTime
time_t com_startTime
Definition: common.c:125
Com_Error
void Com_Error(error_type_t type, const char *fmt,...)
Definition: g_main.c:258
dedicated
cvar_t * dedicated
Definition: g_main.c:46
Cmd_RemoveCommand
void Cmd_RemoveCommand(const char *name)
Definition: cmd.c:1593
NET_Listen
neterr_t NET_Listen(qboolean arg)
Definition: net.c:1466
io_numfds
static int io_numfds
Definition: net.c:123
NET_Stats_f
static void NET_Stats_f(void)
Definition: net.c:496
net_packets_sent
static uint64_t net_packets_sent
Definition: net.c:141
Com_FormatTime
size_t Com_FormatTime(char *buffer, size_t size, time_t t)
Definition: utils.c:391
NET_ErrorString
const char * NET_ErrorString(void)
Definition: net.c:659
inet_ntop.h
NET_BaseAdrToString
char * NET_BaseAdrToString(const netadr_t *a)
Definition: net.c:216
net_port
cvar_t * net_port
Definition: net.c:88
Cbuf_AddText
void Cbuf_AddText(cmdbuf_t *buf, const char *text)
Definition: cmd.c:95
va
char * va(const char *format,...)
Definition: shared.c:429
os_socket
static qsocket_t os_socket(int domain, int type, int protocol)
Definition: unix.h:307
net_bytes_sent
static uint64_t net_bytes_sent
Definition: net.c:139
NET_SearchAdrrInfo
static struct addrinfo * NET_SearchAdrrInfo(struct addrinfo *rp, int family)
Definition: net.c:273
logfile_close
static void logfile_close(void)
Definition: common.c:204
net_send_errors
static uint64_t net_send_errors
Definition: net.c:134
NET_SockadrToNetadr
static void NET_SockadrToNetadr(const struct sockaddr_storage *s, netadr_t *a)
Definition: net.c:176
NET_StringToAdr
qboolean NET_StringToAdr(const char *s, netadr_t *a, int default_port)
Definition: net.c:332
NET_Config
void NET_Config(netflag_t flag)
Definition: net.c:1312
Cvar_SetByVar
void Cvar_SetByVar(cvar_t *var, const char *value, from_t from)
Definition: cvar.c:345
Q_strlcpy
size_t Q_strlcpy(char *dst, const char *src, size_t size)
Definition: shared.c:715
NET_NetadrToSockadr
static size_t NET_NetadrToSockadr(const netadr_t *a, struct sockaddr_storage *s)
Definition: net.c:145
os_getsockopt
static neterr_t os_getsockopt(qsocket_t sock, int level, int name, int *val)
Definition: unix.h:264
os_send
static ssize_t os_send(qsocket_t sock, const void *data, size_t len, int flags)
Definition: unix.h:185
os_make_nonblock
static neterr_t os_make_nonblock(qsocket_t sock, int val)
Definition: unix.h:244
com_localTime
unsigned com_localTime
Definition: common.c:123
NET_GetAddress
qboolean NET_GetAddress(netsrc_t sock, netadr_t *adr)
Definition: net.c:1358
win.h
os_net_shutdown
static void os_net_shutdown(void)
Definition: unix.h:364
NET_OpenServer
static void NET_OpenServer(void)
Definition: net.c:1195
io_entries
static ioentry_t io_entries[FD_SETSIZE]
Definition: net.c:122
COM_IsUint
qboolean COM_IsUint(const char *s)
Definition: shared.c:330
c
statCounters_t c
Definition: main.c:30
NET_AddFd
ioentry_t * NET_AddFd(qsocket_t fd)
Definition: net.c:671
os_listen
static neterr_t os_listen(qsocket_t sock, int backlog)
Definition: unix.h:195
NET_ShowIP_f
static void NET_ShowIP_f(void)
Definition: net.c:1783
RATE_SECS
#define RATE_SECS
Definition: net.c:470
NET_SendPacket
qboolean NET_SendPacket(netsrc_t sock, const void *data, size_t len, const netadr_t *to)
Definition: net.c:918
NET_Shutdown
void NET_Shutdown(void)
Definition: net.c:1986
net_rate_rcvd
static size_t net_rate_rcvd
Definition: net.c:127
NET_GetUdpPackets
static void NET_GetUdpPackets(qsocket_t sock, void(*packet_cb)(void))
Definition: net.c:845
os_select
static int os_select(int nfds, fd_set *rfds, fd_set *wfds, fd_set *efds, struct timeval *tv)
Definition: unix.h:346
os_setsockopt
static neterr_t os_setsockopt(qsocket_t sock, int level, int name, int val)
Definition: unix.h:254
NET_StringPairToAdr
qboolean NET_StringPairToAdr(const char *host, const char *port, netadr_t *a)
Definition: net.c:284
Sys_Sleep
void Sys_Sleep(int msec)
Definition: system.c:653
diff
static q_noinline int diff(uint32_t A_u32, uint32_t B_u32)
Definition: hq2x.c:55
Cmd_ArgvBuffer
size_t Cmd_ArgvBuffer(int arg, char *buffer, size_t size)
Definition: cmd.c:912
NET_AcceptSocket
static neterr_t NET_AcceptSocket(netstream_t *s, qsocket_t sock)
Definition: net.c:1482
client.h
os_net_init
static void os_net_init(void)
Definition: unix.h:360
net_rate_time
static unsigned net_rate_time
Definition: net.c:126
err
int err
Definition: win.h:24
os_udp_send
static ssize_t os_udp_send(qsocket_t sock, const void *data, size_t len, const netadr_t *to)
Definition: unix.h:137
msg
const char * msg
Definition: win.h:25
net_rate_dn
static size_t net_rate_dn
Definition: net.c:129
NET_Restart_f
static void NET_Restart_f(void)
Definition: net.c:1888
Cmd_AddMacro
void Cmd_AddMacro(const char *name, xmacro_t function)
Definition: cmd.c:770
NET_UpdateStats
void NET_UpdateStats(void)
Definition: net.c:472
NET_RunStream
neterr_t NET_RunStream(netstream_t *s)
Definition: net.c:1647
FS_FCloseFile
void FS_FCloseFile(qhandle_t f)
Definition: files.c:759
net_ip
cvar_t * net_ip
Definition: net.c:86
NET_Sleep
int NET_Sleep(int msec)
Definition: net.c:712
server.h
tcp_socket
static qsocket_t tcp_socket
Definition: net.c:113
udp6_sockets
static qsocket_t udp6_sockets[NS_COUNT]
Definition: net.c:115
Q_scnprintf
size_t Q_scnprintf(char *dest, size_t size, const char *fmt,...)
Definition: shared.c:867
net_udp_param_changed
static void net_udp_param_changed(cvar_t *self)
Definition: net.c:1912
net_active
static netflag_t net_active
Definition: net.c:109
net_rate_up
static size_t net_rate_up
Definition: net.c:130
com_eventTime
unsigned com_eventTime
Definition: common.c:122
dump_socket
static void dump_socket(qsocket_t s, const char *s1, const char *s2)
Definition: net.c:1761
logfile_open
static void logfile_open(void)
Definition: common.c:216
dump_addrinfo
static void dump_addrinfo(struct addrinfo *ai)
Definition: net.c:1747