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]
76 #define SLSERVERS 1024
80 typedef struct slserver_s
86 char mapname[SLMAPNAME];
87 char modname[SLMODNAME];
91 slserver_t sl_server[SLSERVERS];
92 int sl_numservers = 0;
94 void SL_ClearServers(void)
99 slserver_t *SL_FindServer(unsigned int ipaddr, unsigned short port)
103 for (i = 0, sl = sl_server;i < sl_numservers;i++, sl++)
104 if (sl->ipaddr == ipaddr && sl->port == port)
108 void SL_AddServer(unsigned int ipaddr, unsigned short port)
110 if (SL_FindServer(ipaddr, port))
112 memset(sl_server + sl_numservers, 0, sizeof(slserver_t));
113 sl_server[sl_numservers].ipaddr = ipaddr;
114 sl_server[sl_numservers].port = port;
115 sl_server[sl_numservers].ping = 0xFFFF;
119 void SL_UpdateServerName(unsigned int ipaddr, unsigned short port, const char *name);
123 sl = SL_FindServer(ipaddr, port);
126 memset(sl->name, 0, sizeof(sl->name));
127 namelen = strlen(name);
128 if (namelen > sizeof(sl->name) - 1)
129 namelen = sizeof(sl->name) - 1;
131 memcpy(sl->name, name, namelen);
134 void SL_UpdateServerModName(unsigned int ipaddr, unsigned short port, const char *name);
138 sl = SL_FindServer(ipaddr, port);
141 memset(sl->modname, 0, sizeof(sl->modname));
142 namelen = strlen(name);
143 if (namelen > sizeof(sl->modname) - 1)
144 namelen = sizeof(sl->modname) - 1;
146 memcpy(sl->modname, name, namelen);
149 void SL_UpdateServerMapName(unsigned int ipaddr, unsigned short port, const char *name);
153 sl = SL_FindServer(ipaddr, port);
156 memset(sl->mapname, 0, sizeof(sl->mapname));
157 namelen = strlen(name);
158 if (namelen > sizeof(sl->mapname) - 1)
159 namelen = sizeof(sl->mapname) - 1;
161 memcpy(sl->mapname, name, namelen);
164 void SL_UpdateServerPing(unsigned int ipaddr, unsigned short port, float ping);
168 sl = SL_FindServer(ipaddr, port);
172 sl->ping = bound(0, i, 9999);
179 double SetNetTime(void)
181 net_time = Sys_DoubleTime();
190 Called by drivers when a new communications endpoint is required
191 The sequence and buffer fields will be filled in properly
194 qsocket_t *NET_NewQSocket (void)
198 if (net_activeconnections >= svs.maxclients)
201 sock = Mem_Alloc(net_mempool, sizeof(qsocket_t));
203 // add it to active list
204 sock->next = net_activeSockets;
205 net_activeSockets = sock;
207 sock->disconnected = false;
208 sock->connecttime = net_time;
209 strcpy (sock->address,"UNSET ADDRESS");
210 sock->driver = net_driverlevel;
212 sock->driverdata = NULL;
213 sock->canSend = true;
214 sock->sendNext = false;
215 sock->lastMessageTime = net_time;
216 sock->ackSequence = 0;
217 sock->sendSequence = 0;
218 sock->unreliableSendSequence = 0;
219 sock->sendMessageLength = 0;
220 sock->receiveSequence = 0;
221 sock->unreliableReceiveSequence = 0;
222 sock->receiveMessageLength = 0;
228 void NET_FreeQSocket(qsocket_t *sock)
232 // remove it from active list
233 if (sock == net_activeSockets)
234 net_activeSockets = net_activeSockets->next;
237 for (s = net_activeSockets; s; s = s->next)
240 s->next = sock->next;
244 Sys_Error ("NET_FreeQSocket: not active\n");
251 static void NET_Listen_f (void)
253 if (Cmd_Argc () != 2)
255 Con_Printf ("\"listen\" is \"%u\"\n", listening ? 1 : 0);
259 listening = atoi(Cmd_Argv(1)) ? true : false;
261 for (net_driverlevel=0 ; net_driverlevel<net_numdrivers; net_driverlevel++)
263 if (net_drivers[net_driverlevel].initialized == false)
265 dfunc.Listen (listening);
270 static void MaxPlayers_f (void)
274 if (Cmd_Argc () != 2)
276 Con_Printf ("\"maxplayers\" is \"%u\"\n", svs.maxclients);
282 Con_Printf ("maxplayers can not be changed while a server is running.\n");
286 n = atoi(Cmd_Argv(1));
287 n = bound(1, n, MAX_SCOREBOARD);
288 if (svs.maxclients != n)
289 Con_Printf ("\"maxplayers\" set to \"%u\"\n", n);
291 if ((n == 1) && listening)
292 Cbuf_AddText ("listen 0\n");
294 if ((n > 1) && (!listening))
295 Cbuf_AddText ("listen 1\n");
301 static void NET_Port_f (void)
305 if (Cmd_Argc () != 2)
307 Con_Printf ("\"port\" is \"%u\"\n", net_hostport);
311 n = atoi(Cmd_Argv(1));
312 if (n < 1 || n > 65534)
314 Con_Printf ("Bad value, must be between 1 and 65534\n");
318 DEFAULTnet_hostport = n;
323 // force a change to the new port
324 Cbuf_AddText ("listen 0\n");
325 Cbuf_AddText ("listen 1\n");
330 static void NET_Heartbeat_f (void)
336 static void PrintSlistHeader(void)
338 Con_Printf("Server Map Users\n");
339 Con_Printf("--------------- --------------- -----\n");
344 static void PrintSlist(void)
348 for (n = slistLastShown; n < hostCacheCount; n++)
350 if (hostcache[n].maxusers)
351 Con_Printf("%-15.15s %-15.15s %2u/%2u\n", hostcache[n].name, hostcache[n].map, hostcache[n].users, hostcache[n].maxusers);
353 Con_Printf("%-15.15s %-15.15s\n", hostcache[n].name, hostcache[n].map);
359 static void PrintSlistTrailer(void)
362 Con_Printf("== end list ==\n\n");
365 if (gamemode == GAME_TRANSFUSION)
366 Con_Printf("No Transfusion servers found.\n\n");
368 Con_Printf("No Quake servers found.\n\n");
373 void NET_SlistCommon (PollProcedure *sendProcedure, PollProcedure *pollProcedure)
380 if (gamemode == GAME_TRANSFUSION)
381 Con_Printf("Looking for Transfusion servers...\n");
383 Con_Printf("Looking for Quake servers...\n");
387 slistInProgress = true;
388 slistStartTime = Sys_DoubleTime();
390 SchedulePollProcedure(sendProcedure, 0.0);
391 SchedulePollProcedure(pollProcedure, 0.1);
397 void NET_Slist_f (void)
399 NET_SlistCommon (&slistSendProcedure, &slistPollProcedure);
403 void NET_InetSlist_f (void)
405 NET_SlistCommon (&inetSlistSendProcedure, &inetSlistPollProcedure);
409 static void Slist_Send(void)
411 for (net_driverlevel=0; net_driverlevel < net_numdrivers; net_driverlevel++)
413 if (!slistLocal && net_driverlevel == 0)
415 if (net_drivers[net_driverlevel].initialized == false)
417 dfunc.SearchForHosts (true);
420 if ((Sys_DoubleTime() - slistStartTime) < 0.5)
421 SchedulePollProcedure(&slistSendProcedure, 0.75);
425 static void Slist_Poll(void)
427 for (net_driverlevel=0; net_driverlevel < net_numdrivers; net_driverlevel++)
429 if (!slistLocal && net_driverlevel == 0)
431 if (net_drivers[net_driverlevel].initialized == false)
433 dfunc.SearchForHosts (false);
439 if ((Sys_DoubleTime() - slistStartTime) < 1.5)
441 SchedulePollProcedure(&slistPollProcedure, 0.1);
447 slistInProgress = false;
453 static void InetSlist_Send(void)
457 if (!slistInProgress)
460 while ((host = Master_BuildGetServers ()) != NULL)
462 for (net_driverlevel=0; net_driverlevel < net_numdrivers; net_driverlevel++)
464 if (!slistLocal && net_driverlevel == 0)
466 if (net_drivers[net_driverlevel].initialized == false)
468 dfunc.SearchForInetHosts (host);
472 if ((Sys_DoubleTime() - slistStartTime) < 3.5)
473 SchedulePollProcedure(&inetSlistSendProcedure, 1.0);
477 static void InetSlist_Poll(void)
479 for (net_driverlevel=0; net_driverlevel < net_numdrivers; net_driverlevel++)
481 if (!slistLocal && net_driverlevel == 0)
483 if (net_drivers[net_driverlevel].initialized == false)
485 // We stop as soon as we have one answer (FIXME: bad...)
486 if (dfunc.SearchForInetHosts (NULL))
487 slistInProgress = false;
493 if (slistInProgress && (Sys_DoubleTime() - slistStartTime) < 4.0)
495 SchedulePollProcedure(&inetSlistPollProcedure, 0.1);
501 slistInProgress = false;
513 int hostCacheCount = 0;
514 hostcache_t hostcache[HOSTCACHESIZE];
516 qsocket_t *NET_Connect (char *host)
520 int numdrivers = net_numdrivers;
524 if (host && *host == 0)
529 if (Q_strcasecmp (host, "local") == 0)
537 for (n = 0; n < hostCacheCount; n++)
538 if (Q_strcasecmp (host, hostcache[n].name) == 0)
540 host = hostcache[n].cname;
543 if (n < hostCacheCount)
548 slistSilent = host ? true : false;
551 while(slistInProgress)
556 if (hostCacheCount != 1)
558 host = hostcache[0].cname;
559 Con_Printf("Connecting to...\n%s @ %s\n\n", hostcache[0].name, host);
563 for (n = 0; n < hostCacheCount; n++)
564 if (Q_strcasecmp (host, hostcache[n].name) == 0)
566 host = hostcache[n].cname;
571 for (net_driverlevel=0 ; net_driverlevel<numdrivers; net_driverlevel++)
573 if (net_drivers[net_driverlevel].initialized == false)
575 ret = dfunc.Connect (host);
594 NET_CheckNewConnections
598 qsocket_t *NET_CheckNewConnections (void)
604 for (net_driverlevel=0 ; net_driverlevel<net_numdrivers; net_driverlevel++)
606 if (net_drivers[net_driverlevel].initialized == false)
608 if (net_driverlevel && listening == false)
610 ret = dfunc.CheckNewConnections ();
623 void NET_Close (qsocket_t *sock)
628 if (sock->disconnected)
633 // call the driver_Close function
636 NET_FreeQSocket(sock);
644 If there is a complete message, return it in net_message
646 returns 0 if no data is waiting
647 returns 1 if a message was received
648 returns -1 if connection is invalid
652 extern void PrintStats(qsocket_t *s);
654 int NET_GetMessage (qsocket_t *sock)
661 if (sock->disconnected)
663 Con_Printf("NET_GetMessage: disconnected socket\n");
669 ret = sfunc.QGetMessage(sock);
671 // see if this connection has timed out
672 if (ret == 0 && sock->driver)
674 if (net_time - sock->lastMessageTime > net_messagetimeout.value)
686 sock->lastMessageTime = net_time;
690 unreliableMessagesReceived++;
702 Try to send a complete length+message unit over the reliable stream.
703 returns 0 if the message cannot be delivered reliably, but the connection
704 is still considered valid
705 returns 1 if the message was sent properly
706 returns -1 if the connection died
709 int NET_SendMessage (qsocket_t *sock, sizebuf_t *data)
716 if (sock->disconnected)
718 Con_Printf("NET_SendMessage: disconnected socket\n");
723 r = sfunc.QSendMessage(sock, data);
724 if (r == 1 && sock->driver)
731 int NET_SendUnreliableMessage (qsocket_t *sock, sizebuf_t *data)
738 if (sock->disconnected)
740 Con_Printf("NET_SendMessage: disconnected socket\n");
745 r = sfunc.SendUnreliableMessage(sock, data);
746 if (r == 1 && sock->driver)
747 unreliableMessagesSent++;
757 Returns true or false if the given qsocket can currently accept a
758 message to be transmitted.
761 qboolean NET_CanSendMessage (qsocket_t *sock)
768 if (sock->disconnected)
773 r = sfunc.CanSendMessage(sock);
783 Send an heartbeat to the master server(s)
786 void NET_Heartbeat (int priority)
790 if (! Master_AllowHeartbeat (priority))
793 while ((host = Master_BuildHeartbeat ()) != NULL)
795 for (net_driverlevel=0 ; net_driverlevel<net_numdrivers; net_driverlevel++)
797 if (net_drivers[net_driverlevel].initialized == false)
799 if (net_driverlevel && listening == false)
801 dfunc.Heartbeat (host);
807 int NET_SendToAll(sizebuf_t *data, int blocktime)
812 qboolean state1 [MAX_SCOREBOARD];
813 qboolean state2 [MAX_SCOREBOARD];
815 for (i=0, host_client = svs.clients ; i<svs.maxclients ; i++, host_client++)
817 if (!host_client->netconnection)
819 if (host_client->active)
821 if (host_client->netconnection->driver == 0)
823 NET_SendMessage(host_client->netconnection, data);
839 start = Sys_DoubleTime();
843 for (i=0, host_client = svs.clients ; i<svs.maxclients ; i++, host_client++)
847 if (NET_CanSendMessage (host_client->netconnection))
850 NET_SendMessage(host_client->netconnection, data);
854 NET_GetMessage (host_client->netconnection);
862 if (NET_CanSendMessage (host_client->netconnection))
868 NET_GetMessage (host_client->netconnection);
874 if ((Sys_DoubleTime() - start) > blocktime)
881 //=============================================================================
894 i = COM_CheckParm ("-port");
896 i = COM_CheckParm ("-udpport");
898 i = COM_CheckParm ("-ipxport");
903 DEFAULTnet_hostport = atoi (com_argv[i+1]);
905 Sys_Error ("NET_Init: you must specify a number after -port");
907 net_hostport = DEFAULTnet_hostport;
909 if (COM_CheckParm("-listen") || cls.state == ca_dedicated || gamemode == GAME_TRANSFUSION)
914 net_mempool = Mem_AllocPool("qsocket");
916 // allocate space for network message buffer
917 SZ_Alloc (&net_message, NET_MAXMESSAGE, "net_message");
919 Cvar_RegisterVariable (&net_messagetimeout);
920 Cvar_RegisterVariable (&hostname);
922 Cmd_AddCommand ("net_slist", NET_Slist_f);
923 Cmd_AddCommand ("net_inetslist", NET_InetSlist_f);
924 Cmd_AddCommand ("listen", NET_Listen_f);
925 Cmd_AddCommand ("maxplayers", MaxPlayers_f);
926 Cmd_AddCommand ("port", NET_Port_f);
927 Cmd_AddCommand ("heartbeat", NET_Heartbeat_f);
929 // initialize all the drivers
930 for (net_driverlevel=0 ; net_driverlevel<net_numdrivers ; net_driverlevel++)
932 controlSocket = net_drivers[net_driverlevel].Init();
933 if (controlSocket == -1)
935 net_drivers[net_driverlevel].initialized = true;
936 net_drivers[net_driverlevel].controlSock = controlSocket;
938 net_drivers[net_driverlevel].Listen (true);
942 Con_DPrintf("IPX address %s\n", my_ipx_address);
943 if (*my_tcpip_address)
944 Con_DPrintf("TCP/IP address %s\n", my_tcpip_address);
955 void NET_Shutdown (void)
959 while (net_activeSockets)
960 NET_Close(net_activeSockets);
963 // shutdown the drivers
965 for (net_driverlevel = 0; net_driverlevel < net_numdrivers; net_driverlevel++)
967 if (net_drivers[net_driverlevel].initialized == true)
969 net_drivers[net_driverlevel].Shutdown ();
970 net_drivers[net_driverlevel].initialized = false;
974 Mem_FreePool(&net_mempool);
978 static PollProcedure *pollProcedureList = NULL;
985 configRestored = true;
989 for (pp = pollProcedureList; pp; pp = pp->next)
991 if (pp->nextTime > net_time)
993 pollProcedureList = pp->next;
994 pp->procedure(pp->arg);
999 void SchedulePollProcedure(PollProcedure *proc, double timeOffset)
1001 PollProcedure *pp, *prev;
1003 proc->nextTime = Sys_DoubleTime() + timeOffset;
1004 for (pp = pollProcedureList, prev = NULL; pp; pp = pp->next)
1006 if (pp->nextTime >= proc->nextTime)
1013 proc->next = pollProcedureList;
1014 pollProcedureList = proc;