1 /*
2 Copyright (C) 1996-2001 Id Software, Inc.
3 Copyright (C) 2010-2014 QuakeSpasm developers
4
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either version 2
8 of the License, or (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13
14 See the GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19
20 */
21
22 #include "q_stdinc.h"
23 #include "arch_def.h"
24 #include "net_sys.h"
25 #include "quakedef.h"
26 #include "net_defs.h"
27
28 qsocket_t *net_activeSockets = NULL;
29 qsocket_t *net_freeSockets = NULL;
30 int net_numsockets = 0;
31
32 qboolean ipxAvailable = false;
33 qboolean ipv4Available = false;
34 qboolean ipv6Available = false;
35
36 int net_hostport;
37 int DEFAULTnet_hostport = 26000;
38
39 char my_ipx_address[NET_NAMELEN];
40 char my_ipv4_address[NET_NAMELEN];
41 char my_ipv6_address[NET_NAMELEN];
42
43 static qboolean listening = false;
44
45 qboolean slistInProgress = false;
46 qboolean slistSilent = false;
47 enum slistScope_e slistScope = SLIST_LOOP;
48 static double slistStartTime;
49 static double slistActiveTime;
50 static int slistLastShown;
51
52 static void Slist_Send (void *);
53 static void Slist_Poll (void *);
54 static PollProcedure slistSendProcedure = {NULL, 0.0, Slist_Send};
55 static PollProcedure slistPollProcedure = {NULL, 0.0, Slist_Poll};
56
57 sizebuf_t net_message;
58 int net_activeconnections = 0;
59
60 int messagesSent = 0;
61 int messagesReceived = 0;
62 int unreliableMessagesSent = 0;
63 int unreliableMessagesReceived = 0;
64
65 cvar_t net_messagetimeout = {"net_messagetimeout","300",CVAR_NONE};
66 cvar_t net_connecttimeout = {"net_connecttimeout","10",CVAR_NONE}; //this might be a little brief, but we don't have a way to protect against smurf attacks.
67 cvar_t hostname = {"hostname", "UNNAMED", CVAR_SERVERINFO};
68
69 // these two macros are to make the code more readable
70 #define sfunc net_drivers[sock->driver]
71 #define dfunc net_drivers[net_driverlevel]
72
73 int net_driverlevel;
74
75 double net_time;
76
77
SetNetTime(void)78 double SetNetTime (void)
79 {
80 net_time = Sys_DoubleTime();
81 return net_time;
82 }
83
84
85 /*
86 ===================
87 NET_NewQSocket
88
89 Called by drivers when a new communications endpoint is required
90 The sequence and buffer fields will be filled in properly
91 ===================
92 */
NET_NewQSocket(void)93 qsocket_t *NET_NewQSocket (void)
94 {
95 qsocket_t *sock;
96
97 if (net_freeSockets == NULL)
98 return NULL;
99
100 if (net_activeconnections >= svs.maxclients)
101 return NULL;
102
103 // get one from free list
104 sock = net_freeSockets;
105 net_freeSockets = sock->next;
106
107 // add it to active list
108 sock->next = net_activeSockets;
109 net_activeSockets = sock;
110
111 sock->isvirtual = false;
112 sock->disconnected = false;
113 sock->connecttime = net_time;
114 Q_strcpy (sock->trueaddress,"UNSET ADDRESS");
115 Q_strcpy (sock->maskedaddress,"UNSET ADDRESS");
116 sock->driver = net_driverlevel;
117 sock->socket = 0;
118 sock->driverdata = NULL;
119 sock->canSend = true;
120 sock->sendNext = false;
121 sock->lastMessageTime = net_time;
122 sock->ackSequence = 0;
123 sock->sendSequence = 0;
124 sock->unreliableSendSequence = 0;
125 sock->sendMessageLength = 0;
126 sock->receiveSequence = 0;
127 sock->unreliableReceiveSequence = 0;
128 sock->receiveMessageLength = 0;
129 sock->pending_max_datagram = 1024;
130 sock->proquake_angle_hack = false;
131
132 return sock;
133 }
134
135
NET_FreeQSocket(qsocket_t * sock)136 void NET_FreeQSocket(qsocket_t *sock)
137 {
138 qsocket_t *s;
139
140 // remove it from active list
141 if (sock == net_activeSockets)
142 net_activeSockets = net_activeSockets->next;
143 else
144 {
145 for (s = net_activeSockets; s; s = s->next)
146 {
147 if (s->next == sock)
148 {
149 s->next = sock->next;
150 break;
151 }
152 }
153
154 if (!s)
155 Sys_Error ("NET_FreeQSocket: not active");
156 }
157
158 // add it to free list
159 sock->next = net_freeSockets;
160 net_freeSockets = sock;
161 sock->disconnected = true;
162 }
163
164
NET_QSocketGetSequenceIn(const qsocket_t * s)165 int NET_QSocketGetSequenceIn (const qsocket_t *s)
166 { //returns the last unreliable sequence that was received
167 return s->unreliableReceiveSequence-1;
168 }
NET_QSocketGetSequenceOut(const qsocket_t * s)169 int NET_QSocketGetSequenceOut (const qsocket_t *s)
170 { //returns the next unreliable sequence that will be sent
171 return s->unreliableSendSequence;
172 }
NET_QSocketGetTime(const qsocket_t * s)173 double NET_QSocketGetTime (const qsocket_t *s)
174 {
175 return s->connecttime;
176 }
177
178
NET_QSocketGetTrueAddressString(const qsocket_t * s)179 const char *NET_QSocketGetTrueAddressString (const qsocket_t *s)
180 {
181 return s->trueaddress;
182 }
NET_QSocketGetMaskedAddressString(const qsocket_t * s)183 const char *NET_QSocketGetMaskedAddressString (const qsocket_t *s)
184 {
185 return s->maskedaddress;
186 }
NET_QSocketGetProQuakeAngleHack(const qsocket_t * s)187 qboolean NET_QSocketGetProQuakeAngleHack(const qsocket_t *s)
188 {
189 if (s && !s->disconnected)
190 return s->proquake_angle_hack;
191 else
192 return false; //happens with demos
193 }
NET_QSocketSetMSS(qsocket_t * s,int mss)194 void NET_QSocketSetMSS(qsocket_t *s, int mss)
195 {
196 s->pending_max_datagram = mss;
197 }
198
199
NET_Listen_f(void)200 static void NET_Listen_f (void)
201 {
202 if (Cmd_Argc () != 2)
203 {
204 Con_Printf ("\"listen\" is \"%d\"\n", listening ? 1 : 0);
205 return;
206 }
207
208 listening = Q_atoi(Cmd_Argv(1)) ? true : false;
209
210 for (net_driverlevel = 0; net_driverlevel < net_numdrivers; net_driverlevel++)
211 {
212 if (net_drivers[net_driverlevel].initialized == false)
213 continue;
214 dfunc.Listen (listening);
215 }
216 }
217
218
MaxPlayers_f(void)219 static void MaxPlayers_f (void)
220 {
221 int n;
222
223 if (Cmd_Argc () != 2)
224 {
225 Con_Printf ("\"maxplayers\" is \"%d\"\n", svs.maxclients);
226 return;
227 }
228
229 if (sv.active)
230 {
231 Con_Printf ("maxplayers can not be changed while a server is running.\n");
232 return;
233 }
234
235 n = Q_atoi(Cmd_Argv(1));
236 if (n < 1)
237 n = 1;
238 if (n > svs.maxclientslimit)
239 {
240 n = svs.maxclientslimit;
241 Con_Printf ("\"maxplayers\" set to \"%d\"\n", n);
242 }
243
244 if ((n == 1) && listening)
245 Cbuf_AddText ("listen 0\n");
246
247 if ((n > 1) && (!listening))
248 Cbuf_AddText ("listen 1\n");
249
250 svs.maxclients = n;
251 if (n == 1)
252 Cvar_Set ("deathmatch", "0");
253 else
254 Cvar_Set ("deathmatch", "1");
255 }
256
257
NET_Port_f(void)258 static void NET_Port_f (void)
259 {
260 int n;
261
262 if (Cmd_Argc () != 2)
263 {
264 Con_Printf ("\"port\" is \"%d\"\n", net_hostport);
265 return;
266 }
267
268 n = Q_atoi(Cmd_Argv(1));
269 if (n < 1 || n > 65534)
270 {
271 Con_Printf ("Bad value, must be between 1 and 65534\n");
272 return;
273 }
274
275 DEFAULTnet_hostport = n;
276 net_hostport = n;
277
278 if (listening)
279 {
280 // force a change to the new port
281 Cbuf_AddText ("listen 0\n");
282 Cbuf_AddText ("listen 1\n");
283 }
284 }
285
286
PrintSlistHeader(void)287 static void PrintSlistHeader(void)
288 {
289 Con_Printf("Server Map Users\n");
290 Con_Printf("--------------- --------------- -----\n");
291 slistLastShown = 0;
292 }
293
294
PrintSlist(void)295 static void PrintSlist(void)
296 {
297 size_t n;
298
299 for (n = slistLastShown; n < hostCacheCount; n++)
300 {
301 if (hostcache[n].maxusers)
302 Con_Printf("%-15.15s %-15.15s %2u/%2u\n", hostcache[n].name, hostcache[n].map, hostcache[n].users, hostcache[n].maxusers);
303 else
304 Con_Printf("%-15.15s %-15.15s\n", hostcache[n].name, hostcache[n].map);
305 }
306 slistLastShown = n;
307 }
308
309
PrintSlistTrailer(void)310 static void PrintSlistTrailer(void)
311 {
312 if (hostCacheCount)
313 Con_Printf("== end list ==\n\n");
314 else
315 Con_Printf("No Quake servers found.\n\n");
316 }
317
318
NET_Slist_f(void)319 void NET_Slist_f (void)
320 {
321 if (slistInProgress)
322 return;
323
324 if (! slistSilent)
325 {
326 Con_Printf("Looking for Quake servers...\n");
327 PrintSlistHeader();
328 }
329
330 slistInProgress = true;
331 slistActiveTime = slistStartTime = Sys_DoubleTime();
332
333 SchedulePollProcedure(&slistSendProcedure, 0.0);
334 SchedulePollProcedure(&slistPollProcedure, 0.1);
335
336 hostCacheCount = 0;
337 }
338
339
NET_SlistSort(void)340 void NET_SlistSort (void)
341 {
342 if (hostCacheCount > 1)
343 {
344 size_t i, j;
345 hostcache_t temp;
346 for (i = 0; i < hostCacheCount; i++)
347 {
348 for (j = i + 1; j < hostCacheCount; j++)
349 {
350 if (strcmp(hostcache[j].name, hostcache[i].name) < 0)
351 {
352 memcpy(&temp, &hostcache[j], sizeof(hostcache_t));
353 memcpy(&hostcache[j], &hostcache[i], sizeof(hostcache_t));
354 memcpy(&hostcache[i], &temp, sizeof(hostcache_t));
355 }
356 }
357 }
358 }
359 }
360
361
NET_SlistPrintServer(size_t idx)362 const char *NET_SlistPrintServer (size_t idx)
363 {
364 static char string[64];
365
366 if (idx >= hostCacheCount)
367 return "";
368
369 if (hostcache[idx].maxusers)
370 {
371 q_snprintf(string, sizeof(string), "%-15.15s %-15.15s %2u/%2u\n",
372 hostcache[idx].name, hostcache[idx].map,
373 hostcache[idx].users, hostcache[idx].maxusers);
374 }
375 else
376 {
377 q_snprintf(string, sizeof(string), "%-15.15s %-15.15s\n",
378 hostcache[idx].name, hostcache[idx].map);
379 }
380
381 return string;
382 }
383
384
NET_SlistPrintServerName(size_t idx)385 const char *NET_SlistPrintServerName (size_t idx)
386 {
387 if (idx >= hostCacheCount)
388 return "";
389 return hostcache[idx].cname;
390 }
391
392
Slist_Send(void * unused)393 static void Slist_Send (void *unused)
394 {
395 for (net_driverlevel = 0; net_driverlevel < net_numdrivers; net_driverlevel++)
396 {
397 if (slistScope!=SLIST_LOOP && IS_LOOP_DRIVER(net_driverlevel))
398 continue;
399 if (net_drivers[net_driverlevel].initialized == false)
400 continue;
401 dfunc.SearchForHosts (true);
402 }
403
404 if ((Sys_DoubleTime() - slistStartTime) < 0.5)
405 SchedulePollProcedure(&slistSendProcedure, 0.75);
406 }
407
408
Slist_Poll(void * unused)409 static void Slist_Poll (void *unused)
410 {
411 for (net_driverlevel = 0; net_driverlevel < net_numdrivers; net_driverlevel++)
412 {
413 if (slistScope!=SLIST_LOOP && IS_LOOP_DRIVER(net_driverlevel))
414 continue;
415 if (net_drivers[net_driverlevel].initialized == false)
416 continue;
417 if (dfunc.SearchForHosts (false))
418 slistActiveTime = Sys_DoubleTime(); //something was sent, reset the timer.
419 }
420
421 if (! slistSilent)
422 PrintSlist();
423
424 if ((Sys_DoubleTime() - slistActiveTime) < 1.5)
425 {
426 SchedulePollProcedure(&slistPollProcedure, 0.1);
427 return;
428 }
429
430 if (! slistSilent)
431 PrintSlistTrailer();
432 slistInProgress = false;
433 slistSilent = false;
434 slistScope = SLIST_LOOP;
435 }
436
437
438 /*
439 ===================
440 NET_Connect
441 ===================
442 */
443
444 size_t hostCacheCount = 0;
445 hostcache_t hostcache[HOSTCACHESIZE];
446
NET_Connect(const char * host)447 qsocket_t *NET_Connect (const char *host)
448 {
449 qsocket_t *ret;
450 size_t n;
451 int numdrivers = net_numdrivers;
452
453 SetNetTime();
454
455 if (host && *host == 0)
456 host = NULL;
457
458 if (host)
459 {
460 if (q_strcasecmp (host, "local") == 0)
461 {
462 numdrivers = 1;
463 goto JustDoIt;
464 }
465
466 if (hostCacheCount)
467 {
468 for (n = 0; n < hostCacheCount; n++)
469 if (q_strcasecmp (host, hostcache[n].name) == 0)
470 {
471 host = hostcache[n].cname;
472 break;
473 }
474 if (n < hostCacheCount)
475 goto JustDoIt;
476 }
477 }
478
479 slistSilent = host ? true : false;
480 NET_Slist_f ();
481
482 while (slistInProgress)
483 NET_Poll();
484
485 if (host == NULL)
486 {
487 if (hostCacheCount != 1)
488 return NULL;
489 host = hostcache[0].cname;
490 Con_Printf("Connecting to...\n%s @ %s\n\n", hostcache[0].name, host);
491 }
492
493 if (hostCacheCount)
494 {
495 for (n = 0; n < hostCacheCount; n++)
496 {
497 if (q_strcasecmp (host, hostcache[n].name) == 0)
498 {
499 host = hostcache[n].cname;
500 break;
501 }
502 }
503 }
504
505 JustDoIt:
506 for (net_driverlevel = 0; net_driverlevel < numdrivers; net_driverlevel++)
507 {
508 if (net_drivers[net_driverlevel].initialized == false)
509 continue;
510 ret = dfunc.Connect (host);
511 if (ret)
512 return ret;
513 }
514
515 if (host)
516 {
517 Con_Printf("\n");
518 PrintSlistHeader();
519 PrintSlist();
520 PrintSlistTrailer();
521 }
522
523 return NULL;
524 }
525
526
527 /*
528 ===================
529 NET_CheckNewConnections
530 ===================
531 */
NET_CheckNewConnections(void)532 qsocket_t *NET_CheckNewConnections (void)
533 {
534 qsocket_t *ret;
535
536 SetNetTime();
537
538 for (net_driverlevel = 0; net_driverlevel < net_numdrivers; net_driverlevel++)
539 {
540 if (net_drivers[net_driverlevel].initialized == false)
541 continue;
542 if (!IS_LOOP_DRIVER(net_driverlevel) && listening == false)
543 continue;
544 ret = dfunc.CheckNewConnections ();
545 if (ret)
546 {
547 return ret;
548 }
549 }
550
551 return NULL;
552 }
553
554 /*
555 ===================
556 NET_Close
557 ===================
558 */
NET_Close(qsocket_t * sock)559 void NET_Close (qsocket_t *sock)
560 {
561 if (!sock)
562 return;
563
564 if (sock->disconnected)
565 return;
566
567 SetNetTime();
568
569 // call the driver_Close function
570 sfunc.Close (sock);
571
572 NET_FreeQSocket(sock);
573 }
574
575
576 /*
577 =================
578 NET_GetMessage
579
580 If there is a complete message, return it in net_message
581
582 returns 0 if no data is waiting
583 returns 1 if a message was received
584 returns -1 if connection is invalid
585 =================
586 */
NET_GetMessage(qsocket_t * sock)587 int NET_GetMessage (qsocket_t *sock)
588 {
589 int ret;
590
591 if (!sock)
592 return -1;
593
594 if (sock->disconnected)
595 {
596 Con_Printf("NET_GetMessage: disconnected socket\n");
597 return -1;
598 }
599
600 SetNetTime();
601
602 ret = sfunc.QGetMessage(sock);
603
604 // see if this connection has timed out
605 if (ret == 0 && !IS_LOOP_DRIVER(sock->driver))
606 {
607 if (net_time - sock->lastMessageTime > net_messagetimeout.value)
608 {
609 NET_Close(sock);
610 return -1;
611 }
612 }
613
614 if (ret > 0)
615 {
616 if (!IS_LOOP_DRIVER(sock->driver))
617 {
618 sock->lastMessageTime = net_time;
619 if (ret == 1)
620 messagesReceived++;
621 else if (ret == 2)
622 unreliableMessagesReceived++;
623 }
624 }
625
626 return ret;
627 }
628
629 /*
630 =================
631 NET_GetServerMessage
632
633 If there is a complete message, return it in net_message
634
635 returns the qsocket that the message was meant to be for.
636 =================
637 */
NET_GetServerMessage(void)638 qsocket_t *NET_GetServerMessage(void)
639 {
640 qsocket_t *s;
641 for (net_driverlevel = 0; net_driverlevel < net_numdrivers; net_driverlevel++)
642 {
643 if (!net_drivers[net_driverlevel].initialized)
644 continue;
645 s = net_drivers[net_driverlevel].QGetAnyMessage();
646 if (s)
647 return s;
648 }
649 return NULL;
650 }
651
652 /*
653 Spike: This function is for the menus+status command
654 Just queries each driver's public addresses (which often requires system-specific calls)
655 */
NET_ListAddresses(qhostaddr_t * addresses,int maxaddresses)656 int NET_ListAddresses(qhostaddr_t *addresses, int maxaddresses)
657 {
658 int result = 0;
659 for (net_driverlevel = 0; net_driverlevel < net_numdrivers; net_driverlevel++)
660 {
661 if (!net_drivers[net_driverlevel].initialized)
662 continue;
663 if (net_drivers[net_driverlevel].QueryAddresses)
664 result += net_drivers[net_driverlevel].QueryAddresses(addresses+result, maxaddresses-result);
665 }
666 return result;
667 }
668
669 /*
670 ==================
671 NET_SendMessage
672
673 Try to send a complete length+message unit over the reliable stream.
674 returns 0 if the message cannot be delivered reliably, but the connection
675 is still considered valid
676 returns 1 if the message was sent properly
677 returns -1 if the connection died
678 ==================
679 */
NET_SendMessage(qsocket_t * sock,sizebuf_t * data)680 int NET_SendMessage (qsocket_t *sock, sizebuf_t *data)
681 {
682 int r;
683
684 if (!sock)
685 return -1;
686
687 if (sock->disconnected)
688 {
689 Con_Printf("NET_SendMessage: disconnected socket\n");
690 return -1;
691 }
692
693 SetNetTime();
694 r = sfunc.QSendMessage(sock, data);
695 if (r == 1 && !IS_LOOP_DRIVER(sock->driver))
696 messagesSent++;
697
698 return r;
699 }
700
701
NET_SendUnreliableMessage(qsocket_t * sock,sizebuf_t * data)702 int NET_SendUnreliableMessage (qsocket_t *sock, sizebuf_t *data)
703 {
704 int r;
705
706 if (!sock)
707 return -1;
708
709 if (sock->disconnected)
710 {
711 Con_Printf("NET_SendMessage: disconnected socket\n");
712 return -1;
713 }
714
715 SetNetTime();
716 r = sfunc.SendUnreliableMessage(sock, data);
717 if (r == 1 && !IS_LOOP_DRIVER(sock->driver))
718 unreliableMessagesSent++;
719
720 return r;
721 }
722
723
724 /*
725 ==================
726 NET_CanSendMessage
727
728 Returns true or false if the given qsocket can currently accept a
729 message to be transmitted.
730 ==================
731 */
NET_CanSendMessage(qsocket_t * sock)732 qboolean NET_CanSendMessage (qsocket_t *sock)
733 {
734 if (!sock)
735 return false;
736
737 if (sock->disconnected)
738 return false;
739
740 SetNetTime();
741
742 return sfunc.CanSendMessage(sock);
743 }
744
745
NET_SendToAll(sizebuf_t * data,double blocktime)746 int NET_SendToAll (sizebuf_t *data, double blocktime)
747 {
748 double start;
749 int i;
750 int count = 0;
751 qboolean msg_init[MAX_SCOREBOARD]; /* did we write the message to the client's connection */
752 qboolean msg_sent[MAX_SCOREBOARD]; /* did the msg arrive its destination (canSend state). */
753
754 for (i = 0, host_client = svs.clients; i < svs.maxclients; i++, host_client++)
755 {
756 /*
757 if (!host_client->netconnection)
758 continue;
759 if (host_client->active)
760 */
761 if (host_client->netconnection && host_client->active)
762 {
763 if (IS_LOOP_DRIVER(host_client->netconnection->driver))
764 {
765 NET_SendMessage(host_client->netconnection, data);
766 msg_init[i] = true;
767 msg_sent[i] = true;
768 continue;
769 }
770 count++;
771 msg_init[i] = false;
772 msg_sent[i] = false;
773 }
774 else
775 {
776 msg_init[i] = true;
777 msg_sent[i] = true;
778 }
779 }
780
781 start = Sys_DoubleTime();
782 while (count)
783 {
784 count = 0;
785 for (i = 0, host_client = svs.clients; i < svs.maxclients; i++, host_client++)
786 {
787 if (! msg_init[i])
788 {
789 if (NET_CanSendMessage (host_client->netconnection))
790 {
791 msg_init[i] = true;
792 NET_SendMessage(host_client->netconnection, data);
793 }
794 else
795 {
796 NET_GetMessage (host_client->netconnection);
797 }
798 count++;
799 continue;
800 }
801
802 if (! msg_sent[i])
803 {
804 if (NET_CanSendMessage (host_client->netconnection))
805 {
806 msg_sent[i] = true;
807 }
808 else
809 {
810 NET_GetMessage (host_client->netconnection);
811 }
812 count++;
813 continue;
814 }
815 }
816 if ((Sys_DoubleTime() - start) > blocktime)
817 break;
818 }
819 return count;
820 }
821
822
823 //=============================================================================
824
825 /*
826 ====================
827 NET_Init
828 ====================
829 */
830
NET_Init(void)831 void NET_Init (void)
832 {
833 int i;
834 qsocket_t *s;
835
836 i = COM_CheckParm ("-port");
837 if (!i)
838 i = COM_CheckParm ("-udpport");
839 if (!i)
840 i = COM_CheckParm ("-ipxport");
841
842 if (i)
843 {
844 if (i < com_argc-1)
845 DEFAULTnet_hostport = Q_atoi (com_argv[i+1]);
846 else
847 Sys_Error ("NET_Init: you must specify a number after -port");
848 }
849 net_hostport = DEFAULTnet_hostport;
850
851 net_numsockets = svs.maxclientslimit;
852 if (cls.state != ca_dedicated)
853 net_numsockets++;
854 if (COM_CheckParm("-listen") || cls.state == ca_dedicated)
855 listening = true;
856
857 SetNetTime();
858
859 for (i = 0; i < net_numsockets; i++)
860 {
861 s = (qsocket_t *)Hunk_AllocName(sizeof(qsocket_t), "qsocket");
862 s->next = net_freeSockets;
863 net_freeSockets = s;
864 s->disconnected = true;
865 }
866
867 // allocate space for network message buffer
868 SZ_Alloc (&net_message, NET_MAXMESSAGE);
869
870 Cvar_RegisterVariable (&net_messagetimeout);
871 Cvar_RegisterVariable (&net_connecttimeout);
872 Cvar_RegisterVariable (&hostname);
873
874 Cmd_AddCommand ("slist", NET_Slist_f);
875 Cmd_AddCommand ("listen", NET_Listen_f);
876 Cmd_AddCommand ("maxplayers", MaxPlayers_f);
877 Cmd_AddCommand ("port", NET_Port_f);
878
879 // initialize all the drivers
880 for (i = net_driverlevel = 0; net_driverlevel < net_numdrivers; net_driverlevel++)
881 {
882 if (net_drivers[net_driverlevel].Init() == -1)
883 continue;
884 i++;
885 net_drivers[net_driverlevel].initialized = true;
886 if (listening)
887 net_drivers[net_driverlevel].Listen (true);
888 }
889
890 /* Loop_Init() returns -1 for dedicated server case,
891 * therefore the i == 0 check is correct */
892 if (i == 0
893 && cls.state == ca_dedicated
894 )
895 {
896 Sys_Error("Network not available!");
897 }
898
899 if (*my_ipx_address)
900 {
901 Con_DPrintf("IPX address %s\n", my_ipx_address);
902 }
903 if (*my_ipv4_address)
904 {
905 Con_DPrintf("IPv4 address %s\n", my_ipv4_address);
906 }
907 if (*my_ipv6_address)
908 {
909 Con_DPrintf("IPv6 address %s\n", my_ipv6_address);
910 }
911 }
912
913 /*
914 ====================
915 NET_Shutdown
916 ====================
917 */
918
NET_Shutdown(void)919 void NET_Shutdown (void)
920 {
921 qsocket_t *sock;
922
923 SetNetTime();
924
925 for (sock = net_activeSockets; sock; sock = sock->next)
926 NET_Close(sock);
927
928 //
929 // shutdown the drivers
930 //
931 for (net_driverlevel = 0; net_driverlevel < net_numdrivers; net_driverlevel++)
932 {
933 if (net_drivers[net_driverlevel].initialized == true)
934 {
935 net_drivers[net_driverlevel].Shutdown ();
936 net_drivers[net_driverlevel].initialized = false;
937 }
938 }
939 }
940
941
942 static PollProcedure *pollProcedureList = NULL;
943
NET_Poll(void)944 void NET_Poll(void)
945 {
946 PollProcedure *pp;
947
948 SetNetTime();
949
950 for (pp = pollProcedureList; pp; pp = pp->next)
951 {
952 if (pp->nextTime > net_time)
953 break;
954 pollProcedureList = pp->next;
955 pp->procedure(pp->arg);
956 }
957 }
958
959
SchedulePollProcedure(PollProcedure * proc,double timeOffset)960 void SchedulePollProcedure(PollProcedure *proc, double timeOffset)
961 {
962 PollProcedure *pp, *prev;
963
964 proc->nextTime = Sys_DoubleTime() + timeOffset;
965 for (pp = pollProcedureList, prev = NULL; pp; pp = pp->next)
966 {
967 if (pp->nextTime >= proc->nextTime)
968 break;
969 prev = pp;
970 }
971
972 if (prev == NULL)
973 {
974 proc->next = pollProcedureList;
975 pollProcedureList = proc;
976 return;
977 }
978
979 proc->next = pp;
980 prev->next = proc;
981 }
982
983