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 serialAvailable = false;
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 void (*GetComPortConfig) (int portNumber, int *port, int *irq, int *baud, qboolean *useModem);
39 void (*SetComPortConfig) (int portNumber, int port, int irq, int baud, qboolean useModem);
40 void (*GetModemConfig) (int portNumber, char *dialType, char *clear, char *init, char *hangup);
41 void (*SetModemConfig) (int portNumber, char *dialType, char *clear, char *init, char *hangup);
43 static qboolean listening = false;
45 qboolean slistInProgress = false;
46 qboolean slistSilent = false;
47 qboolean slistLocal = true;
48 static double slistStartTime;
49 static int slistLastShown;
51 static void Slist_Send(void);
52 static void Slist_Poll(void);
53 PollProcedure slistSendProcedure = {NULL, 0.0, Slist_Send};
54 PollProcedure slistPollProcedure = {NULL, 0.0, Slist_Poll};
57 sizebuf_t net_message;
58 int net_activeconnections = 0;
61 int messagesReceived = 0;
62 int unreliableMessagesSent = 0;
63 int unreliableMessagesReceived = 0;
65 cvar_t net_messagetimeout = {"net_messagetimeout","300"};
66 cvar_t hostname = {"hostname", "UNNAMED"};
68 qboolean configRestored = false;
69 cvar_t config_com_port = {"_config_com_port", "0x3f8", true};
70 cvar_t config_com_irq = {"_config_com_irq", "4", true};
71 cvar_t config_com_baud = {"_config_com_baud", "57600", true};
72 cvar_t config_com_modem = {"_config_com_modem", "1", true};
73 cvar_t config_modem_dialtype = {"_config_modem_dialtype", "T", true};
74 cvar_t config_modem_clear = {"_config_modem_clear", "ATZ", true};
75 cvar_t config_modem_init = {"_config_modem_init", "", true};
76 cvar_t config_modem_hangup = {"_config_modem_hangup", "AT H", true};
78 // these two macros are to make the code more readable
79 #define sfunc net_drivers[sock->driver]
80 #define dfunc net_drivers[net_driverlevel]
87 double SetNetTime(void)
89 net_time = Sys_FloatTime();
98 Called by drivers when a new communications endpoint is required
99 The sequence and buffer fields will be filled in properly
102 qsocket_t *NET_NewQSocket (void)
106 if (net_freeSockets == NULL)
109 if (net_activeconnections >= svs.maxclients)
112 // get one from free list
113 sock = net_freeSockets;
114 net_freeSockets = sock->next;
116 // add it to active list
117 sock->next = net_activeSockets;
118 net_activeSockets = sock;
120 sock->disconnected = false;
121 sock->connecttime = net_time;
122 strcpy (sock->address,"UNSET ADDRESS");
123 sock->driver = net_driverlevel;
125 sock->driverdata = NULL;
126 sock->canSend = true;
127 sock->sendNext = false;
128 sock->lastMessageTime = net_time;
129 sock->ackSequence = 0;
130 sock->sendSequence = 0;
131 sock->unreliableSendSequence = 0;
132 sock->sendMessageLength = 0;
133 sock->receiveSequence = 0;
134 sock->unreliableReceiveSequence = 0;
135 sock->receiveMessageLength = 0;
141 void NET_FreeQSocket(qsocket_t *sock)
145 // remove it from active list
146 if (sock == net_activeSockets)
147 net_activeSockets = net_activeSockets->next;
150 for (s = net_activeSockets; s; s = s->next)
153 s->next = sock->next;
157 Sys_Error ("NET_FreeQSocket: not active\n");
160 // add it to free list
161 sock->next = net_freeSockets;
162 net_freeSockets = sock;
163 sock->disconnected = true;
167 static void NET_Listen_f (void)
169 if (Cmd_Argc () != 2)
171 Con_Printf ("\"listen\" is \"%u\"\n", listening ? 1 : 0);
175 listening = atoi(Cmd_Argv(1)) ? true : false;
177 for (net_driverlevel=0 ; net_driverlevel<net_numdrivers; net_driverlevel++)
179 if (net_drivers[net_driverlevel].initialized == false)
181 dfunc.Listen (listening);
186 static void MaxPlayers_f (void)
190 if (Cmd_Argc () != 2)
192 Con_Printf ("\"maxplayers\" is \"%u\"\n", svs.maxclients);
198 Con_Printf ("maxplayers can not be changed while a server is running.\n");
202 n = atoi(Cmd_Argv(1));
205 if (n > svs.maxclientslimit)
207 n = svs.maxclientslimit;
208 Con_Printf ("\"maxplayers\" set to \"%u\"\n", n);
211 if ((n == 1) && listening)
212 Cbuf_AddText ("listen 0\n");
214 if ((n > 1) && (!listening))
215 Cbuf_AddText ("listen 1\n");
218 // LordHavoc: resetting deathmatch and coop was silly
221 Cvar_Set ("deathmatch", "0");
223 Cvar_Set ("deathmatch", "1");
228 static void NET_Port_f (void)
232 if (Cmd_Argc () != 2)
234 Con_Printf ("\"port\" is \"%u\"\n", net_hostport);
238 n = atoi(Cmd_Argv(1));
239 if (n < 1 || n > 65534)
241 Con_Printf ("Bad value, must be between 1 and 65534\n");
245 DEFAULTnet_hostport = n;
250 // force a change to the new port
251 Cbuf_AddText ("listen 0\n");
252 Cbuf_AddText ("listen 1\n");
257 static void PrintSlistHeader(void)
259 Con_Printf("Server Map Users\n");
260 Con_Printf("--------------- --------------- -----\n");
265 static void PrintSlist(void)
269 for (n = slistLastShown; n < hostCacheCount; n++)
271 if (hostcache[n].maxusers)
272 Con_Printf("%-15.15s %-15.15s %2u/%2u\n", hostcache[n].name, hostcache[n].map, hostcache[n].users, hostcache[n].maxusers);
274 Con_Printf("%-15.15s %-15.15s\n", hostcache[n].name, hostcache[n].map);
280 static void PrintSlistTrailer(void)
283 Con_Printf("== end list ==\n\n");
285 Con_Printf("No Quake servers found.\n\n");
289 void NET_Slist_f (void)
296 Con_Printf("Looking for Quake servers...\n");
300 slistInProgress = true;
301 slistStartTime = Sys_FloatTime();
303 SchedulePollProcedure(&slistSendProcedure, 0.0);
304 SchedulePollProcedure(&slistPollProcedure, 0.1);
310 static void Slist_Send(void)
312 for (net_driverlevel=0; net_driverlevel < net_numdrivers; net_driverlevel++)
314 if (!slistLocal && net_driverlevel == 0)
316 if (net_drivers[net_driverlevel].initialized == false)
318 dfunc.SearchForHosts (true);
321 if ((Sys_FloatTime() - slistStartTime) < 0.5)
322 SchedulePollProcedure(&slistSendProcedure, 0.75);
326 static void Slist_Poll(void)
328 for (net_driverlevel=0; net_driverlevel < net_numdrivers; net_driverlevel++)
330 if (!slistLocal && net_driverlevel == 0)
332 if (net_drivers[net_driverlevel].initialized == false)
334 dfunc.SearchForHosts (false);
340 if ((Sys_FloatTime() - slistStartTime) < 1.5)
342 SchedulePollProcedure(&slistPollProcedure, 0.1);
348 slistInProgress = false;
360 int hostCacheCount = 0;
361 hostcache_t hostcache[HOSTCACHESIZE];
363 qsocket_t *NET_Connect (char *host)
367 int numdrivers = net_numdrivers;
371 if (host && *host == 0)
376 if (Q_strcasecmp (host, "local") == 0)
384 for (n = 0; n < hostCacheCount; n++)
385 if (Q_strcasecmp (host, hostcache[n].name) == 0)
387 host = hostcache[n].cname;
390 if (n < hostCacheCount)
395 slistSilent = host ? true : false;
398 while(slistInProgress)
403 if (hostCacheCount != 1)
405 host = hostcache[0].cname;
406 Con_Printf("Connecting to...\n%s @ %s\n\n", hostcache[0].name, host);
410 for (n = 0; n < hostCacheCount; n++)
411 if (Q_strcasecmp (host, hostcache[n].name) == 0)
413 host = hostcache[n].cname;
418 for (net_driverlevel=0 ; net_driverlevel<numdrivers; net_driverlevel++)
420 if (net_drivers[net_driverlevel].initialized == false)
422 ret = dfunc.Connect (host);
441 NET_CheckNewConnections
445 qsocket_t *NET_CheckNewConnections (void)
451 for (net_driverlevel=0 ; net_driverlevel<net_numdrivers; net_driverlevel++)
453 if (net_drivers[net_driverlevel].initialized == false)
455 if (net_driverlevel && listening == false)
457 ret = dfunc.CheckNewConnections ();
470 void NET_Close (qsocket_t *sock)
475 if (sock->disconnected)
480 // call the driver_Close function
483 NET_FreeQSocket(sock);
491 If there is a complete message, return it in net_message
493 returns 0 if no data is waiting
494 returns 1 if a message was received
495 returns -1 if connection is invalid
499 extern void PrintStats(qsocket_t *s);
501 int NET_GetMessage (qsocket_t *sock)
508 if (sock->disconnected)
510 Con_Printf("NET_GetMessage: disconnected socket\n");
516 ret = sfunc.QGetMessage(sock);
518 // see if this connection has timed out
519 if (ret == 0 && sock->driver)
521 if (net_time - sock->lastMessageTime > net_messagetimeout.value)
533 sock->lastMessageTime = net_time;
537 unreliableMessagesReceived++;
549 Try to send a complete length+message unit over the reliable stream.
550 returns 0 if the message cannot be delivered reliably, but the connection
551 is still considered valid
552 returns 1 if the message was sent properly
553 returns -1 if the connection died
556 int NET_SendMessage (qsocket_t *sock, sizebuf_t *data)
563 if (sock->disconnected)
565 Con_Printf("NET_SendMessage: disconnected socket\n");
570 r = sfunc.QSendMessage(sock, data);
571 if (r == 1 && sock->driver)
578 int NET_SendUnreliableMessage (qsocket_t *sock, sizebuf_t *data)
585 if (sock->disconnected)
587 Con_Printf("NET_SendMessage: disconnected socket\n");
592 r = sfunc.SendUnreliableMessage(sock, data);
593 if (r == 1 && sock->driver)
594 unreliableMessagesSent++;
604 Returns true or false if the given qsocket can currently accept a
605 message to be transmitted.
608 qboolean NET_CanSendMessage (qsocket_t *sock)
615 if (sock->disconnected)
620 r = sfunc.CanSendMessage(sock);
626 int NET_SendToAll(sizebuf_t *data, int blocktime)
631 qboolean state1 [MAX_SCOREBOARD];
632 qboolean state2 [MAX_SCOREBOARD];
634 for (i=0, host_client = svs.clients ; i<svs.maxclients ; i++, host_client++)
636 if (!host_client->netconnection)
638 if (host_client->active)
640 if (host_client->netconnection->driver == 0)
642 NET_SendMessage(host_client->netconnection, data);
658 start = Sys_FloatTime();
662 for (i=0, host_client = svs.clients ; i<svs.maxclients ; i++, host_client++)
666 if (NET_CanSendMessage (host_client->netconnection))
669 NET_SendMessage(host_client->netconnection, data);
673 NET_GetMessage (host_client->netconnection);
681 if (NET_CanSendMessage (host_client->netconnection))
687 NET_GetMessage (host_client->netconnection);
693 if ((Sys_FloatTime() - start) > blocktime)
700 //=============================================================================
714 i = COM_CheckParm ("-port");
716 i = COM_CheckParm ("-udpport");
718 i = COM_CheckParm ("-ipxport");
723 DEFAULTnet_hostport = atoi (com_argv[i+1]);
725 Sys_Error ("NET_Init: you must specify a number after -port");
727 net_hostport = DEFAULTnet_hostport;
729 if (COM_CheckParm("-listen") || cls.state == ca_dedicated)
731 net_numsockets = svs.maxclientslimit;
732 if (cls.state != ca_dedicated)
737 for (i = 0; i < net_numsockets; i++)
739 s = (qsocket_t *)Hunk_AllocName(sizeof(qsocket_t), "qsocket");
740 s->next = net_freeSockets;
742 s->disconnected = true;
745 // allocate space for network message buffer
746 SZ_Alloc (&net_message, NET_MAXMESSAGE);
748 Cvar_RegisterVariable (&net_messagetimeout);
749 Cvar_RegisterVariable (&hostname);
750 Cvar_RegisterVariable (&config_com_port);
751 Cvar_RegisterVariable (&config_com_irq);
752 Cvar_RegisterVariable (&config_com_baud);
753 Cvar_RegisterVariable (&config_com_modem);
754 Cvar_RegisterVariable (&config_modem_dialtype);
755 Cvar_RegisterVariable (&config_modem_clear);
756 Cvar_RegisterVariable (&config_modem_init);
757 Cvar_RegisterVariable (&config_modem_hangup);
759 Cmd_AddCommand ("slist", NET_Slist_f);
760 Cmd_AddCommand ("listen", NET_Listen_f);
761 Cmd_AddCommand ("maxplayers", MaxPlayers_f);
762 Cmd_AddCommand ("port", NET_Port_f);
764 // initialize all the drivers
765 for (net_driverlevel=0 ; net_driverlevel<net_numdrivers ; net_driverlevel++)
767 controlSocket = net_drivers[net_driverlevel].Init();
768 if (controlSocket == -1)
770 net_drivers[net_driverlevel].initialized = true;
771 net_drivers[net_driverlevel].controlSock = controlSocket;
773 net_drivers[net_driverlevel].Listen (true);
777 Con_DPrintf("IPX address %s\n", my_ipx_address);
778 if (*my_tcpip_address)
779 Con_DPrintf("TCP/IP address %s\n", my_tcpip_address);
788 void NET_Shutdown (void)
794 for (sock = net_activeSockets; sock; sock = sock->next)
798 // shutdown the drivers
800 for (net_driverlevel = 0; net_driverlevel < net_numdrivers; net_driverlevel++)
802 if (net_drivers[net_driverlevel].initialized == true)
804 net_drivers[net_driverlevel].Shutdown ();
805 net_drivers[net_driverlevel].initialized = false;
811 static PollProcedure *pollProcedureList = NULL;
822 if (config_com_modem.value == 1.0)
826 SetComPortConfig (0, (int)config_com_port.value, (int)config_com_irq.value, (int)config_com_baud.value, useModem);
827 SetModemConfig (0, config_modem_dialtype.string, config_modem_clear.string, config_modem_init.string, config_modem_hangup.string);
829 configRestored = true;
834 for (pp = pollProcedureList; pp; pp = pp->next)
836 if (pp->nextTime > net_time)
838 pollProcedureList = pp->next;
839 pp->procedure(pp->arg);
844 void SchedulePollProcedure(PollProcedure *proc, double timeOffset)
846 PollProcedure *pp, *prev;
848 proc->nextTime = Sys_FloatTime() + timeOffset;
849 for (pp = pollProcedureList, prev = NULL; pp; pp = pp->next)
851 if (pp->nextTime >= proc->nextTime)
858 proc->next = pollProcedureList;
859 pollProcedureList = proc;