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");
264 if (gamemode == GAME_TRANSFUSION)
265 Con_Printf("No Transfusion servers found.\n\n");
267 Con_Printf("No Quake servers found.\n\n");
272 void NET_SlistCommon (PollProcedure *sendProcedure, PollProcedure *pollProcedure)
279 if (gamemode == GAME_TRANSFUSION)
280 Con_Printf("Looking for Transfusion servers...\n");
282 Con_Printf("Looking for Quake servers...\n");
286 slistInProgress = true;
287 slistStartTime = Sys_DoubleTime();
289 SchedulePollProcedure(sendProcedure, 0.0);
290 SchedulePollProcedure(pollProcedure, 0.1);
296 void NET_Slist_f (void)
298 NET_SlistCommon (&slistSendProcedure, &slistPollProcedure);
302 void NET_InetSlist_f (void)
304 NET_SlistCommon (&inetSlistSendProcedure, &inetSlistPollProcedure);
308 static void Slist_Send(void)
310 for (net_driverlevel=0; net_driverlevel < net_numdrivers; net_driverlevel++)
312 if (!slistLocal && net_driverlevel == 0)
314 if (net_drivers[net_driverlevel].initialized == false)
316 dfunc.SearchForHosts (true);
319 if ((Sys_DoubleTime() - slistStartTime) < 0.5)
320 SchedulePollProcedure(&slistSendProcedure, 0.75);
324 static void Slist_Poll(void)
326 for (net_driverlevel=0; net_driverlevel < net_numdrivers; net_driverlevel++)
328 if (!slistLocal && net_driverlevel == 0)
330 if (net_drivers[net_driverlevel].initialized == false)
332 dfunc.SearchForHosts (false);
338 if ((Sys_DoubleTime() - slistStartTime) < 1.5)
340 SchedulePollProcedure(&slistPollProcedure, 0.1);
346 slistInProgress = false;
352 static void InetSlist_Send(void)
356 if (!slistInProgress)
359 while ((host = Master_BuildGetServers ()) != NULL)
361 for (net_driverlevel=0; net_driverlevel < net_numdrivers; net_driverlevel++)
363 if (!slistLocal && net_driverlevel == 0)
365 if (net_drivers[net_driverlevel].initialized == false)
367 dfunc.SearchForInetHosts (host);
371 if ((Sys_DoubleTime() - slistStartTime) < 3.5)
372 SchedulePollProcedure(&inetSlistSendProcedure, 1.0);
376 static void InetSlist_Poll(void)
378 for (net_driverlevel=0; net_driverlevel < net_numdrivers; net_driverlevel++)
380 if (!slistLocal && net_driverlevel == 0)
382 if (net_drivers[net_driverlevel].initialized == false)
384 // We stop as soon as we have one answer (FIXME: bad...)
385 if (dfunc.SearchForInetHosts (NULL))
386 slistInProgress = false;
392 if (slistInProgress && (Sys_DoubleTime() - slistStartTime) < 4.0)
394 SchedulePollProcedure(&inetSlistPollProcedure, 0.1);
400 slistInProgress = false;
412 int hostCacheCount = 0;
413 hostcache_t hostcache[HOSTCACHESIZE];
415 qsocket_t *NET_Connect (char *host)
419 int numdrivers = net_numdrivers;
423 if (host && *host == 0)
428 if (Q_strcasecmp (host, "local") == 0)
436 for (n = 0; n < hostCacheCount; n++)
437 if (Q_strcasecmp (host, hostcache[n].name) == 0)
439 host = hostcache[n].cname;
442 if (n < hostCacheCount)
447 slistSilent = host ? true : false;
450 while(slistInProgress)
455 if (hostCacheCount != 1)
457 host = hostcache[0].cname;
458 Con_Printf("Connecting to...\n%s @ %s\n\n", hostcache[0].name, host);
462 for (n = 0; n < hostCacheCount; n++)
463 if (Q_strcasecmp (host, hostcache[n].name) == 0)
465 host = hostcache[n].cname;
470 for (net_driverlevel=0 ; net_driverlevel<numdrivers; net_driverlevel++)
472 if (net_drivers[net_driverlevel].initialized == false)
474 ret = dfunc.Connect (host);
493 NET_CheckNewConnections
497 qsocket_t *NET_CheckNewConnections (void)
503 for (net_driverlevel=0 ; net_driverlevel<net_numdrivers; net_driverlevel++)
505 if (net_drivers[net_driverlevel].initialized == false)
507 if (net_driverlevel && listening == false)
509 ret = dfunc.CheckNewConnections ();
522 void NET_Close (qsocket_t *sock)
527 if (sock->disconnected)
532 // call the driver_Close function
535 NET_FreeQSocket(sock);
543 If there is a complete message, return it in net_message
545 returns 0 if no data is waiting
546 returns 1 if a message was received
547 returns -1 if connection is invalid
551 extern void PrintStats(qsocket_t *s);
553 int NET_GetMessage (qsocket_t *sock)
560 if (sock->disconnected)
562 Con_Printf("NET_GetMessage: disconnected socket\n");
568 ret = sfunc.QGetMessage(sock);
570 // see if this connection has timed out
571 if (ret == 0 && sock->driver)
573 if (net_time - sock->lastMessageTime > net_messagetimeout.value)
585 sock->lastMessageTime = net_time;
589 unreliableMessagesReceived++;
601 Try to send a complete length+message unit over the reliable stream.
602 returns 0 if the message cannot be delivered reliably, but the connection
603 is still considered valid
604 returns 1 if the message was sent properly
605 returns -1 if the connection died
608 int NET_SendMessage (qsocket_t *sock, sizebuf_t *data)
615 if (sock->disconnected)
617 Con_Printf("NET_SendMessage: disconnected socket\n");
622 r = sfunc.QSendMessage(sock, data);
623 if (r == 1 && sock->driver)
630 int NET_SendUnreliableMessage (qsocket_t *sock, sizebuf_t *data)
637 if (sock->disconnected)
639 Con_Printf("NET_SendMessage: disconnected socket\n");
644 r = sfunc.SendUnreliableMessage(sock, data);
645 if (r == 1 && sock->driver)
646 unreliableMessagesSent++;
656 Returns true or false if the given qsocket can currently accept a
657 message to be transmitted.
660 qboolean NET_CanSendMessage (qsocket_t *sock)
667 if (sock->disconnected)
672 r = sfunc.CanSendMessage(sock);
682 Send an heartbeat to the master server(s)
685 void NET_Heartbeat (int priority)
689 if (! Master_AllowHeartbeat (priority))
692 while ((host = Master_BuildHeartbeat ()) != NULL)
694 for (net_driverlevel=0 ; net_driverlevel<net_numdrivers; net_driverlevel++)
696 if (net_drivers[net_driverlevel].initialized == false)
698 if (net_driverlevel && listening == false)
700 dfunc.Heartbeat (host);
706 int NET_SendToAll(sizebuf_t *data, int blocktime)
711 qboolean state1 [MAX_SCOREBOARD];
712 qboolean state2 [MAX_SCOREBOARD];
714 for (i=0, host_client = svs.clients ; i<svs.maxclients ; i++, host_client++)
716 if (!host_client->netconnection)
718 if (host_client->active)
720 if (host_client->netconnection->driver == 0)
722 NET_SendMessage(host_client->netconnection, data);
738 start = Sys_DoubleTime();
742 for (i=0, host_client = svs.clients ; i<svs.maxclients ; i++, host_client++)
746 if (NET_CanSendMessage (host_client->netconnection))
749 NET_SendMessage(host_client->netconnection, data);
753 NET_GetMessage (host_client->netconnection);
761 if (NET_CanSendMessage (host_client->netconnection))
767 NET_GetMessage (host_client->netconnection);
773 if ((Sys_DoubleTime() - start) > blocktime)
780 //=============================================================================
793 i = COM_CheckParm ("-port");
795 i = COM_CheckParm ("-udpport");
797 i = COM_CheckParm ("-ipxport");
802 DEFAULTnet_hostport = atoi (com_argv[i+1]);
804 Sys_Error ("NET_Init: you must specify a number after -port");
806 net_hostport = DEFAULTnet_hostport;
808 if (COM_CheckParm("-listen") || cls.state == ca_dedicated || gamemode == GAME_TRANSFUSION)
813 net_mempool = Mem_AllocPool("qsocket");
815 // allocate space for network message buffer
816 SZ_Alloc (&net_message, NET_MAXMESSAGE, "net_message");
818 Cvar_RegisterVariable (&net_messagetimeout);
819 Cvar_RegisterVariable (&hostname);
821 Cmd_AddCommand ("net_slist", NET_Slist_f);
822 Cmd_AddCommand ("net_inetslist", NET_InetSlist_f);
823 Cmd_AddCommand ("listen", NET_Listen_f);
824 Cmd_AddCommand ("maxplayers", MaxPlayers_f);
825 Cmd_AddCommand ("port", NET_Port_f);
826 Cmd_AddCommand ("heartbeat", NET_Heartbeat_f);
828 // initialize all the drivers
829 for (net_driverlevel=0 ; net_driverlevel<net_numdrivers ; net_driverlevel++)
831 controlSocket = net_drivers[net_driverlevel].Init();
832 if (controlSocket == -1)
834 net_drivers[net_driverlevel].initialized = true;
835 net_drivers[net_driverlevel].controlSock = controlSocket;
837 net_drivers[net_driverlevel].Listen (true);
841 Con_DPrintf("IPX address %s\n", my_ipx_address);
842 if (*my_tcpip_address)
843 Con_DPrintf("TCP/IP address %s\n", my_tcpip_address);
854 void NET_Shutdown (void)
858 while (net_activeSockets)
859 NET_Close(net_activeSockets);
862 // shutdown the drivers
864 for (net_driverlevel = 0; net_driverlevel < net_numdrivers; net_driverlevel++)
866 if (net_drivers[net_driverlevel].initialized == true)
868 net_drivers[net_driverlevel].Shutdown ();
869 net_drivers[net_driverlevel].initialized = false;
873 Mem_FreePool(&net_mempool);
877 static PollProcedure *pollProcedureList = NULL;
884 configRestored = true;
888 for (pp = pollProcedureList; pp; pp = pp->next)
890 if (pp->nextTime > net_time)
892 pollProcedureList = pp->next;
893 pp->procedure(pp->arg);
898 void SchedulePollProcedure(PollProcedure *proc, double timeOffset)
900 PollProcedure *pp, *prev;
902 proc->nextTime = Sys_DoubleTime() + timeOffset;
903 for (pp = pollProcedureList, prev = NULL; pp; pp = pp->next)
905 if (pp->nextTime >= proc->nextTime)
912 proc->next = pollProcedureList;
913 pollProcedureList = proc;