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 Address Name/Description Map Users\n");
340 Con_Printf("--------------------- ---------------------------------- --------------- -----\n");
345 static void PrintSlist(void)
348 for (n = slistLastShown; n < hostCacheCount; n++)
349 Con_Printf("%-21.21s %-34.34s %-15.15s %2u/%2u\n", hostcache[n].cname, hostcache[n].name, hostcache[n].map, hostcache[n].users, hostcache[n].maxusers);
354 static void PrintSlistTrailer(void)
357 Con_Printf("== end list ==\n\n");
359 Con_Printf("No %s servers found.\n\n", gamename);
363 void NET_SlistCommon (PollProcedure *sendProcedure, PollProcedure *pollProcedure)
370 Con_Printf("Looking for %s servers...\n", gamename);
374 slistInProgress = true;
375 slistStartTime = Sys_DoubleTime();
377 SchedulePollProcedure(sendProcedure, 0.0);
378 SchedulePollProcedure(pollProcedure, 0.1);
384 void NET_Slist_f (void)
386 NET_SlistCommon (&slistSendProcedure, &slistPollProcedure);
390 void NET_InetSlist_f (void)
392 NET_SlistCommon (&inetSlistSendProcedure, &inetSlistPollProcedure);
396 static void Slist_Send(void)
398 for (net_driverlevel=0; net_driverlevel < net_numdrivers; net_driverlevel++)
400 if (!slistLocal && net_driverlevel == 0)
402 if (net_drivers[net_driverlevel].initialized == false)
404 dfunc.SearchForHosts (true);
407 if ((Sys_DoubleTime() - slistStartTime) < 0.5)
408 SchedulePollProcedure(&slistSendProcedure, 0.75);
412 static void Slist_Poll(void)
414 for (net_driverlevel=0; net_driverlevel < net_numdrivers; net_driverlevel++)
416 if (!slistLocal && net_driverlevel == 0)
418 if (net_drivers[net_driverlevel].initialized == false)
420 dfunc.SearchForHosts (false);
426 if ((Sys_DoubleTime() - slistStartTime) < 1.5)
428 SchedulePollProcedure(&slistPollProcedure, 0.1);
434 slistInProgress = false;
440 static void InetSlist_Send(void)
444 if (!slistInProgress)
447 while ((host = Master_BuildGetServers ()) != NULL)
449 for (net_driverlevel=0; net_driverlevel < net_numdrivers; net_driverlevel++)
451 if (!slistLocal && net_driverlevel == 0)
453 if (net_drivers[net_driverlevel].initialized == false)
455 dfunc.SearchForInetHosts (host);
459 if ((Sys_DoubleTime() - slistStartTime) < 3.5)
460 SchedulePollProcedure(&inetSlistSendProcedure, 1.0);
464 static void InetSlist_Poll(void)
466 for (net_driverlevel=0; net_driverlevel < net_numdrivers; net_driverlevel++)
468 if (!slistLocal && net_driverlevel == 0)
470 if (net_drivers[net_driverlevel].initialized == false)
472 // We stop as soon as we have one answer (FIXME: bad...)
473 if (dfunc.SearchForInetHosts (NULL))
474 slistInProgress = false;
480 if (slistInProgress && (Sys_DoubleTime() - slistStartTime) < 4.0)
482 SchedulePollProcedure(&inetSlistPollProcedure, 0.1);
488 slistInProgress = false;
500 int hostCacheCount = 0;
501 hostcache_t hostcache[HOSTCACHESIZE];
503 qsocket_t *NET_Connect (char *host)
507 if (host == NULL || *host == 0)
512 if (host && strcasecmp (host, "local") == 0)
515 return dfunc.Connect (host);
518 for (net_driverlevel = 0;net_driverlevel < net_numdrivers;net_driverlevel++)
520 if (net_drivers[net_driverlevel].initialized == false)
522 ret = dfunc.Connect (host);
533 NET_CheckNewConnections
537 qsocket_t *NET_CheckNewConnections (void)
543 for (net_driverlevel=0 ; net_driverlevel<net_numdrivers; net_driverlevel++)
545 if (net_drivers[net_driverlevel].initialized == false)
547 if (net_driverlevel && listening == false)
549 ret = dfunc.CheckNewConnections ();
562 void NET_Close (qsocket_t *sock)
567 if (sock->disconnected)
572 // call the driver_Close function
575 NET_FreeQSocket(sock);
583 If there is a complete message, return it in net_message
585 returns 0 if no data is waiting
586 returns 1 if a message was received
587 returns -1 if connection is invalid
591 extern void PrintStats(qsocket_t *s);
593 int NET_GetMessage (qsocket_t *sock)
600 if (sock->disconnected)
602 Con_Printf("NET_GetMessage: disconnected socket\n");
608 ret = sfunc.QGetMessage(sock);
610 // see if this connection has timed out
611 if (ret == 0 && sock->driver)
613 if (net_time - sock->lastMessageTime > net_messagetimeout.value)
625 sock->lastMessageTime = net_time;
629 unreliableMessagesReceived++;
641 Try to send a complete length+message unit over the reliable stream.
642 returns 0 if the message cannot be delivered reliably, but the connection
643 is still considered valid
644 returns 1 if the message was sent properly
645 returns -1 if the connection died
648 int NET_SendMessage (qsocket_t *sock, sizebuf_t *data)
655 if (sock->disconnected)
657 Con_Printf("NET_SendMessage: disconnected socket\n");
662 r = sfunc.QSendMessage(sock, data);
663 if (r == 1 && sock->driver)
670 int NET_SendUnreliableMessage (qsocket_t *sock, sizebuf_t *data)
677 if (sock->disconnected)
679 Con_Printf("NET_SendMessage: disconnected socket\n");
684 r = sfunc.SendUnreliableMessage(sock, data);
685 if (r == 1 && sock->driver)
686 unreliableMessagesSent++;
696 Returns true or false if the given qsocket can currently accept a
697 message to be transmitted.
700 qboolean NET_CanSendMessage (qsocket_t *sock)
707 if (sock->disconnected)
712 r = sfunc.CanSendMessage(sock);
722 Send an heartbeat to the master server(s)
725 void NET_Heartbeat (int priority)
729 if (! Master_AllowHeartbeat (priority))
732 while ((host = Master_BuildHeartbeat ()) != NULL)
734 for (net_driverlevel=0 ; net_driverlevel<net_numdrivers; net_driverlevel++)
736 if (net_drivers[net_driverlevel].initialized == false)
738 if (net_driverlevel && listening == false)
740 dfunc.Heartbeat (host);
746 int NET_SendToAll(sizebuf_t *data, int blocktime)
751 qbyte state [MAX_SCOREBOARD];
753 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
756 if (host_client->netconnection && host_client->active)
758 if (host_client->netconnection->driver == 0)
759 NET_SendMessage(host_client->netconnection, data);
765 // for every player (simultaneously) wait for the first CanSendMessage
766 // and send the message, then wait for a second CanSendMessage (verifying
768 start = Sys_DoubleTime();
772 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
777 // need to send to this one
778 if (NET_CanSendMessage (host_client->netconnection))
780 if (state[i] == 0 && NET_SendMessage (host_client->netconnection, data) == -1)
781 state[i] = 2; // connection lost
785 NET_GetMessage (host_client->netconnection);
789 while (count && (Sys_DoubleTime() - start) < blocktime);
794 //=============================================================================
807 i = COM_CheckParm ("-port");
809 i = COM_CheckParm ("-udpport");
811 i = COM_CheckParm ("-ipxport");
816 DEFAULTnet_hostport = atoi (com_argv[i+1]);
818 Sys_Error ("NET_Init: you must specify a number after -port");
820 net_hostport = DEFAULTnet_hostport;
822 if (COM_CheckParm("-listen") || cls.state == ca_dedicated || gamemode == GAME_TRANSFUSION)
827 net_mempool = Mem_AllocPool("qsocket");
829 // allocate space for network message buffer
830 SZ_Alloc (&net_message, NET_MAXMESSAGE, "net_message");
832 Cvar_RegisterVariable (&net_messagetimeout);
833 Cvar_RegisterVariable (&hostname);
834 Cvar_RegisterVariable (&developer_networking);
836 Cmd_AddCommand ("net_slist", NET_Slist_f);
837 Cmd_AddCommand ("net_inetslist", NET_InetSlist_f);
838 Cmd_AddCommand ("listen", NET_Listen_f);
839 Cmd_AddCommand ("maxplayers", MaxPlayers_f);
840 Cmd_AddCommand ("port", NET_Port_f);
841 Cmd_AddCommand ("heartbeat", NET_Heartbeat_f);
843 // initialize all the drivers
844 for (net_driverlevel=0 ; net_driverlevel<net_numdrivers ; net_driverlevel++)
846 controlSocket = net_drivers[net_driverlevel].Init();
847 if (controlSocket == -1)
849 net_drivers[net_driverlevel].initialized = true;
850 net_drivers[net_driverlevel].controlSock = controlSocket;
852 net_drivers[net_driverlevel].Listen (true);
856 Con_DPrintf("IPX address %s\n", my_ipx_address);
857 if (*my_tcpip_address)
858 Con_DPrintf("TCP/IP address %s\n", my_tcpip_address);
869 void NET_Shutdown (void)
873 while (net_activeSockets)
874 NET_Close(net_activeSockets);
877 // shutdown the drivers
879 for (net_driverlevel = 0; net_driverlevel < net_numdrivers; net_driverlevel++)
881 if (net_drivers[net_driverlevel].initialized == true)
883 net_drivers[net_driverlevel].Shutdown ();
884 net_drivers[net_driverlevel].initialized = false;
888 Mem_FreePool(&net_mempool);
892 static PollProcedure *pollProcedureList = NULL;
899 configRestored = true;
903 for (pp = pollProcedureList; pp; pp = pp->next)
905 if (pp->nextTime > net_time)
907 pollProcedureList = pp->next;
908 pp->procedure(pp->arg);
913 void SchedulePollProcedure(PollProcedure *proc, double timeOffset)
915 PollProcedure *pp, *prev;
917 proc->nextTime = Sys_DoubleTime() + timeOffset;
918 for (pp = pollProcedureList, prev = NULL; pp; pp = pp->next)
920 if (pp->nextTime >= proc->nextTime)
927 proc->next = pollProcedureList;
928 pollProcedureList = proc;