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");
366 if (gamemode == GAME_TRANSFUSION)
367 Con_Printf("No Transfusion servers found.\n\n");
369 Con_Printf("No Quake servers found.\n\n");
374 void NET_SlistCommon (PollProcedure *sendProcedure, PollProcedure *pollProcedure)
381 if (gamemode == GAME_TRANSFUSION)
382 Con_Printf("Looking for Transfusion servers...\n");
384 Con_Printf("Looking for Quake servers...\n");
388 slistInProgress = true;
389 slistStartTime = Sys_DoubleTime();
391 SchedulePollProcedure(sendProcedure, 0.0);
392 SchedulePollProcedure(pollProcedure, 0.1);
398 void NET_Slist_f (void)
400 NET_SlistCommon (&slistSendProcedure, &slistPollProcedure);
404 void NET_InetSlist_f (void)
406 NET_SlistCommon (&inetSlistSendProcedure, &inetSlistPollProcedure);
410 static void Slist_Send(void)
412 for (net_driverlevel=0; net_driverlevel < net_numdrivers; net_driverlevel++)
414 if (!slistLocal && net_driverlevel == 0)
416 if (net_drivers[net_driverlevel].initialized == false)
418 dfunc.SearchForHosts (true);
421 if ((Sys_DoubleTime() - slistStartTime) < 0.5)
422 SchedulePollProcedure(&slistSendProcedure, 0.75);
426 static void Slist_Poll(void)
428 for (net_driverlevel=0; net_driverlevel < net_numdrivers; net_driverlevel++)
430 if (!slistLocal && net_driverlevel == 0)
432 if (net_drivers[net_driverlevel].initialized == false)
434 dfunc.SearchForHosts (false);
440 if ((Sys_DoubleTime() - slistStartTime) < 1.5)
442 SchedulePollProcedure(&slistPollProcedure, 0.1);
448 slistInProgress = false;
454 static void InetSlist_Send(void)
458 if (!slistInProgress)
461 while ((host = Master_BuildGetServers ()) != NULL)
463 for (net_driverlevel=0; net_driverlevel < net_numdrivers; net_driverlevel++)
465 if (!slistLocal && net_driverlevel == 0)
467 if (net_drivers[net_driverlevel].initialized == false)
469 dfunc.SearchForInetHosts (host);
473 if ((Sys_DoubleTime() - slistStartTime) < 3.5)
474 SchedulePollProcedure(&inetSlistSendProcedure, 1.0);
478 static void InetSlist_Poll(void)
480 for (net_driverlevel=0; net_driverlevel < net_numdrivers; net_driverlevel++)
482 if (!slistLocal && net_driverlevel == 0)
484 if (net_drivers[net_driverlevel].initialized == false)
486 // We stop as soon as we have one answer (FIXME: bad...)
487 if (dfunc.SearchForInetHosts (NULL))
488 slistInProgress = false;
494 if (slistInProgress && (Sys_DoubleTime() - slistStartTime) < 4.0)
496 SchedulePollProcedure(&inetSlistPollProcedure, 0.1);
502 slistInProgress = false;
514 int hostCacheCount = 0;
515 hostcache_t hostcache[HOSTCACHESIZE];
517 qsocket_t *NET_Connect (char *host)
524 if (host && *host == 0)
529 if (strcasecmp (host, "local") == 0)
532 return dfunc.Connect (host);
537 for (n = 0; n < hostCacheCount; n++)
538 if (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 (strcasecmp (host, hostcache[n].name) == 0)
566 host = hostcache[n].cname;
571 for (net_driverlevel = 0;net_driverlevel < net_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 qbyte state [MAX_SCOREBOARD];
814 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
815 state[i] = (host_client->netconnection && host_client->active) ? 0 : 2;
817 // for every player (simultaneously) wait for the first CanSendMessage
818 // and send the message, then wait for a second CanSendMessage (verifying
820 start = Sys_DoubleTime();
824 for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
828 // need to send to this one
829 if (NET_CanSendMessage (host_client->netconnection))
833 if (NET_SendMessage (host_client->netconnection, data) == 1)
834 state[i] = 2; // connection lost
842 NET_GetMessage (host_client->netconnection);
848 while (count && (Sys_DoubleTime() - start) < blocktime);
853 //=============================================================================
866 i = COM_CheckParm ("-port");
868 i = COM_CheckParm ("-udpport");
870 i = COM_CheckParm ("-ipxport");
875 DEFAULTnet_hostport = atoi (com_argv[i+1]);
877 Sys_Error ("NET_Init: you must specify a number after -port");
879 net_hostport = DEFAULTnet_hostport;
881 if (COM_CheckParm("-listen") || cls.state == ca_dedicated || gamemode == GAME_TRANSFUSION)
886 net_mempool = Mem_AllocPool("qsocket");
888 // allocate space for network message buffer
889 SZ_Alloc (&net_message, NET_MAXMESSAGE, "net_message");
891 Cvar_RegisterVariable (&net_messagetimeout);
892 Cvar_RegisterVariable (&hostname);
893 Cvar_RegisterVariable (&developer_networking);
895 Cmd_AddCommand ("net_slist", NET_Slist_f);
896 Cmd_AddCommand ("net_inetslist", NET_InetSlist_f);
897 Cmd_AddCommand ("listen", NET_Listen_f);
898 Cmd_AddCommand ("maxplayers", MaxPlayers_f);
899 Cmd_AddCommand ("port", NET_Port_f);
900 Cmd_AddCommand ("heartbeat", NET_Heartbeat_f);
902 // initialize all the drivers
903 for (net_driverlevel=0 ; net_driverlevel<net_numdrivers ; net_driverlevel++)
905 controlSocket = net_drivers[net_driverlevel].Init();
906 if (controlSocket == -1)
908 net_drivers[net_driverlevel].initialized = true;
909 net_drivers[net_driverlevel].controlSock = controlSocket;
911 net_drivers[net_driverlevel].Listen (true);
915 Con_DPrintf("IPX address %s\n", my_ipx_address);
916 if (*my_tcpip_address)
917 Con_DPrintf("TCP/IP address %s\n", my_tcpip_address);
928 void NET_Shutdown (void)
932 while (net_activeSockets)
933 NET_Close(net_activeSockets);
936 // shutdown the drivers
938 for (net_driverlevel = 0; net_driverlevel < net_numdrivers; net_driverlevel++)
940 if (net_drivers[net_driverlevel].initialized == true)
942 net_drivers[net_driverlevel].Shutdown ();
943 net_drivers[net_driverlevel].initialized = false;
947 Mem_FreePool(&net_mempool);
951 static PollProcedure *pollProcedureList = NULL;
958 configRestored = true;
962 for (pp = pollProcedureList; pp; pp = pp->next)
964 if (pp->nextTime > net_time)
966 pollProcedureList = pp->next;
967 pp->procedure(pp->arg);
972 void SchedulePollProcedure(PollProcedure *proc, double timeOffset)
974 PollProcedure *pp, *prev;
976 proc->nextTime = Sys_DoubleTime() + timeOffset;
977 for (pp = pollProcedureList, prev = NULL; pp; pp = pp->next)
979 if (pp->nextTime >= proc->nextTime)
986 proc->next = pollProcedureList;
987 pollProcedureList = proc;