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;
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};
51 sizebuf_t net_message;
52 int net_activeconnections = 0;
55 int messagesReceived = 0;
56 int unreliableMessagesSent = 0;
57 int unreliableMessagesReceived = 0;
59 cvar_t net_messagetimeout = {"net_messagetimeout","300"};
60 cvar_t hostname = {"hostname", "UNNAMED"};
62 qboolean configRestored = false;
64 // these two macros are to make the code more readable
65 #define sfunc net_drivers[sock->driver]
66 #define dfunc net_drivers[net_driverlevel]
73 double SetNetTime(void)
75 net_time = Sys_DoubleTime();
84 Called by drivers when a new communications endpoint is required
85 The sequence and buffer fields will be filled in properly
88 qsocket_t *NET_NewQSocket (void)
92 if (net_freeSockets == NULL)
95 if (net_activeconnections >= svs.maxclients)
98 // get one from free list
99 sock = net_freeSockets;
100 net_freeSockets = sock->next;
102 // add it to active list
103 sock->next = net_activeSockets;
104 net_activeSockets = sock;
106 sock->disconnected = false;
107 sock->connecttime = net_time;
108 strcpy (sock->address,"UNSET ADDRESS");
109 sock->driver = net_driverlevel;
111 sock->driverdata = NULL;
112 sock->canSend = true;
113 sock->sendNext = false;
114 sock->lastMessageTime = net_time;
115 sock->ackSequence = 0;
116 sock->sendSequence = 0;
117 sock->unreliableSendSequence = 0;
118 sock->sendMessageLength = 0;
119 sock->receiveSequence = 0;
120 sock->unreliableReceiveSequence = 0;
121 sock->receiveMessageLength = 0;
127 void NET_FreeQSocket(qsocket_t *sock)
131 // remove it from active list
132 if (sock == net_activeSockets)
133 net_activeSockets = net_activeSockets->next;
136 for (s = net_activeSockets; s; s = s->next)
139 s->next = sock->next;
143 Sys_Error ("NET_FreeQSocket: not active\n");
146 // add it to free list
147 sock->next = net_freeSockets;
148 net_freeSockets = sock;
149 sock->disconnected = true;
153 static void NET_Listen_f (void)
155 if (Cmd_Argc () != 2)
157 Con_Printf ("\"listen\" is \"%u\"\n", listening ? 1 : 0);
161 listening = atoi(Cmd_Argv(1)) ? true : false;
163 for (net_driverlevel=0 ; net_driverlevel<net_numdrivers; net_driverlevel++)
165 if (net_drivers[net_driverlevel].initialized == false)
167 dfunc.Listen (listening);
172 static void MaxPlayers_f (void)
176 if (Cmd_Argc () != 2)
178 Con_Printf ("\"maxplayers\" is \"%u\"\n", svs.maxclients);
184 Con_Printf ("maxplayers can not be changed while a server is running.\n");
188 n = atoi(Cmd_Argv(1));
191 if (n > svs.maxclientslimit)
193 n = svs.maxclientslimit;
194 Con_Printf ("\"maxplayers\" set to \"%u\"\n", n);
197 if ((n == 1) && listening)
198 Cbuf_AddText ("listen 0\n");
200 if ((n > 1) && (!listening))
201 Cbuf_AddText ("listen 1\n");
204 // LordHavoc: resetting deathmatch and coop was silly
207 Cvar_Set ("deathmatch", "0");
209 Cvar_Set ("deathmatch", "1");
214 static void NET_Port_f (void)
218 if (Cmd_Argc () != 2)
220 Con_Printf ("\"port\" is \"%u\"\n", net_hostport);
224 n = atoi(Cmd_Argv(1));
225 if (n < 1 || n > 65534)
227 Con_Printf ("Bad value, must be between 1 and 65534\n");
231 DEFAULTnet_hostport = n;
236 // force a change to the new port
237 Cbuf_AddText ("listen 0\n");
238 Cbuf_AddText ("listen 1\n");
243 static void PrintSlistHeader(void)
245 Con_Printf("Server Map Users\n");
246 Con_Printf("--------------- --------------- -----\n");
251 static void PrintSlist(void)
255 for (n = slistLastShown; n < hostCacheCount; n++)
257 if (hostcache[n].maxusers)
258 Con_Printf("%-15.15s %-15.15s %2u/%2u\n", hostcache[n].name, hostcache[n].map, hostcache[n].users, hostcache[n].maxusers);
260 Con_Printf("%-15.15s %-15.15s\n", hostcache[n].name, hostcache[n].map);
266 static void PrintSlistTrailer(void)
269 Con_Printf("== end list ==\n\n");
271 Con_Printf("No Quake servers found.\n\n");
275 void NET_Slist_f (void)
282 Con_Printf("Looking for Quake servers...\n");
286 slistInProgress = true;
287 slistStartTime = Sys_DoubleTime();
289 SchedulePollProcedure(&slistSendProcedure, 0.0);
290 SchedulePollProcedure(&slistPollProcedure, 0.1);
296 static void Slist_Send(void)
298 for (net_driverlevel=0; net_driverlevel < net_numdrivers; net_driverlevel++)
300 if (!slistLocal && net_driverlevel == 0)
302 if (net_drivers[net_driverlevel].initialized == false)
304 dfunc.SearchForHosts (true);
307 if ((Sys_DoubleTime() - slistStartTime) < 0.5)
308 SchedulePollProcedure(&slistSendProcedure, 0.75);
312 static void Slist_Poll(void)
314 for (net_driverlevel=0; net_driverlevel < net_numdrivers; net_driverlevel++)
316 if (!slistLocal && net_driverlevel == 0)
318 if (net_drivers[net_driverlevel].initialized == false)
320 dfunc.SearchForHosts (false);
326 if ((Sys_DoubleTime() - slistStartTime) < 1.5)
328 SchedulePollProcedure(&slistPollProcedure, 0.1);
334 slistInProgress = false;
346 int hostCacheCount = 0;
347 hostcache_t hostcache[HOSTCACHESIZE];
349 qsocket_t *NET_Connect (char *host)
353 int numdrivers = net_numdrivers;
357 if (host && *host == 0)
362 if (Q_strcasecmp (host, "local") == 0)
370 for (n = 0; n < hostCacheCount; n++)
371 if (Q_strcasecmp (host, hostcache[n].name) == 0)
373 host = hostcache[n].cname;
376 if (n < hostCacheCount)
381 slistSilent = host ? true : false;
384 while(slistInProgress)
389 if (hostCacheCount != 1)
391 host = hostcache[0].cname;
392 Con_Printf("Connecting to...\n%s @ %s\n\n", hostcache[0].name, host);
396 for (n = 0; n < hostCacheCount; n++)
397 if (Q_strcasecmp (host, hostcache[n].name) == 0)
399 host = hostcache[n].cname;
404 for (net_driverlevel=0 ; net_driverlevel<numdrivers; net_driverlevel++)
406 if (net_drivers[net_driverlevel].initialized == false)
408 ret = dfunc.Connect (host);
427 NET_CheckNewConnections
431 qsocket_t *NET_CheckNewConnections (void)
437 for (net_driverlevel=0 ; net_driverlevel<net_numdrivers; net_driverlevel++)
439 if (net_drivers[net_driverlevel].initialized == false)
441 if (net_driverlevel && listening == false)
443 ret = dfunc.CheckNewConnections ();
456 void NET_Close (qsocket_t *sock)
461 if (sock->disconnected)
466 // call the driver_Close function
469 NET_FreeQSocket(sock);
477 If there is a complete message, return it in net_message
479 returns 0 if no data is waiting
480 returns 1 if a message was received
481 returns -1 if connection is invalid
485 extern void PrintStats(qsocket_t *s);
487 int NET_GetMessage (qsocket_t *sock)
494 if (sock->disconnected)
496 Con_Printf("NET_GetMessage: disconnected socket\n");
502 ret = sfunc.QGetMessage(sock);
504 // see if this connection has timed out
505 if (ret == 0 && sock->driver)
507 if (net_time - sock->lastMessageTime > net_messagetimeout.value)
519 sock->lastMessageTime = net_time;
523 unreliableMessagesReceived++;
535 Try to send a complete length+message unit over the reliable stream.
536 returns 0 if the message cannot be delivered reliably, but the connection
537 is still considered valid
538 returns 1 if the message was sent properly
539 returns -1 if the connection died
542 int NET_SendMessage (qsocket_t *sock, sizebuf_t *data)
549 if (sock->disconnected)
551 Con_Printf("NET_SendMessage: disconnected socket\n");
556 r = sfunc.QSendMessage(sock, data);
557 if (r == 1 && sock->driver)
564 int NET_SendUnreliableMessage (qsocket_t *sock, sizebuf_t *data)
571 if (sock->disconnected)
573 Con_Printf("NET_SendMessage: disconnected socket\n");
578 r = sfunc.SendUnreliableMessage(sock, data);
579 if (r == 1 && sock->driver)
580 unreliableMessagesSent++;
590 Returns true or false if the given qsocket can currently accept a
591 message to be transmitted.
594 qboolean NET_CanSendMessage (qsocket_t *sock)
601 if (sock->disconnected)
606 r = sfunc.CanSendMessage(sock);
612 int NET_SendToAll(sizebuf_t *data, int blocktime)
617 qboolean state1 [MAX_SCOREBOARD];
618 qboolean state2 [MAX_SCOREBOARD];
620 for (i=0, host_client = svs.clients ; i<svs.maxclients ; i++, host_client++)
622 if (!host_client->netconnection)
624 if (host_client->active)
626 if (host_client->netconnection->driver == 0)
628 NET_SendMessage(host_client->netconnection, data);
644 start = Sys_DoubleTime();
648 for (i=0, host_client = svs.clients ; i<svs.maxclients ; i++, host_client++)
652 if (NET_CanSendMessage (host_client->netconnection))
655 NET_SendMessage(host_client->netconnection, data);
659 NET_GetMessage (host_client->netconnection);
667 if (NET_CanSendMessage (host_client->netconnection))
673 NET_GetMessage (host_client->netconnection);
679 if ((Sys_DoubleTime() - start) > blocktime)
686 //=============================================================================
700 i = COM_CheckParm ("-port");
702 i = COM_CheckParm ("-udpport");
704 i = COM_CheckParm ("-ipxport");
709 DEFAULTnet_hostport = atoi (com_argv[i+1]);
711 Sys_Error ("NET_Init: you must specify a number after -port");
713 net_hostport = DEFAULTnet_hostport;
715 if (COM_CheckParm("-listen") || cls.state == ca_dedicated)
717 net_numsockets = svs.maxclientslimit;
718 if (cls.state != ca_dedicated)
723 for (i = 0; i < net_numsockets; i++)
725 s = (qsocket_t *)Hunk_AllocName(sizeof(qsocket_t), "qsocket");
726 s->next = net_freeSockets;
728 s->disconnected = true;
731 // allocate space for network message buffer
732 SZ_Alloc (&net_message, NET_MAXMESSAGE);
734 Cvar_RegisterVariable (&net_messagetimeout);
735 Cvar_RegisterVariable (&hostname);
737 Cmd_AddCommand ("slist", NET_Slist_f);
738 Cmd_AddCommand ("listen", NET_Listen_f);
739 Cmd_AddCommand ("maxplayers", MaxPlayers_f);
740 Cmd_AddCommand ("port", NET_Port_f);
742 // initialize all the drivers
743 for (net_driverlevel=0 ; net_driverlevel<net_numdrivers ; net_driverlevel++)
745 controlSocket = net_drivers[net_driverlevel].Init();
746 if (controlSocket == -1)
748 net_drivers[net_driverlevel].initialized = true;
749 net_drivers[net_driverlevel].controlSock = controlSocket;
751 net_drivers[net_driverlevel].Listen (true);
755 Con_DPrintf("IPX address %s\n", my_ipx_address);
756 if (*my_tcpip_address)
757 Con_DPrintf("TCP/IP address %s\n", my_tcpip_address);
766 void NET_Shutdown (void)
772 for (sock = net_activeSockets; sock; sock = sock->next)
776 // shutdown the drivers
778 for (net_driverlevel = 0; net_driverlevel < net_numdrivers; net_driverlevel++)
780 if (net_drivers[net_driverlevel].initialized == true)
782 net_drivers[net_driverlevel].Shutdown ();
783 net_drivers[net_driverlevel].initialized = false;
789 static PollProcedure *pollProcedureList = NULL;
796 configRestored = true;
800 for (pp = pollProcedureList; pp; pp = pp->next)
802 if (pp->nextTime > net_time)
804 pollProcedureList = pp->next;
805 pp->procedure(pp->arg);
810 void SchedulePollProcedure(PollProcedure *proc, double timeOffset)
812 PollProcedure *pp, *prev;
814 proc->nextTime = Sys_DoubleTime() + timeOffset;
815 for (pp = pollProcedureList, prev = NULL; pp; pp = pp->next)
817 if (pp->nextTime >= proc->nextTime)
824 proc->next = pollProcedureList;
825 pollProcedureList = proc;