Home | History | Annotate | Download | only in WinQuake
      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, NULL};
     55 PollProcedure	slistPollProcedure = {NULL, 0.0, Slist_Poll, NULL};
     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 = CVAR2("net_messagetimeout","300");
     67 cvar_t	hostname = CVAR2("hostname", "UNNAMED");
     68 
     69 qboolean	configRestored = false;
     70 cvar_t	config_com_port = CVAR3("_config_com_port", "0x3f8", true);
     71 cvar_t	config_com_irq = CVAR3("_config_com_irq", "4", true);
     72 cvar_t	config_com_baud = CVAR3("_config_com_baud", "57600", true);
     73 cvar_t	config_com_modem = CVAR3("_config_com_modem", "1", true);
     74 cvar_t	config_modem_dialtype = CVAR3("_config_modem_dialtype", "T", true);
     75 cvar_t	config_modem_clear = CVAR3("_config_modem_clear", "ATZ", true);
     76 cvar_t	config_modem_init = CVAR3("_config_modem_init", "", true);
     77 cvar_t	config_modem_hangup = CVAR3("_config_modem_hangup", "AT H", true);
     78 
     79 #ifdef IDGODS
     80 cvar_t	idgods = CVAR2("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 
     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 */
    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 
    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 
    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 
    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 
    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 
    262 static void PrintSlistHeader(void)
    263 {
    264 	Con_Printf("Server          Map             Users\n");
    265 	Con_Printf("--------------- --------------- -----\n");
    266 	slistLastShown = 0;
    267 }
    268 
    269 
    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 
    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 
    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 
    315 static void Slist_Send(void* /* arg */)
    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 
    331 static void Slist_Poll(void* /* arg */)
    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 
    368 qsocket_t *NET_Connect (const 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 vcrConnect_t
    451 {
    452 	double	time;
    453 	int		op;
    454 	long	session;
    455 } vcrConnect;
    456 
    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 */
    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 vcrGetMessage_t
    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 
    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 		if (net_time - sock->lastMessageTime > net_messagetimeout.value)
    561 		{
    562 			NET_Close(sock);
    563 			return -1;
    564 		}
    565 	}
    566 
    567 
    568 	if (ret > 0)
    569 	{
    570 		if (sock->driver)
    571 		{
    572 			sock->lastMessageTime = net_time;
    573 			if (ret == 1)
    574 				messagesReceived++;
    575 			else if (ret == 2)
    576 				unreliableMessagesReceived++;
    577 		}
    578 
    579 		if (recording)
    580 		{
    581 			vcrGetMessage.time = host_time;
    582 			vcrGetMessage.op = VCR_OP_GETMESSAGE;
    583 			vcrGetMessage.session = (long)sock;
    584 			vcrGetMessage.ret = ret;
    585 			vcrGetMessage.len = net_message.cursize;
    586 			Sys_FileWrite (vcrFile, &vcrGetMessage, 24);
    587 			Sys_FileWrite (vcrFile, net_message.data, net_message.cursize);
    588 		}
    589 	}
    590 	else
    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 			Sys_FileWrite (vcrFile, &vcrGetMessage, 20);
    599 		}
    600 	}
    601 
    602 	return ret;
    603 }
    604 
    605 
    606 /*
    607 ==================
    608 NET_SendMessage
    609 
    610 Try to send a complete length+message unit over the reliable stream.
    611 returns 0 if the message cannot be delivered reliably, but the connection
    612 		is still considered valid
    613 returns 1 if the message was sent properly
    614 returns -1 if the connection died
    615 ==================
    616 */
    617 struct vcrSendMessage_t
    618 {
    619 	double	time;
    620 	int		op;
    621 	long	session;
    622 	int		r;
    623 } vcrSendMessage;
    624 
    625 int NET_SendMessage (qsocket_t *sock, sizebuf_t *data)
    626 {
    627 	int		r;
    628 
    629 	if (!sock)
    630 		return -1;
    631 
    632 	if (sock->disconnected)
    633 	{
    634 		Con_Printf("NET_SendMessage: disconnected socket\n");
    635 		return -1;
    636 	}
    637 
    638 	SetNetTime();
    639 	r = sfunc.QSendMessage(sock, data);
    640 	if (r == 1 && sock->driver)
    641 		messagesSent++;
    642 
    643 	if (recording)
    644 	{
    645 		vcrSendMessage.time = host_time;
    646 		vcrSendMessage.op = VCR_OP_SENDMESSAGE;
    647 		vcrSendMessage.session = (long)sock;
    648 		vcrSendMessage.r = r;
    649 		Sys_FileWrite (vcrFile, &vcrSendMessage, 20);
    650 	}
    651 
    652 	return r;
    653 }
    654 
    655 
    656 int NET_SendUnreliableMessage (qsocket_t *sock, sizebuf_t *data)
    657 {
    658 	int		r;
    659 
    660 	if (!sock)
    661 		return -1;
    662 
    663 	if (sock->disconnected)
    664 	{
    665 		Con_Printf("NET_SendMessage: disconnected socket\n");
    666 		return -1;
    667 	}
    668 
    669 	SetNetTime();
    670 	r = sfunc.SendUnreliableMessage(sock, data);
    671 	if (r == 1 && sock->driver)
    672 		unreliableMessagesSent++;
    673 
    674 	if (recording)
    675 	{
    676 		vcrSendMessage.time = host_time;
    677 		vcrSendMessage.op = VCR_OP_SENDMESSAGE;
    678 		vcrSendMessage.session = (long)sock;
    679 		vcrSendMessage.r = r;
    680 		Sys_FileWrite (vcrFile, &vcrSendMessage, 20);
    681 	}
    682 
    683 	return r;
    684 }
    685 
    686 
    687 /*
    688 ==================
    689 NET_CanSendMessage
    690 
    691 Returns true or false if the given qsocket can currently accept a
    692 message to be transmitted.
    693 ==================
    694 */
    695 qboolean NET_CanSendMessage (qsocket_t *sock)
    696 {
    697 	int		r;
    698 
    699 	if (!sock)
    700 		return false;
    701 
    702 	if (sock->disconnected)
    703 		return false;
    704 
    705 	SetNetTime();
    706 
    707 	r = sfunc.CanSendMessage(sock);
    708 
    709 	if (recording)
    710 	{
    711 		vcrSendMessage.time = host_time;
    712 		vcrSendMessage.op = VCR_OP_CANSENDMESSAGE;
    713 		vcrSendMessage.session = (long)sock;
    714 		vcrSendMessage.r = r;
    715 		Sys_FileWrite (vcrFile, &vcrSendMessage, 20);
    716 	}
    717 
    718 	return r;
    719 }
    720 
    721 
    722 int NET_SendToAll(sizebuf_t *data, int blocktime)
    723 {
    724 	double		start;
    725 	int			i;
    726 	int			count = 0;
    727 	qboolean	state1 [MAX_SCOREBOARD];
    728 	qboolean	state2 [MAX_SCOREBOARD];
    729 
    730 	for (i=0, host_client = svs.clients ; i<svs.maxclients ; i++, host_client++)
    731 	{
    732 		if (!host_client->netconnection)
    733 			continue;
    734 		if (host_client->active)
    735 		{
    736 			if (host_client->netconnection->driver == 0)
    737 			{
    738 				NET_SendMessage(host_client->netconnection, data);
    739 				state1[i] = true;
    740 				state2[i] = true;
    741 				continue;
    742 			}
    743 			count++;
    744 			state1[i] = false;
    745 			state2[i] = false;
    746 		}
    747 		else
    748 		{
    749 			state1[i] = true;
    750 			state2[i] = true;
    751 		}
    752 	}
    753 
    754 	start = Sys_FloatTime();
    755 	while (count)
    756 	{
    757 		count = 0;
    758 		for (i=0, host_client = svs.clients ; i<svs.maxclients ; i++, host_client++)
    759 		{
    760 			if (! state1[i])
    761 			{
    762 				if (NET_CanSendMessage (host_client->netconnection))
    763 				{
    764 					state1[i] = true;
    765 					NET_SendMessage(host_client->netconnection, data);
    766 				}
    767 				else
    768 				{
    769 					NET_GetMessage (host_client->netconnection);
    770 				}
    771 				count++;
    772 				continue;
    773 			}
    774 
    775 			if (! state2[i])
    776 			{
    777 				if (NET_CanSendMessage (host_client->netconnection))
    778 				{
    779 					state2[i] = true;
    780 				}
    781 				else
    782 				{
    783 					NET_GetMessage (host_client->netconnection);
    784 				}
    785 				count++;
    786 				continue;
    787 			}
    788 		}
    789 		if ((Sys_FloatTime() - start) > blocktime)
    790 			break;
    791 	}
    792 	return count;
    793 }
    794 
    795 
    796 //=============================================================================
    797 
    798 /*
    799 ====================
    800 NET_Init
    801 ====================
    802 */
    803 
    804 void NET_Init (void)
    805 {
    806 	int			i;
    807 	int			controlSocket;
    808 	qsocket_t	*s;
    809 
    810 	if (COM_CheckParm("-playback"))
    811 	{
    812 		net_numdrivers = 1;
    813 		net_drivers[0].Init = VCR_Init;
    814 	}
    815 
    816 	if (COM_CheckParm("-record"))
    817 		recording = true;
    818 
    819 	i = COM_CheckParm ("-port");
    820 	if (!i)
    821 		i = COM_CheckParm ("-udpport");
    822 	if (!i)
    823 		i = COM_CheckParm ("-ipxport");
    824 
    825 	if (i)
    826 	{
    827 		if (i < com_argc-1)
    828 			DEFAULTnet_hostport = Q_atoi (com_argv[i+1]);
    829 		else
    830 			Sys_Error ("NET_Init: you must specify a number after -port");
    831 	}
    832 	net_hostport = DEFAULTnet_hostport;
    833 
    834 	if (COM_CheckParm("-listen") || cls.state == ca_dedicated)
    835 		listening = true;
    836 	net_numsockets = svs.maxclientslimit;
    837 	if (cls.state != ca_dedicated)
    838 		net_numsockets++;
    839 
    840 	SetNetTime();
    841 
    842 	for (i = 0; i < net_numsockets; i++)
    843 	{
    844 		s = (qsocket_t *)Hunk_AllocName(sizeof(qsocket_t), "qsocket");
    845 		s->next = net_freeSockets;
    846 		net_freeSockets = s;
    847 		s->disconnected = true;
    848 	}
    849 
    850 	// allocate space for network message buffer
    851 	SZ_Alloc (&net_message, NET_MAXMESSAGE);
    852 
    853 	Cvar_RegisterVariable (&net_messagetimeout);
    854 	Cvar_RegisterVariable (&hostname);
    855 	Cvar_RegisterVariable (&config_com_port);
    856 	Cvar_RegisterVariable (&config_com_irq);
    857 	Cvar_RegisterVariable (&config_com_baud);
    858 	Cvar_RegisterVariable (&config_com_modem);
    859 	Cvar_RegisterVariable (&config_modem_dialtype);
    860 	Cvar_RegisterVariable (&config_modem_clear);
    861 	Cvar_RegisterVariable (&config_modem_init);
    862 	Cvar_RegisterVariable (&config_modem_hangup);
    863 #ifdef IDGODS
    864 	Cvar_RegisterVariable (&idgods);
    865 #endif
    866 
    867 	Cmd_AddCommand ("slist", NET_Slist_f);
    868 	Cmd_AddCommand ("listen", NET_Listen_f);
    869 	Cmd_AddCommand ("maxplayers", MaxPlayers_f);
    870 	Cmd_AddCommand ("port", NET_Port_f);
    871 
    872 	// initialize all the drivers
    873 	for (net_driverlevel=0 ; net_driverlevel<net_numdrivers ; net_driverlevel++)
    874 		{
    875 		controlSocket = net_drivers[net_driverlevel].Init();
    876 		if (controlSocket == -1)
    877 			continue;
    878 		net_drivers[net_driverlevel].initialized = true;
    879 		net_drivers[net_driverlevel].controlSock = controlSocket;
    880 		if (listening)
    881 			net_drivers[net_driverlevel].Listen (true);
    882 		}
    883 
    884 	if (*my_ipx_address)
    885 		Con_DPrintf("IPX address %s\n", my_ipx_address);
    886 	if (*my_tcpip_address)
    887 		Con_DPrintf("TCP/IP address %s\n", my_tcpip_address);
    888 }
    889 
    890 /*
    891 ====================
    892 NET_Shutdown
    893 ====================
    894 */
    895 
    896 void		NET_Shutdown (void)
    897 {
    898 	qsocket_t	*sock;
    899 
    900 	SetNetTime();
    901 
    902 	for (sock = net_activeSockets; sock; sock = sock->next)
    903 		NET_Close(sock);
    904 
    905 //
    906 // shutdown the drivers
    907 //
    908 	for (net_driverlevel = 0; net_driverlevel < net_numdrivers; net_driverlevel++)
    909 	{
    910 		if (net_drivers[net_driverlevel].initialized == true)
    911 		{
    912 			net_drivers[net_driverlevel].Shutdown ();
    913 			net_drivers[net_driverlevel].initialized = false;
    914 		}
    915 	}
    916 
    917 	if (vcrFile != -1)
    918 	{
    919 		Con_Printf ("Closing vcrfile.\n");
    920 		Sys_FileClose(vcrFile);
    921 	}
    922 }
    923 
    924 
    925 static PollProcedure *pollProcedureList = NULL;
    926 
    927 void NET_Poll(void)
    928 {
    929 	PollProcedure *pp;
    930 	qboolean	useModem;
    931 
    932 	if (!configRestored)
    933 	{
    934 		if (serialAvailable)
    935 		{
    936 			if (config_com_modem.value == 1.0)
    937 				useModem = true;
    938 			else
    939 				useModem = false;
    940 			SetComPortConfig (0, (int)config_com_port.value, (int)config_com_irq.value, (int)config_com_baud.value, useModem);
    941 			SetModemConfig (0, config_modem_dialtype.string, config_modem_clear.string, config_modem_init.string, config_modem_hangup.string);
    942 		}
    943 		configRestored = true;
    944 	}
    945 
    946 	SetNetTime();
    947 
    948 	for (pp = pollProcedureList; pp; pp = pp->next)
    949 	{
    950 		if (pp->nextTime > net_time)
    951 			break;
    952 		pollProcedureList = pp->next;
    953 		pp->procedure(pp->arg);
    954 	}
    955 }
    956 
    957 
    958 void SchedulePollProcedure(PollProcedure *proc, double timeOffset)
    959 {
    960 	PollProcedure *pp, *prev;
    961 
    962 	proc->nextTime = Sys_FloatTime() + timeOffset;
    963 	for (pp = pollProcedureList, prev = NULL; pp; pp = pp->next)
    964 	{
    965 		if (pp->nextTime >= proc->nextTime)
    966 			break;
    967 		prev = pp;
    968 	}
    969 
    970 	if (prev == NULL)
    971 	{
    972 		proc->next = pollProcedureList;
    973 		pollProcedureList = proc;
    974 		return;
    975 	}
    976 
    977 	proc->next = pp;
    978 	prev->next = proc;
    979 }
    980 
    981 
    982 #ifdef IDGODS
    983 #define IDNET	0xc0f62800
    984 
    985 qboolean IsID(struct qsockaddr *addr)
    986 {
    987 	if (idgods.value == 0.0)
    988 		return false;
    989 
    990 	if (addr->sa_family != 2)
    991 		return false;
    992 
    993 	if ((BigLong(*(int *)&addr->sa_data[2]) & 0xffffff00) == IDNET)
    994 		return true;
    995 	return false;
    996 }
    997 #endif
    998