2 Copyright (C) 1996-1997 Id Software, Inc.
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.
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.
13 See the GNU General Public License for more details.
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.
24 qsocket_t *net_activeSockets = NULL;
25 mempool_t *net_mempool;
27 qboolean ipxAvailable = false;
28 qboolean tcpipAvailable = false;
31 int DEFAULTnet_hostport = 26000;
33 char my_ipx_address[NET_NAMELEN];
34 char my_tcpip_address[NET_NAMELEN];
36 static qboolean listening = false;
38 qboolean slistInProgress = false;
39 qboolean slistSilent = false;
40 qboolean slistLocal = true;
41 static double slistStartTime;
42 static int slistLastShown;
44 static void Slist_Send(void);
45 static void Slist_Poll(void);
46 PollProcedure slistSendProcedure = {NULL, 0.0, Slist_Send};
47 PollProcedure slistPollProcedure = {NULL, 0.0, Slist_Poll};
50 sizebuf_t net_message;
51 int net_activeconnections = 0;
54 int messagesReceived = 0;
55 int unreliableMessagesSent = 0;
56 int unreliableMessagesReceived = 0;
58 cvar_t net_messagetimeout = {0, "net_messagetimeout","300"};
59 cvar_t hostname = {CVAR_SAVE, "hostname", "UNNAMED"};
61 qboolean configRestored = false;
63 // these two macros are to make the code more readable
64 #define sfunc net_drivers[sock->driver]
65 #define dfunc net_drivers[net_driverlevel]
72 double SetNetTime(void)
74 net_time = Sys_DoubleTime();
83 Called by drivers when a new communications endpoint is required
84 The sequence and buffer fields will be filled in properly
87 qsocket_t *NET_NewQSocket (void)
91 if (net_activeconnections >= svs.maxclients)
94 sock = Mem_Alloc(net_mempool, sizeof(qsocket_t));
96 // add it to active list
97 sock->next = net_activeSockets;
98 net_activeSockets = sock;
100 sock->disconnected = false;
101 sock->connecttime = net_time;
102 strcpy (sock->address,"UNSET ADDRESS");
103 sock->driver = net_driverlevel;
105 sock->driverdata = NULL;
106 sock->canSend = true;
107 sock->sendNext = false;
108 sock->lastMessageTime = net_time;
109 sock->ackSequence = 0;
110 sock->sendSequence = 0;
111 sock->unreliableSendSequence = 0;
112 sock->sendMessageLength = 0;
113 sock->receiveSequence = 0;
114 sock->unreliableReceiveSequence = 0;
115 sock->receiveMessageLength = 0;
121 void NET_FreeQSocket(qsocket_t *sock)
125 // remove it from active list
126 if (sock == net_activeSockets)
127 net_activeSockets = net_activeSockets->next;
130 for (s = net_activeSockets; s; s = s->next)
133 s->next = sock->next;
137 Sys_Error ("NET_FreeQSocket: not active\n");
144 static void NET_Listen_f (void)
146 if (Cmd_Argc () != 2)
148 Con_Printf ("\"listen\" is \"%u\"\n", listening ? 1 : 0);
152 listening = atoi(Cmd_Argv(1)) ? true : false;
154 for (net_driverlevel=0 ; net_driverlevel<net_numdrivers; net_driverlevel++)
156 if (net_drivers[net_driverlevel].initialized == false)
158 dfunc.Listen (listening);
163 static void MaxPlayers_f (void)
167 if (Cmd_Argc () != 2)
169 Con_Printf ("\"maxplayers\" is \"%u\"\n", svs.maxclients);
175 Con_Printf ("maxplayers can not be changed while a server is running.\n");
179 n = atoi(Cmd_Argv(1));
182 if (n > svs.maxclientslimit)
184 n = svs.maxclientslimit;
185 Con_Printf ("\"maxplayers\" set to \"%u\"\n", n);
188 if ((n == 1) && listening)
189 Cbuf_AddText ("listen 0\n");
191 if ((n > 1) && (!listening))
192 Cbuf_AddText ("listen 1\n");
198 static void NET_Port_f (void)
202 if (Cmd_Argc () != 2)
204 Con_Printf ("\"port\" is \"%u\"\n", net_hostport);
208 n = atoi(Cmd_Argv(1));
209 if (n < 1 || n > 65534)
211 Con_Printf ("Bad value, must be between 1 and 65534\n");
215 DEFAULTnet_hostport = n;
220 // force a change to the new port
221 Cbuf_AddText ("listen 0\n");
222 Cbuf_AddText ("listen 1\n");
227 static void PrintSlistHeader(void)
229 Con_Printf("Server Map Users\n");
230 Con_Printf("--------------- --------------- -----\n");
235 static void PrintSlist(void)
239 for (n = slistLastShown; n < hostCacheCount; n++)
241 if (hostcache[n].maxusers)
242 Con_Printf("%-15.15s %-15.15s %2u/%2u\n", hostcache[n].name, hostcache[n].map, hostcache[n].users, hostcache[n].maxusers);
244 Con_Printf("%-15.15s %-15.15s\n", hostcache[n].name, hostcache[n].map);
250 static void PrintSlistTrailer(void)
253 Con_Printf("== end list ==\n\n");
255 Con_Printf("No Quake servers found.\n\n");
259 void NET_Slist_f (void)
266 Con_Printf("Looking for Quake servers...\n");
270 slistInProgress = true;
271 slistStartTime = Sys_DoubleTime();
273 SchedulePollProcedure(&slistSendProcedure, 0.0);
274 SchedulePollProcedure(&slistPollProcedure, 0.1);
280 static void Slist_Send(void)
282 for (net_driverlevel=0; net_driverlevel < net_numdrivers; net_driverlevel++)
284 if (!slistLocal && net_driverlevel == 0)
286 if (net_drivers[net_driverlevel].initialized == false)
288 dfunc.SearchForHosts (true);
291 if ((Sys_DoubleTime() - slistStartTime) < 0.5)
292 SchedulePollProcedure(&slistSendProcedure, 0.75);
296 static void Slist_Poll(void)
298 for (net_driverlevel=0; net_driverlevel < net_numdrivers; net_driverlevel++)
300 if (!slistLocal && net_driverlevel == 0)
302 if (net_drivers[net_driverlevel].initialized == false)
304 dfunc.SearchForHosts (false);
310 if ((Sys_DoubleTime() - slistStartTime) < 1.5)
312 SchedulePollProcedure(&slistPollProcedure, 0.1);
318 slistInProgress = false;
330 int hostCacheCount = 0;
331 hostcache_t hostcache[HOSTCACHESIZE];
333 qsocket_t *NET_Connect (char *host)
337 int numdrivers = net_numdrivers;
341 if (host && *host == 0)
346 if (Q_strcasecmp (host, "local") == 0)
354 for (n = 0; n < hostCacheCount; n++)
355 if (Q_strcasecmp (host, hostcache[n].name) == 0)
357 host = hostcache[n].cname;
360 if (n < hostCacheCount)
365 slistSilent = host ? true : false;
368 while(slistInProgress)
373 if (hostCacheCount != 1)
375 host = hostcache[0].cname;
376 Con_Printf("Connecting to...\n%s @ %s\n\n", hostcache[0].name, host);
380 for (n = 0; n < hostCacheCount; n++)
381 if (Q_strcasecmp (host, hostcache[n].name) == 0)
383 host = hostcache[n].cname;
388 for (net_driverlevel=0 ; net_driverlevel<numdrivers; net_driverlevel++)
390 if (net_drivers[net_driverlevel].initialized == false)
392 ret = dfunc.Connect (host);
411 NET_CheckNewConnections
415 qsocket_t *NET_CheckNewConnections (void)
421 for (net_driverlevel=0 ; net_driverlevel<net_numdrivers; net_driverlevel++)
423 if (net_drivers[net_driverlevel].initialized == false)
425 if (net_driverlevel && listening == false)
427 ret = dfunc.CheckNewConnections ();
440 void NET_Close (qsocket_t *sock)
445 if (sock->disconnected)
450 // call the driver_Close function
453 NET_FreeQSocket(sock);
461 If there is a complete message, return it in net_message
463 returns 0 if no data is waiting
464 returns 1 if a message was received
465 returns -1 if connection is invalid
469 extern void PrintStats(qsocket_t *s);
471 int NET_GetMessage (qsocket_t *sock)
478 if (sock->disconnected)
480 Con_Printf("NET_GetMessage: disconnected socket\n");
486 ret = sfunc.QGetMessage(sock);
488 // see if this connection has timed out
489 if (ret == 0 && sock->driver)
491 if (net_time - sock->lastMessageTime > net_messagetimeout.value)
503 sock->lastMessageTime = net_time;
507 unreliableMessagesReceived++;
519 Try to send a complete length+message unit over the reliable stream.
520 returns 0 if the message cannot be delivered reliably, but the connection
521 is still considered valid
522 returns 1 if the message was sent properly
523 returns -1 if the connection died
526 int NET_SendMessage (qsocket_t *sock, sizebuf_t *data)
533 if (sock->disconnected)
535 Con_Printf("NET_SendMessage: disconnected socket\n");
540 r = sfunc.QSendMessage(sock, data);
541 if (r == 1 && sock->driver)
548 int NET_SendUnreliableMessage (qsocket_t *sock, sizebuf_t *data)
555 if (sock->disconnected)
557 Con_Printf("NET_SendMessage: disconnected socket\n");
562 r = sfunc.SendUnreliableMessage(sock, data);
563 if (r == 1 && sock->driver)
564 unreliableMessagesSent++;
574 Returns true or false if the given qsocket can currently accept a
575 message to be transmitted.
578 qboolean NET_CanSendMessage (qsocket_t *sock)
585 if (sock->disconnected)
590 r = sfunc.CanSendMessage(sock);
596 int NET_SendToAll(sizebuf_t *data, int blocktime)
601 qboolean state1 [MAX_SCOREBOARD];
602 qboolean state2 [MAX_SCOREBOARD];
604 for (i=0, host_client = svs.clients ; i<svs.maxclients ; i++, host_client++)
606 if (!host_client->netconnection)
608 if (host_client->active)
610 if (host_client->netconnection->driver == 0)
612 NET_SendMessage(host_client->netconnection, data);
628 start = Sys_DoubleTime();
632 for (i=0, host_client = svs.clients ; i<svs.maxclients ; i++, host_client++)
636 if (NET_CanSendMessage (host_client->netconnection))
639 NET_SendMessage(host_client->netconnection, data);
643 NET_GetMessage (host_client->netconnection);
651 if (NET_CanSendMessage (host_client->netconnection))
657 NET_GetMessage (host_client->netconnection);
663 if ((Sys_DoubleTime() - start) > blocktime)
670 //=============================================================================
683 i = COM_CheckParm ("-port");
685 i = COM_CheckParm ("-udpport");
687 i = COM_CheckParm ("-ipxport");
692 DEFAULTnet_hostport = atoi (com_argv[i+1]);
694 Sys_Error ("NET_Init: you must specify a number after -port");
696 net_hostport = DEFAULTnet_hostport;
698 if (COM_CheckParm("-listen") || cls.state == ca_dedicated || gamemode == GAME_BLOODBATH)
703 net_mempool = Mem_AllocPool("qsocket");
705 // allocate space for network message buffer
706 SZ_Alloc (&net_message, NET_MAXMESSAGE, "net_message");
708 Cvar_RegisterVariable (&net_messagetimeout);
709 Cvar_RegisterVariable (&hostname);
711 Cmd_AddCommand ("slist", NET_Slist_f);
712 Cmd_AddCommand ("listen", NET_Listen_f);
713 Cmd_AddCommand ("maxplayers", MaxPlayers_f);
714 Cmd_AddCommand ("port", NET_Port_f);
716 // initialize all the drivers
717 for (net_driverlevel=0 ; net_driverlevel<net_numdrivers ; net_driverlevel++)
719 controlSocket = net_drivers[net_driverlevel].Init();
720 if (controlSocket == -1)
722 net_drivers[net_driverlevel].initialized = true;
723 net_drivers[net_driverlevel].controlSock = controlSocket;
725 net_drivers[net_driverlevel].Listen (true);
729 Con_DPrintf("IPX address %s\n", my_ipx_address);
730 if (*my_tcpip_address)
731 Con_DPrintf("TCP/IP address %s\n", my_tcpip_address);
740 void NET_Shutdown (void)
744 while (net_activeSockets)
745 NET_Close(net_activeSockets);
748 // shutdown the drivers
750 for (net_driverlevel = 0; net_driverlevel < net_numdrivers; net_driverlevel++)
752 if (net_drivers[net_driverlevel].initialized == true)
754 net_drivers[net_driverlevel].Shutdown ();
755 net_drivers[net_driverlevel].initialized = false;
759 Mem_FreePool(&net_mempool);
763 static PollProcedure *pollProcedureList = NULL;
770 configRestored = true;
774 for (pp = pollProcedureList; pp; pp = pp->next)
776 if (pp->nextTime > net_time)
778 pollProcedureList = pp->next;
779 pp->procedure(pp->arg);
784 void SchedulePollProcedure(PollProcedure *proc, double timeOffset)
786 PollProcedure *pp, *prev;
788 proc->nextTime = Sys_DoubleTime() + timeOffset;
789 for (pp = pollProcedureList, prev = NULL; pp; pp = pp->next)
791 if (pp->nextTime >= proc->nextTime)
798 proc->next = pollProcedureList;
799 pollProcedureList = proc;