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"};
66 cvar_t developer_networking = {0, "developer_networking", "0"};
68 qboolean configRestored = false;
70 // these two macros are to make the code more readable
71 #define sfunc net_drivers[sock->driver]
72 #define dfunc net_drivers[net_driverlevel]
77 #define SLSERVERS 1024
81 typedef struct slserver_s
87 char mapname[SLMAPNAME];
88 char modname[SLMODNAME];
92 slserver_t sl_server[SLSERVERS];
93 int sl_numservers = 0;
95 void SL_ClearServers(void)
100 slserver_t *SL_FindServer(unsigned int ipaddr, unsigned short port)
104 for (i = 0, sl = sl_server;i < sl_numservers;i++, sl++)
105 if (sl->ipaddr == ipaddr && sl->port == port)
109 void SL_AddServer(unsigned int ipaddr, unsigned short port)
111 if (SL_FindServer(ipaddr, port))
113 memset(sl_server + sl_numservers, 0, sizeof(slserver_t));
114 sl_server[sl_numservers].ipaddr = ipaddr;
115 sl_server[sl_numservers].port = port;
116 sl_server[sl_numservers].ping = 0xFFFF;
120 void SL_UpdateServerName(unsigned int ipaddr, unsigned short port, const char *name);
124 sl = SL_FindServer(ipaddr, port);
127 memset(sl->name, 0, sizeof(sl->name));
128 namelen = strlen(name);
129 if (namelen > sizeof(sl->name) - 1)
130 namelen = sizeof(sl->name) - 1;
132 memcpy(sl->name, name, namelen);
135 void SL_UpdateServerModName(unsigned int ipaddr, unsigned short port, const char *name);
139 sl = SL_FindServer(ipaddr, port);
142 memset(sl->modname, 0, sizeof(sl->modname));
143 namelen = strlen(name);
144 if (namelen > sizeof(sl->modname) - 1)
145 namelen = sizeof(sl->modname) - 1;
147 memcpy(sl->modname, name, namelen);
150 void SL_UpdateServerMapName(unsigned int ipaddr, unsigned short port, const char *name);
154 sl = SL_FindServer(ipaddr, port);
157 memset(sl->mapname, 0, sizeof(sl->mapname));
158 namelen = strlen(name);
159 if (namelen > sizeof(sl->mapname) - 1)
160 namelen = sizeof(sl->mapname) - 1;
162 memcpy(sl->mapname, name, namelen);
165 void SL_UpdateServerPing(unsigned int ipaddr, unsigned short port, float ping);
169 sl = SL_FindServer(ipaddr, port);
173 sl->ping = bound(0, i, 9999);
180 double SetNetTime(void)
182 net_time = Sys_DoubleTime();
191 Called by drivers when a new communications endpoint is required
192 The sequence and buffer fields will be filled in properly
195 qsocket_t *NET_NewQSocket (void)
199 if (net_activeconnections >= svs.maxclients)
202 sock = Mem_Alloc(net_mempool, sizeof(qsocket_t));
204 // add it to active list
205 sock->next = net_activeSockets;
206 net_activeSockets = sock;
208 sock->disconnected = false;
209 sock->connecttime = net_time;
210 strcpy (sock->address,"UNSET ADDRESS");
211 sock->driver = net_driverlevel;
213 sock->driverdata = NULL;
214 sock->canSend = true;
215 sock->sendNext = false;
216 sock->lastMessageTime = net_time;
217 sock->ackSequence = 0;
218 sock->sendSequence = 0;
219 sock->unreliableSendSequence = 0;
220 sock->sendMessageLength = 0;
221 sock->receiveSequence = 0;
222 sock->unreliableReceiveSequence = 0;
223 sock->receiveMessageLength = 0;
229 void NET_FreeQSocket(qsocket_t *sock)
233 // remove it from active list
234 if (sock == net_activeSockets)
235 net_activeSockets = net_activeSockets->next;
238 for (s = net_activeSockets; s; s = s->next)
241 s->next = sock->next;
245 Sys_Error ("NET_FreeQSocket: not active\n");
252 static void NET_Listen_f (void)
254 if (Cmd_Argc () != 2)
256 Con_Printf ("\"listen\" is \"%u\"\n", listening ? 1 : 0);
260 listening = atoi(Cmd_Argv(1)) ? true : false;
262 for (net_driverlevel=0 ; net_driverlevel<net_numdrivers; net_driverlevel++)
264 if (net_drivers[net_driverlevel].initialized == false)
266 dfunc.Listen (listening);
271 static void MaxPlayers_f (void)
275 if (Cmd_Argc () != 2)
277 Con_Printf ("\"maxplayers\" is \"%u\"\n", svs.maxclients);
283 Con_Printf ("maxplayers can not be changed while a server is running.\n");
287 n = atoi(Cmd_Argv(1));
288 n = bound(1, n, MAX_SCOREBOARD);
289 if (svs.maxclients != n)
290 Con_Printf ("\"maxplayers\" set to \"%u\"\n", n);
292 if ((n == 1) && listening)
293 Cbuf_AddText ("listen 0\n");
295 if ((n > 1) && (!listening))
296 Cbuf_AddText ("listen 1\n");
302 static void NET_Port_f (void)
306 if (Cmd_Argc () != 2)
308 Con_Printf ("\"port\" is \"%u\"\n", net_hostport);
312 n = atoi(Cmd_Argv(1));
313 if (n < 1 || n > 65534)
315 Con_Printf ("Bad value, must be between 1 and 65534\n");
319 DEFAULTnet_hostport = n;
324 // force a change to the new port
325 Cbuf_AddText ("listen 0\n");
326 Cbuf_AddText ("listen 1\n");
331 static void NET_Heartbeat_f (void)
337 static void PrintSlistHeader(void)
339 Con_Printf("Server Map Users\n");
340 Con_Printf("--------------- --------------- -----\n");
345 static void PrintSlist(void)
349 for (n = slistLastShown; n < hostCacheCount; n++)
351 if (hostcache[n].maxusers)
352 Con_Printf("%-15.15s %-15.15s %2u/%2u\n", hostcache[n].name, hostcache[n].map, hostcache[n].users, hostcache[n].maxusers);
354 Con_Printf("%-15.15s %-15.15s\n", hostcache[n].name, hostcache[n].map);
360 static void PrintSlistTrailer(void)
363 Con_Printf("== end list ==\n\n");
365 Con_Printf("No %s servers found.\n\n", gamename);
369 void NET_SlistCommon (PollProcedure *sendProcedure, PollProcedure *pollProcedure)
376 Con_Printf("Looking for %s servers...\n", gamename);
380 slistInProgress = true;
381 slistStartTime = Sys_DoubleTime();
383 SchedulePollProcedure(sendProcedure, 0.0);
384 SchedulePollProcedure(pollProcedure, 0.1);
390 void NET_Slist_f (void)
392 NET_SlistCommon (&slistSendProcedure, &slistPollProcedure);
396 void NET_InetSlist_f (void)
398 NET_SlistCommon (&inetSlistSendProcedure, &inetSlistPollProcedure);
402 static void Slist_Send(void)
404 for (net_driverlevel=0; net_driverlevel < net_numdrivers; net_driverlevel++)
406 if (!slistLocal && net_driverlevel == 0)
408 if (net_drivers[net_driverlevel].initialized == false)
410 dfunc.SearchForHosts (true);
413 if ((Sys_DoubleTime() - slistStartTime) < 0.5)
414 SchedulePollProcedure(&slistSendProcedure, 0.75);
418 static void Slist_Poll(void)
420 for (net_driverlevel=0; net_driverlevel < net_numdrivers; net_driverlevel++)
422 if (!slistLocal && net_driverlevel == 0)
424 if (net_drivers[net_driverlevel].initialized == false)
426 dfunc.SearchForHosts (false);
432 if ((Sys_DoubleTime() - slistStartTime) < 1.5)
434 SchedulePollProcedure(&slistPollProcedure, 0.1);
440 slistInProgress = false;
446 static void InetSlist_Send(void)
450 if (!slistInProgress)
453 while ((host = Master_BuildGetServers ()) != NULL)
455 for (net_driverlevel=0; net_driverlevel < net_numdrivers; net_driverlevel++)
457 if (!slistLocal && net_driverlevel == 0)
459 if (net_drivers[net_driverlevel].initialized == false)
461 dfunc.SearchForInetHosts (host);
465 if ((Sys_DoubleTime() - slistStartTime) < 3.5)
466 SchedulePollProcedure(&inetSlistSendProcedure, 1.0);
470 static void InetSlist_Poll(void)
472 for (net_driverlevel=0; net_driverlevel < net_numdrivers; net_driverlevel++)
474 if (!slistLocal && net_driverlevel == 0)
476 if (net_drivers[net_driverlevel].initialized == false)
478 // We stop as soon as we have one answer (FIXME: bad...)
479 if (dfunc.SearchForInetHosts (NULL))
480 slistInProgress = false;
486 if (slistInProgress && (Sys_DoubleTime() - slistStartTime) < 4.0)
488 SchedulePollProcedure(&inetSlistPollProcedure, 0.1);
494 slistInProgress = false;
506 int hostCacheCount = 0;
507 hostcache_t hostcache[HOSTCACHESIZE];
509 qsocket_t *NET_Connect (char *host)
516 if (host && *host == 0)
521 if (strcasecmp (host, "local") == 0)
524 return dfunc.Connect (host);
529 for (n = 0; n < hostCacheCount; n++)
530 if (strcasecmp (host, hostcache[n].name) == 0)
532 host = hostcache[n].cname;
535 if (n < hostCacheCount)
540 slistSilent = host ? true : false;
543 while(slistInProgress)
548 if (hostCacheCount != 1)
550 host = hostcache[0].cname;
551 Con_Printf("Connecting to...\n%s @ %s\n\n", hostcache[0].name, host);
555 for (n = 0; n < hostCacheCount; n++)
556 if (strcasecmp (host, hostcache[n].name) == 0)
558 host = hostcache[n].cname;
563 for (net_driverlevel = 0;net_driverlevel < net_numdrivers;net_driverlevel++)
565 if (net_drivers[net_driverlevel].initialized == false)
567 ret = dfunc.Connect (host);
586 NET_CheckNewConnections
590 qsocket_t *NET_CheckNewConnections (void)
596 for (net_driverlevel=0 ; net_driverlevel<net_numdrivers; net_driverlevel++)
598 if (net_drivers[net_driverlevel].initialized == false)
600 if (net_driverlevel && listening == false)
602 ret = dfunc.CheckNewConnections ();
615 void NET_Close (qsocket_t *sock)
620 if (sock->disconnected)
625 // call the driver_Close function
628 NET_FreeQSocket(sock);
636 If there is a complete message, return it in net_message
638 returns 0 if no data is waiting
639 returns 1 if a message was received
640 returns -1 if connection is invalid
644 extern void PrintStats(qsocket_t *s);
646 int NET_GetMessage (qsocket_t *sock)
653 if (sock->disconnected)
655 Con_Printf("NET_GetMessage: disconnected socket\n");
661 ret = sfunc.QGetMessage(sock);
663 // see if this connection has timed out
664 if (ret == 0 && sock->driver)
666 if (net_time - sock->lastMessageTime > net_messagetimeout.value)
678 sock->lastMessageTime = net_time;
682 unreliableMessagesReceived++;
694 Try to send a complete length+message unit over the reliable stream.
695 returns 0 if the message cannot be delivered reliably, but the connection
696 is still considered valid
697 returns 1 if the message was sent properly
698 returns -1 if the connection died
701 int NET_SendMessage (qsocket_t *sock, sizebuf_t *data)
708 if (sock->disconnected)
710 Con_Printf("NET_SendMessage: disconnected socket\n");
715 r = sfunc.QSendMessage(sock, data);
716 if (r == 1 && sock->driver)
723 int NET_SendUnreliableMessage (qsocket_t *sock, sizebuf_t *data)
730 if (sock->disconnected)
732 Con_Printf("NET_SendMessage: disconnected socket\n");
737 r = sfunc.SendUnreliableMessage(sock, data);
738 if (r == 1 && sock->driver)
739 unreliableMessagesSent++;
749 Returns true or false if the given qsocket can currently accept a
750 message to be transmitted.
753 qboolean NET_CanSendMessage (qsocket_t *sock)
760 if (sock->disconnected)
765 r = sfunc.CanSendMessage(sock);
775 Send an heartbeat to the master server(s)
778 void NET_Heartbeat (int priority)
782 if (! Master_AllowHeartbeat (priority))
785 while ((host = Master_BuildHeartbeat ()) != NULL)
787 for (net_driverlevel=0 ; net_driverlevel<net_numdrivers; net_driverlevel++)
789 if (net_drivers[net_driverlevel].initialized == false)
791 if (net_driverlevel && listening == false)
793 dfunc.Heartbeat (host);
799 int NET_SendToAll(sizebuf_t *data, int blocktime)
804 qbyte state [MAX_SCOREBOARD];
806 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
809 if (host_client->netconnection && host_client->active)
811 if (host_client->netconnection->driver == 0)
812 NET_SendMessage(host_client->netconnection, data);
818 // for every player (simultaneously) wait for the first CanSendMessage
819 // and send the message, then wait for a second CanSendMessage (verifying
821 start = Sys_DoubleTime();
825 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
830 // need to send to this one
831 if (NET_CanSendMessage (host_client->netconnection))
833 if (state[i] == 0 && NET_SendMessage (host_client->netconnection, data) == -1)
834 state[i] = 2; // connection lost
838 NET_GetMessage (host_client->netconnection);
842 while (count && (Sys_DoubleTime() - start) < blocktime);
847 //=============================================================================
860 i = COM_CheckParm ("-port");
862 i = COM_CheckParm ("-udpport");
864 i = COM_CheckParm ("-ipxport");
869 DEFAULTnet_hostport = atoi (com_argv[i+1]);
871 Sys_Error ("NET_Init: you must specify a number after -port");
873 net_hostport = DEFAULTnet_hostport;
875 if (COM_CheckParm("-listen") || cls.state == ca_dedicated || gamemode == GAME_TRANSFUSION)
880 net_mempool = Mem_AllocPool("qsocket");
882 // allocate space for network message buffer
883 SZ_Alloc (&net_message, NET_MAXMESSAGE, "net_message");
885 Cvar_RegisterVariable (&net_messagetimeout);
886 Cvar_RegisterVariable (&hostname);
887 Cvar_RegisterVariable (&developer_networking);
889 Cmd_AddCommand ("net_slist", NET_Slist_f);
890 Cmd_AddCommand ("net_inetslist", NET_InetSlist_f);
891 Cmd_AddCommand ("listen", NET_Listen_f);
892 Cmd_AddCommand ("maxplayers", MaxPlayers_f);
893 Cmd_AddCommand ("port", NET_Port_f);
894 Cmd_AddCommand ("heartbeat", NET_Heartbeat_f);
896 // initialize all the drivers
897 for (net_driverlevel=0 ; net_driverlevel<net_numdrivers ; net_driverlevel++)
899 controlSocket = net_drivers[net_driverlevel].Init();
900 if (controlSocket == -1)
902 net_drivers[net_driverlevel].initialized = true;
903 net_drivers[net_driverlevel].controlSock = controlSocket;
905 net_drivers[net_driverlevel].Listen (true);
909 Con_DPrintf("IPX address %s\n", my_ipx_address);
910 if (*my_tcpip_address)
911 Con_DPrintf("TCP/IP address %s\n", my_tcpip_address);
922 void NET_Shutdown (void)
926 while (net_activeSockets)
927 NET_Close(net_activeSockets);
930 // shutdown the drivers
932 for (net_driverlevel = 0; net_driverlevel < net_numdrivers; net_driverlevel++)
934 if (net_drivers[net_driverlevel].initialized == true)
936 net_drivers[net_driverlevel].Shutdown ();
937 net_drivers[net_driverlevel].initialized = false;
941 Mem_FreePool(&net_mempool);
945 static PollProcedure *pollProcedureList = NULL;
952 configRestored = true;
956 for (pp = pollProcedureList; pp; pp = pp->next)
958 if (pp->nextTime > net_time)
960 pollProcedureList = pp->next;
961 pp->procedure(pp->arg);
966 void SchedulePollProcedure(PollProcedure *proc, double timeOffset)
968 PollProcedure *pp, *prev;
970 proc->nextTime = Sys_DoubleTime() + timeOffset;
971 for (pp = pollProcedureList, prev = NULL; pp; pp = pp->next)
973 if (pp->nextTime >= proc->nextTime)
980 proc->next = pollProcedureList;
981 pollProcedureList = proc;