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 mempool_t *net_mempool;
27 qboolean ipxAvailable = false;
28 qboolean tcpipAvailable = false;
31 int DEFAULTnet_hostport = 26000;
33 char my_ipx_address[NET_NAMELEN];
34 char my_tcpip_address[NET_NAMELEN];
36 static qboolean listening = false;
38 qboolean slistInProgress = false;
39 qboolean slistSilent = false;
40 qboolean slistLocal = true;
41 static double slistStartTime;
42 static int slistLastShown;
44 static void Slist_Send(void);
45 static void Slist_Poll(void);
46 PollProcedure slistSendProcedure = {NULL, 0.0, Slist_Send};
47 PollProcedure slistPollProcedure = {NULL, 0.0, Slist_Poll};
50 sizebuf_t net_message;
51 int net_activeconnections = 0;
54 int messagesReceived = 0;
55 int unreliableMessagesSent = 0;
56 int unreliableMessagesReceived = 0;
58 cvar_t net_messagetimeout = {0, "net_messagetimeout","300"};
59 cvar_t hostname = {CVAR_SAVE, "hostname", "UNNAMED"};
61 qboolean configRestored = false;
63 // these two macros are to make the code more readable
64 #define sfunc net_drivers[sock->driver]
65 #define dfunc net_drivers[net_driverlevel]
72 double SetNetTime(void)
74 net_time = Sys_DoubleTime();
83 Called by drivers when a new communications endpoint is required
84 The sequence and buffer fields will be filled in properly
87 qsocket_t *NET_NewQSocket (void)
91 if (net_activeconnections >= svs.maxclients)
94 sock = Mem_Alloc(net_mempool, sizeof(qsocket_t));
96 // add it to active list
97 sock->next = net_activeSockets;
98 net_activeSockets = sock;
100 sock->disconnected = false;
101 sock->connecttime = net_time;
102 strcpy (sock->address,"UNSET ADDRESS");
103 sock->driver = net_driverlevel;
105 sock->driverdata = NULL;
106 sock->canSend = true;
107 sock->sendNext = false;
108 sock->lastMessageTime = net_time;
109 sock->ackSequence = 0;
110 sock->sendSequence = 0;
111 sock->unreliableSendSequence = 0;
112 sock->sendMessageLength = 0;
113 sock->receiveSequence = 0;
114 sock->unreliableReceiveSequence = 0;
115 sock->receiveMessageLength = 0;
121 void NET_FreeQSocket(qsocket_t *sock)
125 // remove it from active list
126 if (sock == net_activeSockets)
127 net_activeSockets = net_activeSockets->next;
130 for (s = net_activeSockets; s; s = s->next)
133 s->next = sock->next;
137 Sys_Error ("NET_FreeQSocket: not active\n");
144 static void NET_Listen_f (void)
146 if (Cmd_Argc () != 2)
148 Con_Printf ("\"listen\" is \"%u\"\n", listening ? 1 : 0);
152 listening = atoi(Cmd_Argv(1)) ? true : false;
154 for (net_driverlevel=0 ; net_driverlevel<net_numdrivers; net_driverlevel++)
156 if (net_drivers[net_driverlevel].initialized == false)
158 dfunc.Listen (listening);
163 static void MaxPlayers_f (void)
167 if (Cmd_Argc () != 2)
169 Con_Printf ("\"maxplayers\" is \"%u\"\n", svs.maxclients);
175 Con_Printf ("maxplayers can not be changed while a server is running.\n");
179 n = atoi(Cmd_Argv(1));
180 n = bound(1, n, MAX_SCOREBOARD);
181 if (svs.maxclients != n)
182 Con_Printf ("\"maxplayers\" set to \"%u\"\n", n);
184 if ((n == 1) && listening)
185 Cbuf_AddText ("listen 0\n");
187 if ((n > 1) && (!listening))
188 Cbuf_AddText ("listen 1\n");
194 static void NET_Port_f (void)
198 if (Cmd_Argc () != 2)
200 Con_Printf ("\"port\" is \"%u\"\n", net_hostport);
204 n = atoi(Cmd_Argv(1));
205 if (n < 1 || n > 65534)
207 Con_Printf ("Bad value, must be between 1 and 65534\n");
211 DEFAULTnet_hostport = n;
216 // force a change to the new port
217 Cbuf_AddText ("listen 0\n");
218 Cbuf_AddText ("listen 1\n");
223 static void PrintSlistHeader(void)
225 Con_Printf("Server Map Users\n");
226 Con_Printf("--------------- --------------- -----\n");
231 static void PrintSlist(void)
235 for (n = slistLastShown; n < hostCacheCount; n++)
237 if (hostcache[n].maxusers)
238 Con_Printf("%-15.15s %-15.15s %2u/%2u\n", hostcache[n].name, hostcache[n].map, hostcache[n].users, hostcache[n].maxusers);
240 Con_Printf("%-15.15s %-15.15s\n", hostcache[n].name, hostcache[n].map);
246 static void PrintSlistTrailer(void)
249 Con_Printf("== end list ==\n\n");
251 Con_Printf("No Quake servers found.\n\n");
255 void NET_Slist_f (void)
262 Con_Printf("Looking for Quake servers...\n");
266 slistInProgress = true;
267 slistStartTime = Sys_DoubleTime();
269 SchedulePollProcedure(&slistSendProcedure, 0.0);
270 SchedulePollProcedure(&slistPollProcedure, 0.1);
276 static void Slist_Send(void)
278 for (net_driverlevel=0; net_driverlevel < net_numdrivers; net_driverlevel++)
280 if (!slistLocal && net_driverlevel == 0)
282 if (net_drivers[net_driverlevel].initialized == false)
284 dfunc.SearchForHosts (true);
287 if ((Sys_DoubleTime() - slistStartTime) < 0.5)
288 SchedulePollProcedure(&slistSendProcedure, 0.75);
292 static void Slist_Poll(void)
294 for (net_driverlevel=0; net_driverlevel < net_numdrivers; net_driverlevel++)
296 if (!slistLocal && net_driverlevel == 0)
298 if (net_drivers[net_driverlevel].initialized == false)
300 dfunc.SearchForHosts (false);
306 if ((Sys_DoubleTime() - slistStartTime) < 1.5)
308 SchedulePollProcedure(&slistPollProcedure, 0.1);
314 slistInProgress = false;
326 int hostCacheCount = 0;
327 hostcache_t hostcache[HOSTCACHESIZE];
329 qsocket_t *NET_Connect (char *host)
333 int numdrivers = net_numdrivers;
337 if (host && *host == 0)
342 if (Q_strcasecmp (host, "local") == 0)
350 for (n = 0; n < hostCacheCount; n++)
351 if (Q_strcasecmp (host, hostcache[n].name) == 0)
353 host = hostcache[n].cname;
356 if (n < hostCacheCount)
361 slistSilent = host ? true : false;
364 while(slistInProgress)
369 if (hostCacheCount != 1)
371 host = hostcache[0].cname;
372 Con_Printf("Connecting to...\n%s @ %s\n\n", hostcache[0].name, host);
376 for (n = 0; n < hostCacheCount; n++)
377 if (Q_strcasecmp (host, hostcache[n].name) == 0)
379 host = hostcache[n].cname;
384 for (net_driverlevel=0 ; net_driverlevel<numdrivers; net_driverlevel++)
386 if (net_drivers[net_driverlevel].initialized == false)
388 ret = dfunc.Connect (host);
407 NET_CheckNewConnections
411 qsocket_t *NET_CheckNewConnections (void)
417 for (net_driverlevel=0 ; net_driverlevel<net_numdrivers; net_driverlevel++)
419 if (net_drivers[net_driverlevel].initialized == false)
421 if (net_driverlevel && listening == false)
423 ret = dfunc.CheckNewConnections ();
436 void NET_Close (qsocket_t *sock)
441 if (sock->disconnected)
446 // call the driver_Close function
449 NET_FreeQSocket(sock);
457 If there is a complete message, return it in net_message
459 returns 0 if no data is waiting
460 returns 1 if a message was received
461 returns -1 if connection is invalid
465 extern void PrintStats(qsocket_t *s);
467 int NET_GetMessage (qsocket_t *sock)
474 if (sock->disconnected)
476 Con_Printf("NET_GetMessage: disconnected socket\n");
482 ret = sfunc.QGetMessage(sock);
484 // see if this connection has timed out
485 if (ret == 0 && sock->driver)
487 if (net_time - sock->lastMessageTime > net_messagetimeout.value)
499 sock->lastMessageTime = net_time;
503 unreliableMessagesReceived++;
515 Try to send a complete length+message unit over the reliable stream.
516 returns 0 if the message cannot be delivered reliably, but the connection
517 is still considered valid
518 returns 1 if the message was sent properly
519 returns -1 if the connection died
522 int NET_SendMessage (qsocket_t *sock, sizebuf_t *data)
529 if (sock->disconnected)
531 Con_Printf("NET_SendMessage: disconnected socket\n");
536 r = sfunc.QSendMessage(sock, data);
537 if (r == 1 && sock->driver)
544 int NET_SendUnreliableMessage (qsocket_t *sock, sizebuf_t *data)
551 if (sock->disconnected)
553 Con_Printf("NET_SendMessage: disconnected socket\n");
558 r = sfunc.SendUnreliableMessage(sock, data);
559 if (r == 1 && sock->driver)
560 unreliableMessagesSent++;
570 Returns true or false if the given qsocket can currently accept a
571 message to be transmitted.
574 qboolean NET_CanSendMessage (qsocket_t *sock)
581 if (sock->disconnected)
586 r = sfunc.CanSendMessage(sock);
592 int NET_SendToAll(sizebuf_t *data, int blocktime)
597 qboolean state1 [MAX_SCOREBOARD];
598 qboolean state2 [MAX_SCOREBOARD];
600 for (i=0, host_client = svs.clients ; i<svs.maxclients ; i++, host_client++)
602 if (!host_client->netconnection)
604 if (host_client->active)
606 if (host_client->netconnection->driver == 0)
608 NET_SendMessage(host_client->netconnection, data);
624 start = Sys_DoubleTime();
628 for (i=0, host_client = svs.clients ; i<svs.maxclients ; i++, host_client++)
632 if (NET_CanSendMessage (host_client->netconnection))
635 NET_SendMessage(host_client->netconnection, data);
639 NET_GetMessage (host_client->netconnection);
647 if (NET_CanSendMessage (host_client->netconnection))
653 NET_GetMessage (host_client->netconnection);
659 if ((Sys_DoubleTime() - start) > blocktime)
666 //=============================================================================
679 i = COM_CheckParm ("-port");
681 i = COM_CheckParm ("-udpport");
683 i = COM_CheckParm ("-ipxport");
688 DEFAULTnet_hostport = atoi (com_argv[i+1]);
690 Sys_Error ("NET_Init: you must specify a number after -port");
692 net_hostport = DEFAULTnet_hostport;
694 if (COM_CheckParm("-listen") || cls.state == ca_dedicated || gamemode == GAME_TRANSFUSION)
699 net_mempool = Mem_AllocPool("qsocket");
701 // allocate space for network message buffer
702 SZ_Alloc (&net_message, NET_MAXMESSAGE, "net_message");
704 Cvar_RegisterVariable (&net_messagetimeout);
705 Cvar_RegisterVariable (&hostname);
707 Cmd_AddCommand ("slist", NET_Slist_f);
708 Cmd_AddCommand ("listen", NET_Listen_f);
709 Cmd_AddCommand ("maxplayers", MaxPlayers_f);
710 Cmd_AddCommand ("port", NET_Port_f);
712 // initialize all the drivers
713 for (net_driverlevel=0 ; net_driverlevel<net_numdrivers ; net_driverlevel++)
715 controlSocket = net_drivers[net_driverlevel].Init();
716 if (controlSocket == -1)
718 net_drivers[net_driverlevel].initialized = true;
719 net_drivers[net_driverlevel].controlSock = controlSocket;
721 net_drivers[net_driverlevel].Listen (true);
725 Con_DPrintf("IPX address %s\n", my_ipx_address);
726 if (*my_tcpip_address)
727 Con_DPrintf("TCP/IP address %s\n", my_tcpip_address);
736 void NET_Shutdown (void)
740 while (net_activeSockets)
741 NET_Close(net_activeSockets);
744 // shutdown the drivers
746 for (net_driverlevel = 0; net_driverlevel < net_numdrivers; net_driverlevel++)
748 if (net_drivers[net_driverlevel].initialized == true)
750 net_drivers[net_driverlevel].Shutdown ();
751 net_drivers[net_driverlevel].initialized = false;
755 Mem_FreePool(&net_mempool);
759 static PollProcedure *pollProcedureList = NULL;
766 configRestored = true;
770 for (pp = pollProcedureList; pp; pp = pp->next)
772 if (pp->nextTime > net_time)
774 pollProcedureList = pp->next;
775 pp->procedure(pp->arg);
780 void SchedulePollProcedure(PollProcedure *proc, double timeOffset)
782 PollProcedure *pp, *prev;
784 proc->nextTime = Sys_DoubleTime() + timeOffset;
785 for (pp = pollProcedureList, prev = NULL; pp; pp = pp->next)
787 if (pp->nextTime >= proc->nextTime)
794 proc->next = pollProcedureList;
795 pollProcedureList = proc;