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