1 /*
2 Copyright (C) 1996-1997 Id Software, Inc.
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (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.
12
13 See the GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19
20 */
21 // net.c
22
23 #ifdef SERVERONLY
24 #include "qwsvdef.h"
25 #else
26 #include "quakedef.h"
27 #include "server.h"
28 #endif
29
30 #ifdef _WIN32
31 WSADATA winsockdata;
32 #endif
33
34 #ifndef SERVERONLY
35 netadr_t net_local_cl_ipadr;
36 #endif
37
38 #ifndef CLIENTONLY
39 netadr_t net_local_sv_ipadr;
40 netadr_t net_local_sv_tcpipadr;
41
42 cvar_t sv_local_addr = {"sv_local_addr", "", CVAR_ROM};
43 #endif
44
45 netadr_t net_from;
46 sizebuf_t net_message;
47
48 static byte net_message_buffer[MSG_BUF_SIZE];
49
50 // forward definition.
51 qbool NET_GetPacketEx (netsrc_t netsrc, qbool delay);
52 void NET_SendPacketEx (netsrc_t netsrc, int length, void *data, netadr_t to, qbool delay);
53
54 //=============================================================================
55 //
56 // LOOPBACK defs.
57 //
58
59 #define MAX_LOOPBACK 4 // must be a power of two
60
61 typedef struct
62 {
63 byte data[MSG_BUF_SIZE];
64 int datalen;
65 } loopmsg_t;
66
67 typedef struct
68 {
69 loopmsg_t msgs[MAX_LOOPBACK];
70 unsigned int get, send;
71 } loopback_t;
72
73 loopback_t loopbacks[2];
74
75 //=============================================================================
76 //
77 // Delayed packets, CLIENT ONLY.
78 //
79
80 #ifndef SERVERONLY
81
82 static cl_delayed_packet_t cl_delayed_packets_input[CL_MAX_DELAYED_PACKETS]; // from server to our client.
83 static cl_delayed_packet_t cl_delayed_packets_output[CL_MAX_DELAYED_PACKETS]; // from our client to server.
84
85 //
86 // Attempt to read packet from network and if succeed we put that packet in array/queue (so they are delayed).
87 // Packet will be unqued/extracted and used/parsed later, that depends of cl_delay_packet variable.
88 //
CL_QueInputPacket(void)89 void CL_QueInputPacket(void)
90 {
91 int i;
92
93 // read packets.
94 while (NET_GetPacketEx(NS_CLIENT, false))
95 {
96 // queue one packet.
97 for (i = 0; i < CL_MAX_DELAYED_PACKETS; i++)
98 {
99 if (cl_delayed_packets_input[i].time)
100 continue; // busy slot
101
102 // we found unused slot, copy packet, get it later, later depends of cl_delay_packet
103 memmove(cl_delayed_packets_input[i].data, net_message.data, net_message.cursize);
104 cl_delayed_packets_input[i].length = net_message.cursize;
105 cl_delayed_packets_input[i].addr = net_from;
106 cl_delayed_packets_input[i].time = Sys_DoubleTime() + 0.001 * bound(0, 0.5 * cl_delay_packet.value, CL_MAX_PACKET_DELAY);
107 break; // queued OK.
108 }
109
110 if (i >= CL_MAX_DELAYED_PACKETS)
111 {
112 Con_DPrintf("CL_QueInputPacket: cl_delayed_packets_input overflowed\n");
113 break;
114 }
115 }
116
117 return;
118 }
119
120 //
121 // Check if delayed output packets must be sent right now.
122 //
CL_UnqueOutputPacket(qbool sendall)123 void CL_UnqueOutputPacket(qbool sendall)
124 {
125 int i;
126 double time = Sys_DoubleTime();
127
128 for (i = 0; i < CL_MAX_DELAYED_PACKETS; i++)
129 {
130 if (!cl_delayed_packets_output[i].time)
131 continue; // unused slot
132 if (cl_delayed_packets_output[i].time > time && !sendall)
133 continue; // we are not yet ready for send
134
135 // ok, send it
136 NET_SendPacketEx(NS_CLIENT, cl_delayed_packets_output[i].length,
137 cl_delayed_packets_output[i].data, cl_delayed_packets_output[i].addr, false);
138
139 cl_delayed_packets_output[i].time = 0; // mark as unused slot
140
141 // perhaps there other packets should be sent
142 // return;
143 }
144 }
145
146 //
147 // Get packet from input queue.
148 //
NET_GetDelayedPacket(netsrc_t netsrc,netadr_t * from,sizebuf_t * message)149 qbool NET_GetDelayedPacket (netsrc_t netsrc, netadr_t *from, sizebuf_t *message)
150 {
151 int i;
152 double time = Sys_DoubleTime();
153
154 for (i = 0; i < CL_MAX_DELAYED_PACKETS; i++)
155 {
156 if (!cl_delayed_packets_input[i].time)
157 continue; // unused slot
158 if (cl_delayed_packets_input[i].time > time)
159 continue; // we are not yet ready to get this
160
161 // ok, we got something
162 SZ_Clear(message);
163 SZ_Write(message, cl_delayed_packets_input[i].data, cl_delayed_packets_input[i].length);
164 *from = cl_delayed_packets_input[i].addr;
165
166 cl_delayed_packets_input[i].time = 0; // mark as free slot
167
168 return true;
169 }
170
171 return false;
172 }
173
174 //
175 // Put packet in output queue.
176 //
NET_SendDelayedPacket(netsrc_t netsrc,int length,void * data,netadr_t to)177 void NET_SendDelayedPacket (netsrc_t netsrc, int length, void *data, netadr_t to)
178 {
179 int i;
180
181 for (i = 0; i < CL_MAX_DELAYED_PACKETS; i++)
182 {
183 if (cl_delayed_packets_output[i].time)
184 continue; // busy slot
185 // we found unused slot, copy packet, send it later, later depends of cl_delay_packet
186 memmove(cl_delayed_packets_output[i].data, data, length);
187 cl_delayed_packets_output[i].length = length;
188 cl_delayed_packets_output[i].addr = to;
189 cl_delayed_packets_output[i].time = Sys_DoubleTime() + 0.001 * bound(0, 0.5 * cl_delay_packet.value, CL_MAX_PACKET_DELAY);
190
191 return;
192 }
193
194 Con_DPrintf("NET_SendPacketEx: cl_delayed_packets_output overflowed\n");
195 return;
196 }
197
198 #endif
199
200 //=============================================================================
201 //
202 // Geters.
203 //
204
NET_UDPSVPort(void)205 int NET_UDPSVPort (void)
206 {
207 return ntohs(net_local_sv_ipadr.port);
208 }
209
NET_GetSocket(netsrc_t netsrc,qbool tcp)210 int NET_GetSocket(netsrc_t netsrc, qbool tcp)
211 {
212 if (netsrc == NS_SERVER)
213 {
214 #ifdef CLIENTONLY
215 Sys_Error("NET_GetPacket: Bad netsrc");
216 return INVALID_SOCKET;
217 #else
218 return tcp ? svs.sockettcp : svs.socketip;
219 #endif
220 }
221 else
222 {
223 #ifdef SERVERONLY
224 Sys_Error("NET_GetPacket: Bad netsrc");
225 return INVALID_SOCKET;
226 #else
227 return tcp ? cls.sockettcp : cls.socketip;
228 #endif
229 }
230 }
231
232 //=============================================================================
233 //
234 // Converters.
235 //
236
NetadrToSockadr(const netadr_t * a,struct sockaddr_storage * s)237 void NetadrToSockadr (const netadr_t *a, struct sockaddr_storage *s)
238 {
239 memset (s, 0, sizeof(struct sockaddr_in));
240 ((struct sockaddr_in*)s)->sin_family = AF_INET;
241
242 ((struct sockaddr_in*)s)->sin_addr.s_addr = *(int *)&a->ip;
243 ((struct sockaddr_in*)s)->sin_port = a->port;
244 }
245
SockadrToNetadr(const struct sockaddr_storage * s,netadr_t * a)246 void SockadrToNetadr (const struct sockaddr_storage *s, netadr_t *a)
247 {
248 a->type = NA_IP;
249 *(int *)&a->ip = ((struct sockaddr_in *)s)->sin_addr.s_addr;
250 a->port = ((struct sockaddr_in *)s)->sin_port;
251 return;
252 }
253
254 //=============================================================================
255 //
256 // Comparators.
257 //
258
NET_CompareBaseAdr(const netadr_t a,const netadr_t b)259 qbool NET_CompareBaseAdr (const netadr_t a, const netadr_t b)
260 {
261 #ifndef SERVERONLY
262 if (a.type == NA_LOOPBACK && b.type == NA_LOOPBACK)
263 return true;
264 #endif
265
266 // FIXME: Should we check a.type == b.type here ???
267
268 if (a.ip[0] == b.ip[0] && a.ip[1] == b.ip[1] && a.ip[2] == b.ip[2] && a.ip[3] == b.ip[3])
269 return true;
270 return false;
271 }
272
NET_CompareAdr(const netadr_t a,const netadr_t b)273 qbool NET_CompareAdr (const netadr_t a, const netadr_t b)
274 {
275 #ifndef SERVERONLY
276 if (a.type == NA_LOOPBACK && b.type == NA_LOOPBACK)
277 return true;
278 #endif
279
280 // FIXME: Should we check a.type == b.type here ???
281
282 if (a.ip[0] == b.ip[0] && a.ip[1] == b.ip[1] && a.ip[2] == b.ip[2] && a.ip[3] == b.ip[3] && a.port == b.port)
283 return true;
284 return false;
285 }
286
287 //=============================================================================
288 //
289 // Printors.
290 //
291
NET_AdrToString(const netadr_t a)292 char *NET_AdrToString (const netadr_t a)
293 {
294 static char s[MAX_STRINGS][32]; // 22 should be OK too
295 static int idx = 0;
296
297 idx %= MAX_STRINGS;
298
299 #ifndef SERVERONLY
300 if (a.type == NA_LOOPBACK)
301 {
302 snprintf (s[idx], sizeof(s[0]), "loopback");
303 }
304 else
305 #endif
306 {
307 snprintf (s[idx], sizeof(s[0]), "%i.%i.%i.%i:%i", a.ip[0], a.ip[1], a.ip[2], a.ip[3], ntohs (a.port));
308 }
309
310 return s[idx++];
311 }
312
NET_BaseAdrToString(const netadr_t a)313 char *NET_BaseAdrToString (const netadr_t a)
314 {
315 static char s[MAX_STRINGS][32]; // 22 should be OK too
316 static int idx = 0;
317
318 idx %= MAX_STRINGS;
319
320 #ifndef SERVERONLY
321 if (a.type == NA_LOOPBACK)
322 {
323 snprintf (s[idx], sizeof(s[0]), "loopback");
324 }
325 else
326 #endif
327 {
328 snprintf (s[idx], sizeof(s[0]), "%i.%i.%i.%i", a.ip[0], a.ip[1], a.ip[2], a.ip[3]);
329 }
330
331 return s[idx++];
332 }
333
334 // !!! Not used outside of the net.c !!!
NET_StringToSockaddr(const char * s,struct sockaddr_storage * sadr)335 static qbool NET_StringToSockaddr (const char *s, struct sockaddr_storage *sadr)
336 {
337 struct hostent *h;
338 char *colon;
339 char copy[128];
340
341 if (!(*s))
342 return false;
343
344 memset (sadr, 0, sizeof(*sadr));
345
346 ((struct sockaddr_in *)sadr)->sin_family = AF_INET;
347 ((struct sockaddr_in *)sadr)->sin_port = 0;
348
349 // can't resolve IP by hostname if hostname was truncated
350 if (strlcpy (copy, s, sizeof(copy)) >= sizeof(copy))
351 return false;
352
353 // strip off a trailing :port if present
354 for (colon = copy ; *colon ; colon++)
355 {
356 if (*colon == ':') {
357 *colon = 0;
358 ((struct sockaddr_in *)sadr)->sin_port = htons((short)atoi(colon+1));
359 }
360 }
361
362 //this is the wrong way to test. a server name may start with a number.
363 if (copy[0] >= '0' && copy[0] <= '9')
364 {
365 //this is the wrong way to test. a server name may start with a number.
366 *(int *)&((struct sockaddr_in *)sadr)->sin_addr = inet_addr(copy);
367 } else
368 {
369 if (!(h = gethostbyname(copy)))
370 return false;
371
372 if (h->h_addrtype != AF_INET)
373 return false;
374
375 *(int *)&((struct sockaddr_in *)sadr)->sin_addr = *(int *)h->h_addr_list[0];
376 }
377
378 return true;
379 }
380
NET_StringToAdr(const char * s,netadr_t * a)381 qbool NET_StringToAdr (const char *s, netadr_t *a)
382 {
383 struct sockaddr_storage sadr;
384
385 #ifndef SERVERONLY
386 if (!strcmp(s, "local"))
387 {
388 memset(a, 0, sizeof(*a));
389 a->type = NA_LOOPBACK;
390 return true;
391 }
392 #endif
393
394 if (!NET_StringToSockaddr (s, &sadr))
395 return false;
396
397 SockadrToNetadr (&sadr, a);
398
399 return true;
400 }
401
402 /*
403 =============================================================================
404 LOOPBACK BUFFERS FOR LOCAL PLAYER
405 =============================================================================
406 */
407
NET_GetLoopPacket(netsrc_t netsrc,netadr_t * from,sizebuf_t * message)408 qbool NET_GetLoopPacket (netsrc_t netsrc, netadr_t *from, sizebuf_t *message)
409 {
410 int i;
411 loopback_t *loop;
412
413 loop = &loopbacks[netsrc];
414
415 if (loop->send - loop->get > MAX_LOOPBACK)
416 loop->get = loop->send - MAX_LOOPBACK;
417
418 if (loop->get >= loop->send)
419 return false;
420
421 i = loop->get & (MAX_LOOPBACK-1);
422 loop->get++;
423
424 if (message->maxsize < loop->msgs[i].datalen)
425 Sys_Error("NET_SendLoopPacket: Loopback buffer was too big");
426
427 memcpy (message->data, loop->msgs[i].data, loop->msgs[i].datalen);
428 message->cursize = loop->msgs[i].datalen;
429 memset (from, 0, sizeof(*from));
430 from->type = NA_LOOPBACK;
431 return true;
432 }
433
NET_SendLoopPacket(netsrc_t netsrc,int length,void * data,netadr_t to)434 void NET_SendLoopPacket (netsrc_t netsrc, int length, void *data, netadr_t to)
435 {
436 int i;
437 loopback_t *loop;
438
439 loop = &loopbacks[netsrc ^ 1];
440
441 i = loop->send & (MAX_LOOPBACK - 1);
442 loop->send++;
443
444 if (length > (int) sizeof(loop->msgs[i].data))
445 Sys_Error ("NET_SendLoopPacket: length > %d", (int) sizeof(loop->msgs[i].data));
446
447 memcpy (loop->msgs[i].data, data, length);
448 loop->msgs[i].datalen = length;
449 }
450
NET_ClearLoopback(void)451 void NET_ClearLoopback (void)
452 {
453 loopbacks[0].send = loopbacks[0].get = 0;
454 loopbacks[1].send = loopbacks[1].get = 0;
455 }
456
457 //=============================================================================
458 //
459 // SV TCP connection.
460 //
461
462 // allocate, may link it in, if requested
sv_tcp_connection_new(int sock,netadr_t from,char * buf,int buf_len,qbool link)463 svtcpstream_t *sv_tcp_connection_new(int sock, netadr_t from, char *buf, int buf_len, qbool link)
464 {
465 svtcpstream_t *st = NULL;
466
467 st = Q_malloc(sizeof(svtcpstream_t));
468 st->waitingforprotocolconfirmation = true;
469 st->socketnum = sock;
470 st->remoteaddr = from;
471 if (buf_len > 0 && buf_len < sizeof(st->inbuffer))
472 {
473 memmove(st->inbuffer, buf, buf_len);
474 st->inlen = buf_len;
475 }
476 else
477 st->drop = true; // yeah, funny
478
479 // link it in if requested
480 if (link)
481 {
482 st->next = svs.tcpstreams;
483 svs.tcpstreams = st;
484 }
485
486 return st;
487 }
488
489 // free data, may unlink it out if requested
sv_tcp_connection_free(svtcpstream_t * drop,qbool unlink)490 static void sv_tcp_connection_free(svtcpstream_t *drop, qbool unlink)
491 {
492 if (!drop)
493 return; // someone kidding us
494
495 // unlink if requested
496 if (unlink)
497 {
498 if (svs.tcpstreams == drop)
499 {
500 svs.tcpstreams = svs.tcpstreams->next;
501 }
502 else
503 {
504 svtcpstream_t *st = NULL;
505
506 for (st = svs.tcpstreams; st; st = st->next)
507 {
508 if (st->next == drop)
509 {
510 st->next = st->next->next;
511 break;
512 }
513 }
514 }
515 }
516
517 // well, think socket may be zero, but most of the time zero is stdin fd, so better not close it
518 if (drop->socketnum && drop->socketnum != INVALID_SOCKET)
519 closesocket(drop->socketnum);
520
521 Q_free(drop);
522 }
523
sv_tcp_connection_count(void)524 int sv_tcp_connection_count(void)
525 {
526 svtcpstream_t *st = NULL;
527 int cnt = 0;
528
529 for (st = svs.tcpstreams; st; st = st->next)
530 cnt++;
531
532 return cnt;
533 }
534
535 //=============================================================================
536
NET_GetUDPPacket(netsrc_t netsrc,netadr_t * from_adr,sizebuf_t * message)537 qbool NET_GetUDPPacket (netsrc_t netsrc, netadr_t *from_adr, sizebuf_t *message)
538 {
539 int ret, err;
540 struct sockaddr_storage from = {0};
541 socklen_t fromlen;
542 int socket = NET_GetSocket(netsrc, false);
543
544 if (socket == INVALID_SOCKET)
545 return false;
546
547 fromlen = sizeof(from);
548 ret = recvfrom (socket, (char *)message->data, message->maxsize, 0, (struct sockaddr *)&from, &fromlen);
549 SockadrToNetadr (&from, from_adr);
550
551 if (ret == -1)
552 {
553 err = qerrno;
554
555 if (err == EWOULDBLOCK)
556 return false; // common error, does not spam in logs.
557
558 if (err == EMSGSIZE)
559 {
560 Con_DPrintf ("Warning: Oversize packet from %s\n", NET_AdrToString (*from_adr));
561 return false;
562 }
563
564 if (err == ECONNABORTED || err == ECONNRESET)
565 {
566 Con_DPrintf ("Connection lost or aborted\n");
567 return false;
568 }
569
570 Con_Printf ("NET_GetPacket: recvfrom: (%i): %s\n", err, strerror(err));
571 return false;
572 }
573
574 if (ret >= message->maxsize)
575 {
576 Con_Printf ("Oversize packet from %s\n", NET_AdrToString (*from_adr));
577 return false;
578 }
579
580 message->cursize = ret;
581
582 return ret;
583 }
584
585 #ifndef SERVERONLY
NET_GetTCPPacket_CL(netsrc_t netsrc,netadr_t * from,sizebuf_t * message)586 qbool NET_GetTCPPacket_CL (netsrc_t netsrc, netadr_t *from, sizebuf_t *message)
587 {
588 int ret, err;
589
590 if (netsrc != NS_CLIENT || cls.sockettcp == INVALID_SOCKET)
591 return false;
592
593 ret = recv(cls.sockettcp, (char *) cls.tcpinbuffer + cls.tcpinlen, sizeof(cls.tcpinbuffer) - cls.tcpinlen, 0);
594
595 // FIXME: should we check for ret == 0 for disconnect ???
596
597 if (ret == -1)
598 {
599 err = qerrno;
600
601 if (err == EWOULDBLOCK)
602 {
603 ret = 0; // hint for code below that it was not cricial error.
604 }
605 else if (err == ECONNABORTED || err == ECONNRESET)
606 {
607 Con_Printf ("Connection lost or aborted\n"); //server died/connection lost.
608 }
609 else
610 {
611 Con_Printf ("NET_GetPacket: Error (%i): %s\n", err, strerror(err));
612 }
613
614 if (ret)
615 {
616 // error detected, close socket then.
617 closesocket(cls.sockettcp);
618 cls.sockettcp = INVALID_SOCKET;
619 return false;
620 }
621 }
622
623 cls.tcpinlen += ret;
624
625 if (cls.tcpinlen < 2)
626 return false;
627
628 message->cursize = BigShort(*(short*)cls.tcpinbuffer);
629 if (message->cursize >= message->maxsize)
630 {
631 closesocket(cls.sockettcp);
632 cls.sockettcp = INVALID_SOCKET;
633 Con_Printf ("Warning: Oversize packet from %s\n", NET_AdrToString (cls.sockettcpdest));
634 return false;
635 }
636
637 if (message->cursize + 2 > cls.tcpinlen)
638 {
639 //not enough buffered to read a packet out of it.
640 return false;
641 }
642
643 memcpy(message->data, cls.tcpinbuffer + 2, message->cursize);
644 memmove(cls.tcpinbuffer, cls.tcpinbuffer + message->cursize + 2, cls.tcpinlen - (message->cursize + 2));
645 cls.tcpinlen -= message->cursize + 2;
646
647 *from = cls.sockettcpdest;
648
649 return true;
650 }
651 #endif
652
653 #ifndef CLIENTONLY
NET_GetTCPPacket_SV(netsrc_t netsrc,netadr_t * from,sizebuf_t * message)654 qbool NET_GetTCPPacket_SV (netsrc_t netsrc, netadr_t *from, sizebuf_t *message)
655 {
656 int ret;
657 float timeval = Sys_DoubleTime();
658 svtcpstream_t *st = NULL, *next = NULL;
659
660 if (netsrc != NS_SERVER)
661 return false;
662
663 for (st = svs.tcpstreams; st; st = next)
664 {
665 next = st->next;
666
667 *from = st->remoteaddr;
668
669 if (st->socketnum == INVALID_SOCKET || st->drop)
670 {
671 sv_tcp_connection_free(st, true); // free and unlink
672 continue;
673 }
674
675 //due to the above checks about invalid sockets, the socket is always open for st below.
676
677 // check for client timeout
678 if (st->timeouttime < timeval)
679 {
680 st->drop = true;
681 continue;
682 }
683
684 ret = recv(st->socketnum, st->inbuffer+st->inlen, sizeof(st->inbuffer)-st->inlen, 0);
685 if (ret == 0)
686 {
687 // connection closed
688 st->drop = true;
689 continue;
690 }
691 else if (ret == -1)
692 {
693 int err = qerrno;
694
695 if (err == EWOULDBLOCK)
696 {
697 ret = 0; // it's OK
698 }
699 else
700 {
701 if (err == ECONNABORTED || err == ECONNRESET)
702 {
703 Con_DPrintf ("Connection lost or aborted\n"); //server died/connection lost.
704 }
705 else
706 {
707 Con_DPrintf ("NET_GetPacket: Error (%i): %s\n", err, strerror(err));
708 }
709
710 st->drop = true;
711 continue;
712 }
713 }
714 else
715 {
716 // update timeout
717 st->timeouttime = Sys_DoubleTime() + 10;
718 }
719
720 st->inlen += ret;
721
722 if (st->waitingforprotocolconfirmation)
723 {
724 // not enough data
725 if (st->inlen < 6)
726 continue;
727
728 if (strncmp(st->inbuffer, "qizmo\n", 6))
729 {
730 Con_Printf ("Unknown TCP client\n");
731 st->drop = true;
732 continue;
733 }
734
735 // remove leading 6 bytes
736 memmove(st->inbuffer, st->inbuffer+6, st->inlen - (6));
737 st->inlen -= 6;
738 // confirmed
739 st->waitingforprotocolconfirmation = false;
740 }
741
742 // need two bytes for packet len
743 if (st->inlen < 2)
744 continue;
745
746 message->cursize = BigShort(*(short*)st->inbuffer);
747 if (message->cursize < 0)
748 {
749 message->cursize = 0;
750 Con_Printf ("Warning: malformed message from %s\n", NET_AdrToString (*from));
751 st->drop = true;
752 continue;
753 }
754
755 if (message->cursize >= message->maxsize)
756 {
757 Con_Printf ("Warning: Oversize packet from %s\n", NET_AdrToString (*from));
758 st->drop = true;
759 continue;
760 }
761
762 if (message->cursize + 2 > st->inlen)
763 {
764 //not enough buffered to read a packet out of it.
765 continue;
766 }
767
768 memcpy(message->data, st->inbuffer + 2, message->cursize);
769 memmove(st->inbuffer, st->inbuffer + message->cursize + 2, st->inlen - (message->cursize + 2));
770 st->inlen -= message->cursize + 2;
771
772 return true; // we got packet!
773 }
774
775 return false; // no packet received.
776 }
777 #endif
778
NET_GetPacketEx(netsrc_t netsrc,qbool delay)779 qbool NET_GetPacketEx (netsrc_t netsrc, qbool delay)
780 {
781 #ifndef SERVERONLY
782 if (delay)
783 return NET_GetDelayedPacket(netsrc, &net_from, &net_message);
784 #endif
785
786 #ifndef SERVERONLY
787 if (NET_GetLoopPacket(netsrc, &net_from, &net_message))
788 return true;
789 #endif
790
791 if (NET_GetUDPPacket(netsrc, &net_from, &net_message))
792 return true;
793
794 // TCPCONNECT -->
795 #ifndef SERVERONLY
796 if (netsrc == NS_CLIENT && cls.sockettcp != INVALID_SOCKET && NET_GetTCPPacket_CL(netsrc, &net_from, &net_message))
797 return true;
798 #endif
799
800 #ifndef CLIENTONLY
801 if (netsrc == NS_SERVER && svs.tcpstreams && NET_GetTCPPacket_SV(netsrc, &net_from, &net_message))
802 return true;
803 #endif
804 // <--TCPCONNECT
805
806 return false;
807 }
808
NET_GetPacket(netsrc_t netsrc)809 qbool NET_GetPacket (netsrc_t netsrc)
810 {
811 #ifdef SERVERONLY
812 qbool delay = false;
813 #else
814 qbool delay = (netsrc == NS_CLIENT && cl_delay_packet.integer);
815 #endif
816
817 return NET_GetPacketEx (netsrc, delay);
818 }
819
820 //=============================================================================
821
822 #ifndef SERVERONLY
NET_SendTCPPacket_CL(netsrc_t netsrc,int length,void * data,netadr_t to)823 qbool NET_SendTCPPacket_CL (netsrc_t netsrc, int length, void *data, netadr_t to)
824 {
825 unsigned short slen;
826
827 if (netsrc != NS_CLIENT || cls.sockettcp == INVALID_SOCKET)
828 return false;
829
830 if (!NET_CompareAdr(to, cls.sockettcpdest))
831 return false;
832
833 // this goes to the server so send it via TCP.
834 slen = BigShort((unsigned short)length);
835 // FIXME: CHECK send() result, we use NON BLOCKIN MODE, FFS!
836 send(cls.sockettcp, (char*)&slen, sizeof(slen), 0);
837 send(cls.sockettcp, data, length, 0);
838
839 return true;
840 }
841 #endif
842
843 #ifndef CLIENTONLY
NET_SendTCPPacket_SV(netsrc_t netsrc,int length,void * data,netadr_t to)844 qbool NET_SendTCPPacket_SV (netsrc_t netsrc, int length, void *data, netadr_t to)
845 {
846 svtcpstream_t *st;
847
848 if (netsrc != NS_SERVER)
849 return false;
850
851 for (st = svs.tcpstreams; st; st = st->next)
852 {
853 if (st->socketnum == INVALID_SOCKET)
854 continue;
855
856 if (NET_CompareAdr(to, st->remoteaddr))
857 {
858 int sent;
859 unsigned short slen = BigShort((unsigned short)length);
860
861 if (st->outlen + length + sizeof(slen) >= sizeof(st->outbuffer))
862 {
863 // not enough space, we overflowed
864 break; // well, quake should resist to some packet lost.. so we just drop that packet.
865 }
866
867 // put data in buffer
868 memmove(st->outbuffer + st->outlen, (char*)&slen, sizeof(slen));
869 st->outlen += sizeof(slen);
870 memmove(st->outbuffer + st->outlen, data, length);
871 st->outlen += length;
872
873 sent = send(st->socketnum, st->outbuffer, st->outlen, 0);
874
875 if (sent == 0)
876 {
877 // think it's OK
878 }
879 else if (sent > 0) //we put some data through
880 { //move up the buffer
881 st->outlen -= sent;
882 memmove(st->outbuffer, st->outbuffer + sent, st->outlen);
883 }
884 else
885 { //error of some kind. would block or something
886 if (qerrno != EWOULDBLOCK && qerrno != EAGAIN)
887 {
888 st->drop = true; // something cricial, drop than
889 }
890 }
891
892 break;
893 }
894 }
895
896 // 'st' will be not zero, if we found 'to' in 'svs.tcpstreams'.
897 // That does not mean we actualy send packet, since there case of overflow, but who cares,
898 // all is matter that we found such 'to' and tried to send packet.
899 return !!st;
900 }
901 #endif
902
NET_SendUDPPacket(netsrc_t netsrc,int length,void * data,netadr_t to)903 qbool NET_SendUDPPacket (netsrc_t netsrc, int length, void *data, netadr_t to)
904 {
905 struct sockaddr_storage addr;
906 int ret;
907 int socket = NET_GetSocket(netsrc, false);
908
909 if (socket == INVALID_SOCKET)
910 return false;
911
912 NetadrToSockadr (&to, &addr);
913
914 ret = sendto (socket, data, length, 0, (struct sockaddr *)&addr, sizeof(struct sockaddr_in));
915 if (ret == -1)
916 {
917 int err = qerrno;
918
919 if (err == EWOULDBLOCK || err == ECONNREFUSED || err == EADDRNOTAVAIL)
920 ; // nothing
921 else
922 Con_Printf ("NET_SendPacket: sendto: (%i): %s %i\n", err, strerror(err), socket);
923 }
924
925 return true;
926 }
927
NET_SendPacketEx(netsrc_t netsrc,int length,void * data,netadr_t to,qbool delay)928 void NET_SendPacketEx (netsrc_t netsrc, int length, void *data, netadr_t to, qbool delay)
929 {
930 #ifndef SERVERONLY
931 if (delay)
932 {
933 NET_SendDelayedPacket (netsrc, length, data, to);
934 return;
935 }
936 #endif
937
938 #ifndef SERVERONLY
939 if (to.type == NA_LOOPBACK)
940 {
941 NET_SendLoopPacket (netsrc, length, data, to);
942 return;
943 }
944 #endif
945
946 // TCPCONNECT -->
947 #ifndef SERVERONLY
948 if (netsrc == NS_CLIENT && cls.sockettcp != INVALID_SOCKET && NET_SendTCPPacket_CL(netsrc, length, data, to))
949 return;
950 #endif
951
952 #ifndef CLIENTONLY
953 if (netsrc == NS_SERVER && svs.tcpstreams && NET_SendTCPPacket_SV(netsrc, length, data, to))
954 return;
955 #endif
956 // <--TCPCONNECT
957
958 NET_SendUDPPacket(netsrc, length, data, to);
959 }
960
NET_SendPacket(netsrc_t netsrc,int length,void * data,netadr_t to)961 void NET_SendPacket (netsrc_t netsrc, int length, void *data, netadr_t to)
962 {
963 #ifdef SERVERONLY
964 qbool delay = false;
965 #else
966 qbool delay = (netsrc == NS_CLIENT && cl_delay_packet.integer);
967 #endif
968
969 NET_SendPacketEx (netsrc, length, data, to, delay);
970 }
971
972 //=============================================================================
973
TCP_Set_KEEPALIVE(int sock)974 qbool TCP_Set_KEEPALIVE(int sock)
975 {
976 int iOptVal = 1;
977
978 if (sock == INVALID_SOCKET)
979 {
980 Con_Printf("TCP_Set_KEEPALIVE: invalid socket\n");
981 return false;
982 }
983
984 if (setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (void*)&iOptVal, sizeof(iOptVal)) == SOCKET_ERROR)
985 {
986 Con_Printf ("TCP_Set_KEEPALIVE: setsockopt: (%i): %s\n", qerrno, strerror (qerrno));
987 return false;
988 }
989
990 #if defined(__linux__)
991
992 // The time (in seconds) the connection needs to remain idle before TCP starts sending keepalive probes,
993 // if the socket option SO_KEEPALIVE has been set on this socket.
994
995 iOptVal = 60;
996
997 if (setsockopt(sock, SOL_TCP, TCP_KEEPIDLE, (void*)&iOptVal, sizeof(iOptVal)) == -1)
998 {
999 Con_Printf ("TCP_Set_KEEPALIVE: setsockopt TCP_KEEPIDLE: (%i): %s\n", qerrno, strerror(qerrno));
1000 return false;
1001 }
1002
1003 // The time (in seconds) between individual keepalive probes.
1004 iOptVal = 30;
1005
1006 if (setsockopt(sock, SOL_TCP, TCP_KEEPINTVL, (void*)&iOptVal, sizeof(iOptVal)) == -1)
1007 {
1008 Con_Printf ("TCP_Set_KEEPALIVE: setsockopt TCP_KEEPINTVL: (%i): %s\n", qerrno, strerror(qerrno));
1009 return false;
1010 }
1011
1012 // The maximum number of keepalive probes TCP should send before dropping the connection.
1013 iOptVal = 6;
1014
1015 if (setsockopt(sock, SOL_TCP, TCP_KEEPCNT, (void*)&iOptVal, sizeof(iOptVal)) == -1)
1016 {
1017 Con_Printf ("TCP_Set_KEEPALIVE: setsockopt TCP_KEEPCNT: (%i): %s\n", qerrno, strerror(qerrno));
1018 return false;
1019 }
1020 #else
1021 // FIXME: windows, bsd etc...
1022 #endif
1023
1024 return true;
1025 }
1026
TCP_OpenStream(netadr_t remoteaddr)1027 int TCP_OpenStream (netadr_t remoteaddr)
1028 {
1029 unsigned long _true = true;
1030 int newsocket;
1031 int temp;
1032 struct sockaddr_storage qs;
1033
1034 NetadrToSockadr(&remoteaddr, &qs);
1035 temp = sizeof(struct sockaddr_in);
1036
1037 if ((newsocket = socket (((struct sockaddr_in*)&qs)->sin_family, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET)
1038 {
1039 Con_Printf ("TCP_OpenStream: socket: (%i): %s\n", qerrno, strerror(qerrno));
1040 return INVALID_SOCKET;
1041 }
1042
1043 if (connect (newsocket, (struct sockaddr *)&qs, temp) == INVALID_SOCKET)
1044 {
1045 Con_Printf ("TCP_OpenStream: connect: (%i): %s\n", qerrno, strerror(qerrno));
1046 closesocket(newsocket);
1047 return INVALID_SOCKET;
1048 }
1049
1050 #ifndef _WIN32
1051 if ((fcntl (newsocket, F_SETFL, O_NONBLOCK)) == -1)
1052 { // O'Rly?! @@@
1053 Con_Printf ("TCP_OpenStream: fcntl: (%i): %s\n", qerrno, strerror(qerrno));
1054 closesocket(newsocket);
1055 return INVALID_SOCKET;
1056 }
1057 #endif
1058
1059 if (ioctlsocket (newsocket, FIONBIO, &_true) == -1)
1060 { // make asynchronous
1061 Con_Printf ("TCP_OpenStream: ioctl: (%i): %s\n", qerrno, strerror(qerrno));
1062 closesocket(newsocket);
1063 return INVALID_SOCKET;
1064 }
1065
1066 return newsocket;
1067 }
1068
TCP_OpenListenSocket(unsigned short int port)1069 int TCP_OpenListenSocket (unsigned short int port)
1070 {
1071 int newsocket;
1072 struct sockaddr_in address = {0};
1073 unsigned long nonblocking = true;
1074 int i;
1075
1076 if ((newsocket = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET)
1077 {
1078 Con_Printf ("TCP_OpenListenSocket: socket: (%i): %s\n", qerrno, strerror(qerrno));
1079 return INVALID_SOCKET;
1080 }
1081
1082 if (ioctlsocket (newsocket, FIONBIO, &nonblocking) == -1)
1083 { // make asynchronous
1084 Con_Printf ("TCP_OpenListenSocket: ioctl: (%i): %s\n", qerrno, strerror(qerrno));
1085 closesocket(newsocket);
1086 return INVALID_SOCKET;
1087 }
1088
1089 #ifdef __APPLE__
1090 address.sin_len = sizeof(address); // apple are special...
1091 #endif
1092 address.sin_family = AF_INET;
1093
1094 // check for interface binding option
1095 if ((i = COM_CheckParm("-ip")) != 0 && i < COM_Argc())
1096 {
1097 address.sin_addr.s_addr = inet_addr(COM_Argv(i+1));
1098 Con_DPrintf ("Binding to IP Interface Address of %s\n", inet_ntoa(address.sin_addr));
1099 }
1100 else
1101 {
1102 address.sin_addr.s_addr = INADDR_ANY;
1103 }
1104
1105 if (port == PORT_ANY)
1106 address.sin_port = 0;
1107 else
1108 address.sin_port = htons(port);
1109
1110 if (bind (newsocket, (void *)&address, sizeof(address)) == -1)
1111 {
1112 Con_Printf ("TCP_OpenListenSocket: bind: (%i): %s\n", qerrno, strerror(qerrno));
1113 closesocket(newsocket);
1114 return INVALID_SOCKET;
1115 }
1116
1117 if (listen (newsocket, 2) == INVALID_SOCKET)
1118 {
1119 Con_Printf ("TCP_OpenListenSocket: listen: (%i): %s\n", qerrno, strerror(qerrno));
1120 closesocket(newsocket);
1121 return INVALID_SOCKET;
1122 }
1123
1124 if (!TCP_Set_KEEPALIVE(newsocket))
1125 {
1126 Con_Printf ("TCP_OpenListenSocket: TCP_Set_KEEPALIVE: failed\n");
1127 closesocket(newsocket);
1128 return INVALID_SOCKET;
1129 }
1130
1131 return newsocket;
1132 }
1133
UDP_OpenSocket(unsigned short int port)1134 int UDP_OpenSocket (unsigned short int port)
1135 {
1136 int newsocket;
1137 struct sockaddr_in address;
1138 unsigned long _true = true;
1139 int i;
1140
1141 if ((newsocket = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == INVALID_SOCKET)
1142 {
1143 Con_Printf ("UDP_OpenSocket: socket: (%i): %s\n", qerrno, strerror(qerrno));
1144 return INVALID_SOCKET;
1145 }
1146
1147 #ifndef _WIN32
1148 if ((fcntl (newsocket, F_SETFL, O_NONBLOCK)) == -1)
1149 { // O'Rly?! @@@
1150 Con_Printf ("UDP_OpenSocket: fcntl: (%i): %s\n", qerrno, strerror(qerrno));
1151 closesocket(newsocket);
1152 return INVALID_SOCKET;
1153 }
1154 #endif
1155
1156 if (ioctlsocket (newsocket, FIONBIO, &_true) == -1)
1157 { // make asynchronous
1158 Con_Printf ("UDP_OpenSocket: ioctl: (%i): %s\n", qerrno, strerror(qerrno));
1159 closesocket(newsocket);
1160 return INVALID_SOCKET;
1161 }
1162
1163 address.sin_family = AF_INET;
1164
1165 // check for interface binding option
1166 if ((i = COM_CheckParm("-ip")) != 0 && i < COM_Argc())
1167 {
1168 address.sin_addr.s_addr = inet_addr(COM_Argv(i+1));
1169 Con_DPrintf ("Binding to IP Interface Address of %s\n", inet_ntoa(address.sin_addr));
1170 }
1171 else
1172 {
1173 address.sin_addr.s_addr = INADDR_ANY;
1174 }
1175
1176 if (port == PORT_ANY)
1177 address.sin_port = 0;
1178 else
1179 address.sin_port = htons(port);
1180
1181 if (bind (newsocket, (void *)&address, sizeof(address)) == -1)
1182 {
1183 Con_Printf ("UDP_OpenSocket: bind: (%i): %s\n", qerrno, strerror(qerrno));
1184 closesocket(newsocket);
1185 return INVALID_SOCKET;
1186 }
1187
1188 return newsocket;
1189 }
1190
NET_Sleep(int msec,qbool stdinissocket)1191 qbool NET_Sleep(int msec, qbool stdinissocket)
1192 {
1193 struct timeval timeout;
1194 fd_set fdset;
1195 qbool stdin_ready = false;
1196 int maxfd = 0;
1197
1198 FD_ZERO (&fdset);
1199
1200 if (stdinissocket)
1201 {
1202 FD_SET (0, &fdset); // stdin is processed too (tends to be socket 0)
1203 maxfd = max(0, maxfd);
1204 }
1205
1206 if (svs.socketip != INVALID_SOCKET)
1207 {
1208 FD_SET(svs.socketip, &fdset); // network socket
1209 maxfd = max(svs.socketip, maxfd);
1210 }
1211
1212 timeout.tv_sec = msec/1000;
1213 timeout.tv_usec = (msec%1000)*1000;
1214 switch (select(maxfd + 1, &fdset, NULL, NULL, &timeout))
1215 {
1216 case -1: break;
1217 case 0: break;
1218 default:
1219
1220 if (stdinissocket)
1221 stdin_ready = FD_ISSET (0, &fdset);
1222
1223 break;
1224 }
1225
1226 return stdin_ready;
1227 }
1228
NET_GetLocalAddress(int socket,netadr_t * out)1229 void NET_GetLocalAddress (int socket, netadr_t *out)
1230 {
1231 char buff[512];
1232 struct sockaddr_storage address;
1233 size_t namelen;
1234 netadr_t adr = {0};
1235 qbool notvalid = false;
1236
1237 strlcpy (buff, "localhost", sizeof (buff));
1238 gethostname (buff, sizeof (buff));
1239 buff[sizeof(buff) - 1] = 0;
1240
1241 if (!NET_StringToAdr (buff, &adr)) //urm
1242 NET_StringToAdr ("127.0.0.1", &adr);
1243
1244 namelen = sizeof(address);
1245 if (getsockname (socket, (struct sockaddr *)&address, (socklen_t *)&namelen) == -1)
1246 {
1247 notvalid = true;
1248 NET_StringToSockaddr("0.0.0.0", (struct sockaddr_storage *)&address);
1249 // Sys_Error ("NET_Init: getsockname:", strerror(qerrno));
1250 }
1251
1252 SockadrToNetadr(&address, out);
1253 if (!*(int*)out->ip) //socket was set to auto
1254 *(int *)out->ip = *(int *)adr.ip; //change it to what the machine says it is, rather than the socket.
1255
1256 #ifndef SERVERONLY
1257 if (notvalid)
1258 Com_Printf_State (PRINT_FAIL, "Couldn't detect local ip\n");
1259 else
1260 Com_Printf_State (PRINT_OK, "IP address %s\n", NET_AdrToString (*out));
1261 #endif
1262 }
1263
NET_Init(void)1264 void NET_Init (void)
1265 {
1266 #ifdef _WIN32
1267 WORD wVersionRequested;
1268 int r;
1269
1270 wVersionRequested = MAKEWORD(1, 1);
1271 r = WSAStartup (wVersionRequested, &winsockdata);
1272 if (r)
1273 Sys_Error ("Winsock initialization failed.");
1274 #endif
1275
1276 // init the message buffer
1277 SZ_Init (&net_message, net_message_buffer, sizeof(net_message_buffer));
1278
1279 Con_DPrintf("UDP Initialized\n");
1280
1281 #ifndef SERVERONLY
1282 cls.socketip = INVALID_SOCKET;
1283 // TCPCONNECT -->
1284 cls.sockettcp = INVALID_SOCKET;
1285 // <--TCPCONNECT
1286 #endif
1287
1288 #ifndef CLIENTONLY
1289
1290 Cvar_Register (&sv_local_addr);
1291
1292 svs.socketip = INVALID_SOCKET;
1293 // TCPCONNECT -->
1294 svs.sockettcp = INVALID_SOCKET;
1295 // <--TCPCONNECT
1296 #endif
1297
1298 #ifdef SERVERONLY
1299 // As client+server we init it in SV_SpawnServer().
1300 // As serveronly we do it here.
1301 NET_InitServer();
1302 #endif
1303 }
1304
NET_Shutdown(void)1305 void NET_Shutdown (void)
1306 {
1307 #ifndef CLIENTONLY
1308 NET_CloseServer();
1309 #endif
1310
1311 #ifndef SERVERONLY
1312 NET_CloseClient();
1313 #endif
1314
1315 #ifdef _WIN32
1316 WSACleanup ();
1317 #endif
1318 }
1319
1320 #ifndef SERVERONLY
NET_InitClient(void)1321 void NET_InitClient(void)
1322 {
1323 int port = PORT_CLIENT;
1324 int p;
1325
1326 p = COM_CheckParm ("-clientport");
1327 if (p && p < COM_Argc())
1328 {
1329 port = atoi(COM_Argv(p+1));
1330 }
1331
1332 if (cls.socketip == INVALID_SOCKET)
1333 cls.socketip = UDP_OpenSocket (port);
1334
1335 if (cls.socketip == INVALID_SOCKET)
1336 cls.socketip = UDP_OpenSocket (PORT_ANY); // any dynamic port
1337
1338 if (cls.socketip == INVALID_SOCKET)
1339 Sys_Error ("Couldn't allocate client socket");
1340
1341 // determine my name & address
1342 NET_GetLocalAddress (cls.socketip, &net_local_cl_ipadr);
1343
1344 Com_Printf_State (PRINT_OK, "Client port Initialized\n");
1345 }
1346
NET_CloseClient(void)1347 void NET_CloseClient (void)
1348 {
1349 if (cls.socketip != INVALID_SOCKET)
1350 {
1351 closesocket(cls.socketip);
1352 cls.socketip = INVALID_SOCKET;
1353 }
1354
1355 // TCPCONNECT -->
1356 // FIXME: is it OK? Probably we should send disconnect?
1357 if (cls.sockettcp != INVALID_SOCKET)
1358 {
1359 closesocket(cls.sockettcp);
1360 cls.sockettcp = INVALID_SOCKET;
1361 }
1362 // <--TCPCONNECT
1363 }
1364
1365 #endif
1366
1367 #ifndef CLIENTONLY
1368
1369 //
1370 // Open server TCP port.
1371 // NOTE: Zero port will actually close already opened port.
1372 //
NET_InitServer_TCP(unsigned short int port)1373 void NET_InitServer_TCP(unsigned short int port)
1374 {
1375 // close socket first.
1376 if (svs.sockettcp != INVALID_SOCKET)
1377 {
1378 Con_Printf("Server TCP port closed\n");
1379 closesocket(svs.sockettcp);
1380 svs.sockettcp = INVALID_SOCKET;
1381 net_local_sv_tcpipadr.type = NA_INVALID;
1382 }
1383
1384 if (port)
1385 {
1386 svs.sockettcp = TCP_OpenListenSocket (port);
1387
1388 if (svs.sockettcp != INVALID_SOCKET)
1389 {
1390 // get local address.
1391 NET_GetLocalAddress (svs.sockettcp, &net_local_sv_tcpipadr);
1392 Con_Printf("Opening server TCP port %u\n", (unsigned int)port);
1393 }
1394 else
1395 {
1396 Con_Printf("Failed to open server TCP port %u\n", (unsigned int)port);
1397 }
1398 }
1399 }
1400
NET_InitServer(void)1401 void NET_InitServer (void)
1402 {
1403 int port = PORT_SERVER;
1404 int p;
1405
1406 p = COM_CheckParm ("-port");
1407 if (p && p < COM_Argc())
1408 {
1409 port = atoi(COM_Argv(p+1));
1410 }
1411
1412 if (svs.socketip == INVALID_SOCKET)
1413 {
1414 svs.socketip = UDP_OpenSocket (port);
1415 }
1416
1417 if (svs.socketip != INVALID_SOCKET)
1418 {
1419 NET_GetLocalAddress (svs.socketip, &net_local_sv_ipadr);
1420 Cvar_SetROM (&sv_local_addr, NET_AdrToString (net_local_sv_ipadr));
1421 }
1422 else
1423 {
1424 // FIXME: is it right???
1425 Cvar_SetROM (&sv_local_addr, "");
1426 }
1427
1428 // TCPCONNECT -->
1429 #if 0 // qqshka: TCP port shared with QTV now, so it opened outside here.
1430 p = COM_CheckParm ("-tcpport");
1431 if (p && p < COM_Argc())
1432 {
1433 NET_InitServer_TCP(atoi(COM_Argv(p+1)));
1434 }
1435 #endif
1436 // <-- TCPCONNECT
1437
1438 if (svs.socketip == INVALID_SOCKET)
1439 {
1440 #ifdef SERVERONLY
1441 Sys_Error
1442 #else
1443 Con_Printf
1444 #endif
1445 ("WARNING: Couldn't allocate server socket\n");
1446 }
1447 }
1448
NET_CloseServer(void)1449 void NET_CloseServer (void)
1450 {
1451 if (svs.socketip != INVALID_SOCKET)
1452 {
1453 closesocket(svs.socketip);
1454 svs.socketip = INVALID_SOCKET;
1455 }
1456
1457 net_local_sv_ipadr.type = NA_LOOPBACK; // FIXME: why not NA_INVALID?
1458
1459 // TCPCONNECT -->
1460 NET_InitServer_TCP(0);
1461 // <--TCPCONNECT
1462 }
1463 #endif
1464
1465