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