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.
24 qsocket_t *net_activeSockets = NULL;
25 //qsocket_t *net_freeSockets = NULL;
26 //int net_numsockets = 0;
27 mempool_t *net_mempool;
29 qboolean ipxAvailable = false;
30 qboolean tcpipAvailable = false;
33 int DEFAULTnet_hostport = 26000;
35 char my_ipx_address[NET_NAMELEN];
36 char my_tcpip_address[NET_NAMELEN];
38 static qboolean listening = false;
40 qboolean slistInProgress = false;
41 qboolean slistSilent = false;
42 qboolean slistLocal = true;
43 static double slistStartTime;
44 static int slistLastShown;
46 static void Slist_Send(void);
47 static void Slist_Poll(void);
48 PollProcedure slistSendProcedure = {NULL, 0.0, Slist_Send};
49 PollProcedure slistPollProcedure = {NULL, 0.0, Slist_Poll};
52 sizebuf_t net_message;
53 int net_activeconnections = 0;
56 int messagesReceived = 0;
57 int unreliableMessagesSent = 0;
58 int unreliableMessagesReceived = 0;
60 cvar_t net_messagetimeout = {0, "net_messagetimeout","300"};
61 cvar_t hostname = {CVAR_SAVE, "hostname", "UNNAMED"};
63 qboolean configRestored = false;
65 // these two macros are to make the code more readable
66 #define sfunc net_drivers[sock->driver]
67 #define dfunc net_drivers[net_driverlevel]
74 double SetNetTime(void)
76 net_time = Sys_DoubleTime();
85 Called by drivers when a new communications endpoint is required
86 The sequence and buffer fields will be filled in properly
89 qsocket_t *NET_NewQSocket (void)
93 // if (net_freeSockets == NULL)
96 if (net_activeconnections >= svs.maxclients)
99 // get one from free list
100 // sock = net_freeSockets;
101 // net_freeSockets = sock->next;
102 // LordHavoc: sockets are dynamically allocated now
103 sock = Mem_Alloc(net_mempool, sizeof(qsocket_t));
105 // add it to active list
106 sock->next = net_activeSockets;
107 net_activeSockets = sock;
109 sock->disconnected = false;
110 sock->connecttime = net_time;
111 strcpy (sock->address,"UNSET ADDRESS");
112 sock->driver = net_driverlevel;
114 sock->driverdata = NULL;
115 sock->canSend = true;
116 sock->sendNext = false;
117 sock->lastMessageTime = net_time;
118 sock->ackSequence = 0;
119 sock->sendSequence = 0;
120 sock->unreliableSendSequence = 0;
121 sock->sendMessageLength = 0;
122 sock->receiveSequence = 0;
123 sock->unreliableReceiveSequence = 0;
124 sock->receiveMessageLength = 0;
130 void NET_FreeQSocket(qsocket_t *sock)
134 // remove it from active list
135 if (sock == net_activeSockets)
136 net_activeSockets = net_activeSockets->next;
139 for (s = net_activeSockets; s; s = s->next)
142 s->next = sock->next;
146 Sys_Error ("NET_FreeQSocket: not active\n");
149 // add it to free list
150 // sock->next = net_freeSockets;
151 // net_freeSockets = sock;
152 // sock->disconnected = true;
153 // LordHavoc: sockets are dynamically allocated now
158 static void NET_Listen_f (void)
160 if (Cmd_Argc () != 2)
162 Con_Printf ("\"listen\" is \"%u\"\n", listening ? 1 : 0);
166 listening = atoi(Cmd_Argv(1)) ? true : false;
168 for (net_driverlevel=0 ; net_driverlevel<net_numdrivers; net_driverlevel++)
170 if (net_drivers[net_driverlevel].initialized == false)
172 dfunc.Listen (listening);
177 static void MaxPlayers_f (void)
181 if (Cmd_Argc () != 2)
183 Con_Printf ("\"maxplayers\" is \"%u\"\n", svs.maxclients);
189 Con_Printf ("maxplayers can not be changed while a server is running.\n");
193 n = atoi(Cmd_Argv(1));
196 if (n > svs.maxclientslimit)
198 n = svs.maxclientslimit;
199 Con_Printf ("\"maxplayers\" set to \"%u\"\n", n);
202 if ((n == 1) && listening)
203 Cbuf_AddText ("listen 0\n");
205 if ((n > 1) && (!listening))
206 Cbuf_AddText ("listen 1\n");
209 // LordHavoc: resetting deathmatch and coop was silly
212 Cvar_Set ("deathmatch", "0");
214 Cvar_Set ("deathmatch", "1");
219 static void NET_Port_f (void)
223 if (Cmd_Argc () != 2)
225 Con_Printf ("\"port\" is \"%u\"\n", net_hostport);
229 n = atoi(Cmd_Argv(1));
230 if (n < 1 || n > 65534)
232 Con_Printf ("Bad value, must be between 1 and 65534\n");
236 DEFAULTnet_hostport = n;
241 // force a change to the new port
242 Cbuf_AddText ("listen 0\n");
243 Cbuf_AddText ("listen 1\n");
248 static void PrintSlistHeader(void)
250 Con_Printf("Server Map Users\n");
251 Con_Printf("--------------- --------------- -----\n");
256 static void PrintSlist(void)
260 for (n = slistLastShown; n < hostCacheCount; n++)
262 if (hostcache[n].maxusers)
263 Con_Printf("%-15.15s %-15.15s %2u/%2u\n", hostcache[n].name, hostcache[n].map, hostcache[n].users, hostcache[n].maxusers);
265 Con_Printf("%-15.15s %-15.15s\n", hostcache[n].name, hostcache[n].map);
271 static void PrintSlistTrailer(void)
274 Con_Printf("== end list ==\n\n");
276 Con_Printf("No Quake servers found.\n\n");
280 void NET_Slist_f (void)
287 Con_Printf("Looking for Quake servers...\n");
291 slistInProgress = true;
292 slistStartTime = Sys_DoubleTime();
294 SchedulePollProcedure(&slistSendProcedure, 0.0);
295 SchedulePollProcedure(&slistPollProcedure, 0.1);
301 static void Slist_Send(void)
303 for (net_driverlevel=0; net_driverlevel < net_numdrivers; net_driverlevel++)
305 if (!slistLocal && net_driverlevel == 0)
307 if (net_drivers[net_driverlevel].initialized == false)
309 dfunc.SearchForHosts (true);
312 if ((Sys_DoubleTime() - slistStartTime) < 0.5)
313 SchedulePollProcedure(&slistSendProcedure, 0.75);
317 static void Slist_Poll(void)
319 for (net_driverlevel=0; net_driverlevel < net_numdrivers; net_driverlevel++)
321 if (!slistLocal && net_driverlevel == 0)
323 if (net_drivers[net_driverlevel].initialized == false)
325 dfunc.SearchForHosts (false);
331 if ((Sys_DoubleTime() - slistStartTime) < 1.5)
333 SchedulePollProcedure(&slistPollProcedure, 0.1);
339 slistInProgress = false;
351 int hostCacheCount = 0;
352 hostcache_t hostcache[HOSTCACHESIZE];
354 qsocket_t *NET_Connect (char *host)
358 int numdrivers = net_numdrivers;
362 if (host && *host == 0)
367 if (Q_strcasecmp (host, "local") == 0)
375 for (n = 0; n < hostCacheCount; n++)
376 if (Q_strcasecmp (host, hostcache[n].name) == 0)
378 host = hostcache[n].cname;
381 if (n < hostCacheCount)
386 slistSilent = host ? true : false;
389 while(slistInProgress)
394 if (hostCacheCount != 1)
396 host = hostcache[0].cname;
397 Con_Printf("Connecting to...\n%s @ %s\n\n", hostcache[0].name, host);
401 for (n = 0; n < hostCacheCount; n++)
402 if (Q_strcasecmp (host, hostcache[n].name) == 0)
404 host = hostcache[n].cname;
409 for (net_driverlevel=0 ; net_driverlevel<numdrivers; net_driverlevel++)
411 if (net_drivers[net_driverlevel].initialized == false)
413 ret = dfunc.Connect (host);
432 NET_CheckNewConnections
436 qsocket_t *NET_CheckNewConnections (void)
442 for (net_driverlevel=0 ; net_driverlevel<net_numdrivers; net_driverlevel++)
444 if (net_drivers[net_driverlevel].initialized == false)
446 if (net_driverlevel && listening == false)
448 ret = dfunc.CheckNewConnections ();
461 void NET_Close (qsocket_t *sock)
466 if (sock->disconnected)
471 // call the driver_Close function
474 NET_FreeQSocket(sock);
482 If there is a complete message, return it in net_message
484 returns 0 if no data is waiting
485 returns 1 if a message was received
486 returns -1 if connection is invalid
490 extern void PrintStats(qsocket_t *s);
492 int NET_GetMessage (qsocket_t *sock)
499 if (sock->disconnected)
501 Con_Printf("NET_GetMessage: disconnected socket\n");
507 ret = sfunc.QGetMessage(sock);
509 // see if this connection has timed out
510 if (ret == 0 && sock->driver)
512 if (net_time - sock->lastMessageTime > net_messagetimeout.value)
524 sock->lastMessageTime = net_time;
528 unreliableMessagesReceived++;
540 Try to send a complete length+message unit over the reliable stream.
541 returns 0 if the message cannot be delivered reliably, but the connection
542 is still considered valid
543 returns 1 if the message was sent properly
544 returns -1 if the connection died
547 int NET_SendMessage (qsocket_t *sock, sizebuf_t *data)
554 if (sock->disconnected)
556 Con_Printf("NET_SendMessage: disconnected socket\n");
561 r = sfunc.QSendMessage(sock, data);
562 if (r == 1 && sock->driver)
569 int NET_SendUnreliableMessage (qsocket_t *sock, sizebuf_t *data)
576 if (sock->disconnected)
578 Con_Printf("NET_SendMessage: disconnected socket\n");
583 r = sfunc.SendUnreliableMessage(sock, data);
584 if (r == 1 && sock->driver)
585 unreliableMessagesSent++;
595 Returns true or false if the given qsocket can currently accept a
596 message to be transmitted.
599 qboolean NET_CanSendMessage (qsocket_t *sock)
606 if (sock->disconnected)
611 r = sfunc.CanSendMessage(sock);
617 int NET_SendToAll(sizebuf_t *data, int blocktime)
622 qboolean state1 [MAX_SCOREBOARD];
623 qboolean state2 [MAX_SCOREBOARD];
625 for (i=0, host_client = svs.clients ; i<svs.maxclients ; i++, host_client++)
627 if (!host_client->netconnection)
629 if (host_client->active)
631 if (host_client->netconnection->driver == 0)
633 NET_SendMessage(host_client->netconnection, data);
649 start = Sys_DoubleTime();
653 for (i=0, host_client = svs.clients ; i<svs.maxclients ; i++, host_client++)
657 if (NET_CanSendMessage (host_client->netconnection))
660 NET_SendMessage(host_client->netconnection, data);
664 NET_GetMessage (host_client->netconnection);
672 if (NET_CanSendMessage (host_client->netconnection))
678 NET_GetMessage (host_client->netconnection);
684 if ((Sys_DoubleTime() - start) > blocktime)
691 //=============================================================================
703 // LordHavoc: sockets are dynamically allocated now
706 i = COM_CheckParm ("-port");
708 i = COM_CheckParm ("-udpport");
710 i = COM_CheckParm ("-ipxport");
715 DEFAULTnet_hostport = atoi (com_argv[i+1]);
717 Sys_Error ("NET_Init: you must specify a number after -port");
719 net_hostport = DEFAULTnet_hostport;
721 if (COM_CheckParm("-listen") || cls.state == ca_dedicated)
723 // LordHavoc: sockets are dynamically allocated now
724 //net_numsockets = svs.maxclientslimit;
725 //if (cls.state != ca_dedicated)
730 net_mempool = Mem_AllocPool("qsocket");
731 // LordHavoc: sockets are dynamically allocated now
733 s = Mem_Alloc(net_mempool, net_numsockets * sizeof(qsocket_t));
734 for (i = 0; i < net_numsockets; i++)
736 s->next = net_freeSockets;
738 s->disconnected = true;
743 // allocate space for network message buffer
744 SZ_Alloc (&net_message, NET_MAXMESSAGE, "net_message");
746 Cvar_RegisterVariable (&net_messagetimeout);
747 Cvar_RegisterVariable (&hostname);
749 Cmd_AddCommand ("slist", NET_Slist_f);
750 Cmd_AddCommand ("listen", NET_Listen_f);
751 Cmd_AddCommand ("maxplayers", MaxPlayers_f);
752 Cmd_AddCommand ("port", NET_Port_f);
754 // initialize all the drivers
755 for (net_driverlevel=0 ; net_driverlevel<net_numdrivers ; net_driverlevel++)
757 controlSocket = net_drivers[net_driverlevel].Init();
758 if (controlSocket == -1)
760 net_drivers[net_driverlevel].initialized = true;
761 net_drivers[net_driverlevel].controlSock = controlSocket;
763 net_drivers[net_driverlevel].Listen (true);
767 Con_DPrintf("IPX address %s\n", my_ipx_address);
768 if (*my_tcpip_address)
769 Con_DPrintf("TCP/IP address %s\n", my_tcpip_address);
778 void NET_Shutdown (void)
784 for (sock = net_activeSockets; sock; sock = sock->next)
788 // shutdown the drivers
790 for (net_driverlevel = 0; net_driverlevel < net_numdrivers; net_driverlevel++)
792 if (net_drivers[net_driverlevel].initialized == true)
794 net_drivers[net_driverlevel].Shutdown ();
795 net_drivers[net_driverlevel].initialized = false;
799 Mem_FreePool(&net_mempool);
803 static PollProcedure *pollProcedureList = NULL;
810 configRestored = true;
814 for (pp = pollProcedureList; pp; pp = pp->next)
816 if (pp->nextTime > net_time)
818 pollProcedureList = pp->next;
819 pp->procedure(pp->arg);
824 void SchedulePollProcedure(PollProcedure *proc, double timeOffset)
826 PollProcedure *pp, *prev;
828 proc->nextTime = Sys_DoubleTime() + timeOffset;
829 for (pp = pollProcedureList, prev = NULL; pp; pp = pp->next)
831 if (pp->nextTime >= proc->nextTime)
838 proc->next = pollProcedureList;
839 pollProcedureList = proc;