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.
23 #include "net_master.h"
25 qsocket_t *net_activeSockets = NULL;
26 mempool_t *net_mempool;
28 qboolean ipxAvailable = false;
29 qboolean tcpipAvailable = false;
32 int DEFAULTnet_hostport = 26000;
34 char my_ipx_address[NET_NAMELEN];
35 char my_tcpip_address[NET_NAMELEN];
37 static qboolean listening = false;
39 qboolean slistInProgress = false;
40 qboolean slistSilent = false;
41 qboolean slistLocal = true;
42 static double slistStartTime;
43 static int slistLastShown;
45 static void Slist_Send(void);
46 static void Slist_Poll(void);
47 PollProcedure slistSendProcedure = {NULL, 0.0, Slist_Send};
48 PollProcedure slistPollProcedure = {NULL, 0.0, Slist_Poll};
50 static void InetSlist_Send(void);
51 static void InetSlist_Poll(void);
52 PollProcedure inetSlistSendProcedure = {NULL, 0.0, InetSlist_Send};
53 PollProcedure inetSlistPollProcedure = {NULL, 0.0, InetSlist_Poll};
56 sizebuf_t net_message;
57 int net_activeconnections = 0;
60 int messagesReceived = 0;
61 int unreliableMessagesSent = 0;
62 int unreliableMessagesReceived = 0;
64 cvar_t net_messagetimeout = {0, "net_messagetimeout","300"};
65 cvar_t hostname = {CVAR_SAVE, "hostname", "UNNAMED"};
67 qboolean configRestored = false;
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]
78 double SetNetTime(void)
80 net_time = Sys_DoubleTime();
89 Called by drivers when a new communications endpoint is required
90 The sequence and buffer fields will be filled in properly
93 qsocket_t *NET_NewQSocket (void)
97 if (net_activeconnections >= svs.maxclients)
100 sock = Mem_Alloc(net_mempool, sizeof(qsocket_t));
102 // add it to active list
103 sock->next = net_activeSockets;
104 net_activeSockets = sock;
106 sock->disconnected = false;
107 sock->connecttime = net_time;
108 strcpy (sock->address,"UNSET ADDRESS");
109 sock->driver = net_driverlevel;
111 sock->driverdata = NULL;
112 sock->canSend = true;
113 sock->sendNext = false;
114 sock->lastMessageTime = net_time;
115 sock->ackSequence = 0;
116 sock->sendSequence = 0;
117 sock->unreliableSendSequence = 0;
118 sock->sendMessageLength = 0;
119 sock->receiveSequence = 0;
120 sock->unreliableReceiveSequence = 0;
121 sock->receiveMessageLength = 0;
127 void NET_FreeQSocket(qsocket_t *sock)
131 // remove it from active list
132 if (sock == net_activeSockets)
133 net_activeSockets = net_activeSockets->next;
136 for (s = net_activeSockets; s; s = s->next)
139 s->next = sock->next;
143 Sys_Error ("NET_FreeQSocket: not active\n");
150 static void NET_Listen_f (void)
152 if (Cmd_Argc () != 2)
154 Con_Printf ("\"listen\" is \"%u\"\n", listening ? 1 : 0);
158 listening = atoi(Cmd_Argv(1)) ? true : false;
160 for (net_driverlevel=0 ; net_driverlevel<net_numdrivers; net_driverlevel++)
162 if (net_drivers[net_driverlevel].initialized == false)
164 dfunc.Listen (listening);
169 static void MaxPlayers_f (void)
173 if (Cmd_Argc () != 2)
175 Con_Printf ("\"maxplayers\" is \"%u\"\n", svs.maxclients);
181 Con_Printf ("maxplayers can not be changed while a server is running.\n");
185 n = atoi(Cmd_Argv(1));
186 n = bound(1, n, MAX_SCOREBOARD);
187 if (svs.maxclients != n)
188 Con_Printf ("\"maxplayers\" set to \"%u\"\n", n);
190 if ((n == 1) && listening)
191 Cbuf_AddText ("listen 0\n");
193 if ((n > 1) && (!listening))
194 Cbuf_AddText ("listen 1\n");
200 static void NET_Port_f (void)
204 if (Cmd_Argc () != 2)
206 Con_Printf ("\"port\" is \"%u\"\n", net_hostport);
210 n = atoi(Cmd_Argv(1));
211 if (n < 1 || n > 65534)
213 Con_Printf ("Bad value, must be between 1 and 65534\n");
217 DEFAULTnet_hostport = n;
222 // force a change to the new port
223 Cbuf_AddText ("listen 0\n");
224 Cbuf_AddText ("listen 1\n");
229 static void NET_Heartbeat_f (void)
235 static void PrintSlistHeader(void)
237 Con_Printf("Server Map Users\n");
238 Con_Printf("--------------- --------------- -----\n");
243 static void PrintSlist(void)
247 for (n = slistLastShown; n < hostCacheCount; n++)
249 if (hostcache[n].maxusers)
250 Con_Printf("%-15.15s %-15.15s %2u/%2u\n", hostcache[n].name, hostcache[n].map, hostcache[n].users, hostcache[n].maxusers);
252 Con_Printf("%-15.15s %-15.15s\n", hostcache[n].name, hostcache[n].map);
258 static void PrintSlistTrailer(void)
261 Con_Printf("== end list ==\n\n");
263 Con_Printf("No Quake servers found.\n\n");
267 void NET_Slist_f (void)
274 Con_Printf("Looking for Quake servers...\n");
278 slistInProgress = true;
279 slistStartTime = Sys_DoubleTime();
281 SchedulePollProcedure(&slistSendProcedure, 0.0);
282 SchedulePollProcedure(&slistPollProcedure, 0.1);
288 void NET_InetSlist_f (void)
295 Con_Printf("Looking for Quake servers...\n");
299 slistInProgress = true;
300 slistStartTime = Sys_DoubleTime();
302 SchedulePollProcedure(&inetSlistSendProcedure, 0.0);
303 SchedulePollProcedure(&inetSlistPollProcedure, 0.1);
309 static void Slist_Send(void)
311 for (net_driverlevel=0; net_driverlevel < net_numdrivers; net_driverlevel++)
313 if (!slistLocal && net_driverlevel == 0)
315 if (net_drivers[net_driverlevel].initialized == false)
317 dfunc.SearchForHosts (true);
320 if ((Sys_DoubleTime() - slistStartTime) < 0.5)
321 SchedulePollProcedure(&slistSendProcedure, 0.75);
325 static void Slist_Poll(void)
327 for (net_driverlevel=0; net_driverlevel < net_numdrivers; net_driverlevel++)
329 if (!slistLocal && net_driverlevel == 0)
331 if (net_drivers[net_driverlevel].initialized == false)
333 dfunc.SearchForHosts (false);
339 if ((Sys_DoubleTime() - slistStartTime) < 1.5)
341 SchedulePollProcedure(&slistPollProcedure, 0.1);
347 slistInProgress = false;
353 static void InetSlist_Send(void)
357 if (!slistInProgress)
360 while ((host = Master_BuildGetServers ()) != NULL)
362 for (net_driverlevel=0; net_driverlevel < net_numdrivers; net_driverlevel++)
364 if (!slistLocal && net_driverlevel == 0)
366 if (net_drivers[net_driverlevel].initialized == false)
368 dfunc.SearchForInetHosts (host);
372 if ((Sys_DoubleTime() - slistStartTime) < 3.5)
373 SchedulePollProcedure(&inetSlistSendProcedure, 1.0);
377 static void InetSlist_Poll(void)
379 for (net_driverlevel=0; net_driverlevel < net_numdrivers; net_driverlevel++)
381 if (!slistLocal && net_driverlevel == 0)
383 if (net_drivers[net_driverlevel].initialized == false)
385 // We stop as soon as we have one answer (FIXME: bad...)
386 if (dfunc.SearchForInetHosts (NULL))
387 slistInProgress = false;
393 if (slistInProgress && (Sys_DoubleTime() - slistStartTime) < 4.0)
395 SchedulePollProcedure(&inetSlistPollProcedure, 0.1);
401 slistInProgress = false;
413 int hostCacheCount = 0;
414 hostcache_t hostcache[HOSTCACHESIZE];
416 qsocket_t *NET_Connect (char *host)
420 int numdrivers = net_numdrivers;
424 if (host && *host == 0)
429 if (Q_strcasecmp (host, "local") == 0)
437 for (n = 0; n < hostCacheCount; n++)
438 if (Q_strcasecmp (host, hostcache[n].name) == 0)
440 host = hostcache[n].cname;
443 if (n < hostCacheCount)
448 slistSilent = host ? true : false;
451 while(slistInProgress)
456 if (hostCacheCount != 1)
458 host = hostcache[0].cname;
459 Con_Printf("Connecting to...\n%s @ %s\n\n", hostcache[0].name, host);
463 for (n = 0; n < hostCacheCount; n++)
464 if (Q_strcasecmp (host, hostcache[n].name) == 0)
466 host = hostcache[n].cname;
471 for (net_driverlevel=0 ; net_driverlevel<numdrivers; net_driverlevel++)
473 if (net_drivers[net_driverlevel].initialized == false)
475 ret = dfunc.Connect (host);
494 NET_CheckNewConnections
498 qsocket_t *NET_CheckNewConnections (void)
504 for (net_driverlevel=0 ; net_driverlevel<net_numdrivers; net_driverlevel++)
506 if (net_drivers[net_driverlevel].initialized == false)
508 if (net_driverlevel && listening == false)
510 ret = dfunc.CheckNewConnections ();
523 void NET_Close (qsocket_t *sock)
528 if (sock->disconnected)
533 // call the driver_Close function
536 NET_FreeQSocket(sock);
544 If there is a complete message, return it in net_message
546 returns 0 if no data is waiting
547 returns 1 if a message was received
548 returns -1 if connection is invalid
552 extern void PrintStats(qsocket_t *s);
554 int NET_GetMessage (qsocket_t *sock)
561 if (sock->disconnected)
563 Con_Printf("NET_GetMessage: disconnected socket\n");
569 ret = sfunc.QGetMessage(sock);
571 // see if this connection has timed out
572 if (ret == 0 && sock->driver)
574 if (net_time - sock->lastMessageTime > net_messagetimeout.value)
586 sock->lastMessageTime = net_time;
590 unreliableMessagesReceived++;
602 Try to send a complete length+message unit over the reliable stream.
603 returns 0 if the message cannot be delivered reliably, but the connection
604 is still considered valid
605 returns 1 if the message was sent properly
606 returns -1 if the connection died
609 int NET_SendMessage (qsocket_t *sock, sizebuf_t *data)
616 if (sock->disconnected)
618 Con_Printf("NET_SendMessage: disconnected socket\n");
623 r = sfunc.QSendMessage(sock, data);
624 if (r == 1 && sock->driver)
631 int NET_SendUnreliableMessage (qsocket_t *sock, sizebuf_t *data)
638 if (sock->disconnected)
640 Con_Printf("NET_SendMessage: disconnected socket\n");
645 r = sfunc.SendUnreliableMessage(sock, data);
646 if (r == 1 && sock->driver)
647 unreliableMessagesSent++;
657 Returns true or false if the given qsocket can currently accept a
658 message to be transmitted.
661 qboolean NET_CanSendMessage (qsocket_t *sock)
668 if (sock->disconnected)
673 r = sfunc.CanSendMessage(sock);
683 Send an heartbeat to the master server(s)
686 void NET_Heartbeat (void)
689 while ((host = Master_BuildHeartbeat ()) != NULL)
691 for (net_driverlevel=0 ; net_driverlevel<net_numdrivers; net_driverlevel++)
693 if (net_drivers[net_driverlevel].initialized == false)
695 if (net_driverlevel && listening == false)
697 dfunc.Heartbeat (host);
703 int NET_SendToAll(sizebuf_t *data, int blocktime)
708 qboolean state1 [MAX_SCOREBOARD];
709 qboolean state2 [MAX_SCOREBOARD];
711 for (i=0, host_client = svs.clients ; i<svs.maxclients ; i++, host_client++)
713 if (!host_client->netconnection)
715 if (host_client->active)
717 if (host_client->netconnection->driver == 0)
719 NET_SendMessage(host_client->netconnection, data);
735 start = Sys_DoubleTime();
739 for (i=0, host_client = svs.clients ; i<svs.maxclients ; i++, host_client++)
743 if (NET_CanSendMessage (host_client->netconnection))
746 NET_SendMessage(host_client->netconnection, data);
750 NET_GetMessage (host_client->netconnection);
758 if (NET_CanSendMessage (host_client->netconnection))
764 NET_GetMessage (host_client->netconnection);
770 if ((Sys_DoubleTime() - start) > blocktime)
777 //=============================================================================
790 i = COM_CheckParm ("-port");
792 i = COM_CheckParm ("-udpport");
794 i = COM_CheckParm ("-ipxport");
799 DEFAULTnet_hostport = atoi (com_argv[i+1]);
801 Sys_Error ("NET_Init: you must specify a number after -port");
803 net_hostport = DEFAULTnet_hostport;
805 if (COM_CheckParm("-listen") || cls.state == ca_dedicated || gamemode == GAME_TRANSFUSION)
810 net_mempool = Mem_AllocPool("qsocket");
812 // allocate space for network message buffer
813 SZ_Alloc (&net_message, NET_MAXMESSAGE, "net_message");
815 Cvar_RegisterVariable (&net_messagetimeout);
816 Cvar_RegisterVariable (&hostname);
818 Cmd_AddCommand ("net_slist", NET_Slist_f);
819 Cmd_AddCommand ("net_inetslist", NET_InetSlist_f);
820 Cmd_AddCommand ("listen", NET_Listen_f);
821 Cmd_AddCommand ("maxplayers", MaxPlayers_f);
822 Cmd_AddCommand ("port", NET_Port_f);
823 Cmd_AddCommand ("heartbeat", NET_Heartbeat_f);
825 // initialize all the drivers
826 for (net_driverlevel=0 ; net_driverlevel<net_numdrivers ; net_driverlevel++)
828 controlSocket = net_drivers[net_driverlevel].Init();
829 if (controlSocket == -1)
831 net_drivers[net_driverlevel].initialized = true;
832 net_drivers[net_driverlevel].controlSock = controlSocket;
834 net_drivers[net_driverlevel].Listen (true);
838 Con_DPrintf("IPX address %s\n", my_ipx_address);
839 if (*my_tcpip_address)
840 Con_DPrintf("TCP/IP address %s\n", my_tcpip_address);
851 void NET_Shutdown (void)
855 while (net_activeSockets)
856 NET_Close(net_activeSockets);
859 // shutdown the drivers
861 for (net_driverlevel = 0; net_driverlevel < net_numdrivers; net_driverlevel++)
863 if (net_drivers[net_driverlevel].initialized == true)
865 net_drivers[net_driverlevel].Shutdown ();
866 net_drivers[net_driverlevel].initialized = false;
870 Mem_FreePool(&net_mempool);
874 static PollProcedure *pollProcedureList = NULL;
881 configRestored = true;
885 for (pp = pollProcedureList; pp; pp = pp->next)
887 if (pp->nextTime > net_time)
889 pollProcedureList = pp->next;
890 pp->procedure(pp->arg);
895 void SchedulePollProcedure(PollProcedure *proc, double timeOffset)
897 PollProcedure *pp, *prev;
899 proc->nextTime = Sys_DoubleTime() + timeOffset;
900 for (pp = pollProcedureList, prev = NULL; pp; pp = pp->next)
902 if (pp->nextTime >= proc->nextTime)
909 proc->next = pollProcedureList;
910 pollProcedureList = proc;