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.
25 qsocket_t *net_activeSockets = NULL;
26 qsocket_t *net_freeSockets = NULL;
27 int net_numsockets = 0;
29 qboolean serialAvailable = false;
30 qboolean ipxAvailable = false;
31 qboolean tcpipAvailable = false;
34 int DEFAULTnet_hostport = 26000;
36 char my_ipx_address[NET_NAMELEN];
37 char my_tcpip_address[NET_NAMELEN];
39 void (*GetComPortConfig) (int portNumber, int *port, int *irq, int *baud, qboolean *useModem);
40 void (*SetComPortConfig) (int portNumber, int port, int irq, int baud, qboolean useModem);
41 void (*GetModemConfig) (int portNumber, char *dialType, char *clear, char *init, char *hangup);
42 void (*SetModemConfig) (int portNumber, char *dialType, char *clear, char *init, char *hangup);
44 static qboolean listening = false;
46 qboolean slistInProgress = false;
47 qboolean slistSilent = false;
48 qboolean slistLocal = true;
49 static double slistStartTime;
50 static int slistLastShown;
52 static void Slist_Send(void);
53 static void Slist_Poll(void);
54 PollProcedure slistSendProcedure = {NULL, 0.0, Slist_Send};
55 PollProcedure slistPollProcedure = {NULL, 0.0, Slist_Poll};
58 sizebuf_t net_message;
59 int net_activeconnections = 0;
62 int messagesReceived = 0;
63 int unreliableMessagesSent = 0;
64 int unreliableMessagesReceived = 0;
66 cvar_t net_messagetimeout = {"net_messagetimeout","300"};
67 cvar_t hostname = {"hostname", "UNNAMED"};
69 qboolean configRestored = false;
70 cvar_t config_com_port = {"_config_com_port", "0x3f8", true};
71 cvar_t config_com_irq = {"_config_com_irq", "4", true};
72 cvar_t config_com_baud = {"_config_com_baud", "57600", true};
73 cvar_t config_com_modem = {"_config_com_modem", "1", true};
74 cvar_t config_modem_dialtype = {"_config_modem_dialtype", "T", true};
75 cvar_t config_modem_clear = {"_config_modem_clear", "ATZ", true};
76 cvar_t config_modem_init = {"_config_modem_init", "", true};
77 cvar_t config_modem_hangup = {"_config_modem_hangup", "AT H", true};
80 cvar_t idgods = {"idgods", "0"};
84 qboolean recording = false;
86 // these two macros are to make the code more readable
87 #define sfunc net_drivers[sock->driver]
88 #define dfunc net_drivers[net_driverlevel]
95 double SetNetTime(void)
97 net_time = Sys_FloatTime();
106 Called by drivers when a new communications endpoint is required
107 The sequence and buffer fields will be filled in properly
110 qsocket_t *NET_NewQSocket (void)
114 if (net_freeSockets == NULL)
117 if (net_activeconnections >= svs.maxclients)
120 // get one from free list
121 sock = net_freeSockets;
122 net_freeSockets = sock->next;
124 // add it to active list
125 sock->next = net_activeSockets;
126 net_activeSockets = sock;
128 sock->disconnected = false;
129 sock->connecttime = net_time;
130 strcpy (sock->address,"UNSET ADDRESS");
131 sock->driver = net_driverlevel;
133 sock->driverdata = NULL;
134 sock->canSend = true;
135 sock->sendNext = false;
136 sock->lastMessageTime = net_time;
137 sock->ackSequence = 0;
138 sock->sendSequence = 0;
139 sock->unreliableSendSequence = 0;
140 sock->sendMessageLength = 0;
141 sock->receiveSequence = 0;
142 sock->unreliableReceiveSequence = 0;
143 sock->receiveMessageLength = 0;
149 void NET_FreeQSocket(qsocket_t *sock)
153 // remove it from active list
154 if (sock == net_activeSockets)
155 net_activeSockets = net_activeSockets->next;
158 for (s = net_activeSockets; s; s = s->next)
161 s->next = sock->next;
165 Sys_Error ("NET_FreeQSocket: not active\n");
168 // add it to free list
169 sock->next = net_freeSockets;
170 net_freeSockets = sock;
171 sock->disconnected = true;
175 static void NET_Listen_f (void)
177 if (Cmd_Argc () != 2)
179 Con_Printf ("\"listen\" is \"%u\"\n", listening ? 1 : 0);
183 listening = atoi(Cmd_Argv(1)) ? true : false;
185 for (net_driverlevel=0 ; net_driverlevel<net_numdrivers; net_driverlevel++)
187 if (net_drivers[net_driverlevel].initialized == false)
189 dfunc.Listen (listening);
194 static void MaxPlayers_f (void)
198 if (Cmd_Argc () != 2)
200 Con_Printf ("\"maxplayers\" is \"%u\"\n", svs.maxclients);
206 Con_Printf ("maxplayers can not be changed while a server is running.\n");
210 n = atoi(Cmd_Argv(1));
213 if (n > svs.maxclientslimit)
215 n = svs.maxclientslimit;
216 Con_Printf ("\"maxplayers\" set to \"%u\"\n", n);
219 if ((n == 1) && listening)
220 Cbuf_AddText ("listen 0\n");
222 if ((n > 1) && (!listening))
223 Cbuf_AddText ("listen 1\n");
226 // LordHavoc: resetting deathmatch and coop was silly
229 Cvar_Set ("deathmatch", "0");
231 Cvar_Set ("deathmatch", "1");
236 static void NET_Port_f (void)
240 if (Cmd_Argc () != 2)
242 Con_Printf ("\"port\" is \"%u\"\n", net_hostport);
246 n = atoi(Cmd_Argv(1));
247 if (n < 1 || n > 65534)
249 Con_Printf ("Bad value, must be between 1 and 65534\n");
253 DEFAULTnet_hostport = n;
258 // force a change to the new port
259 Cbuf_AddText ("listen 0\n");
260 Cbuf_AddText ("listen 1\n");
265 static void PrintSlistHeader(void)
267 Con_Printf("Server Map Users\n");
268 Con_Printf("--------------- --------------- -----\n");
273 static void PrintSlist(void)
277 for (n = slistLastShown; n < hostCacheCount; n++)
279 if (hostcache[n].maxusers)
280 Con_Printf("%-15.15s %-15.15s %2u/%2u\n", hostcache[n].name, hostcache[n].map, hostcache[n].users, hostcache[n].maxusers);
282 Con_Printf("%-15.15s %-15.15s\n", hostcache[n].name, hostcache[n].map);
288 static void PrintSlistTrailer(void)
291 Con_Printf("== end list ==\n\n");
293 Con_Printf("No Quake servers found.\n\n");
297 void NET_Slist_f (void)
304 Con_Printf("Looking for Quake servers...\n");
308 slistInProgress = true;
309 slistStartTime = Sys_FloatTime();
311 SchedulePollProcedure(&slistSendProcedure, 0.0);
312 SchedulePollProcedure(&slistPollProcedure, 0.1);
318 static void Slist_Send(void)
320 for (net_driverlevel=0; net_driverlevel < net_numdrivers; net_driverlevel++)
322 if (!slistLocal && net_driverlevel == 0)
324 if (net_drivers[net_driverlevel].initialized == false)
326 dfunc.SearchForHosts (true);
329 if ((Sys_FloatTime() - slistStartTime) < 0.5)
330 SchedulePollProcedure(&slistSendProcedure, 0.75);
334 static void Slist_Poll(void)
336 for (net_driverlevel=0; net_driverlevel < net_numdrivers; net_driverlevel++)
338 if (!slistLocal && net_driverlevel == 0)
340 if (net_drivers[net_driverlevel].initialized == false)
342 dfunc.SearchForHosts (false);
348 if ((Sys_FloatTime() - slistStartTime) < 1.5)
350 SchedulePollProcedure(&slistPollProcedure, 0.1);
356 slistInProgress = false;
368 int hostCacheCount = 0;
369 hostcache_t hostcache[HOSTCACHESIZE];
371 qsocket_t *NET_Connect (char *host)
375 int numdrivers = net_numdrivers;
379 if (host && *host == 0)
384 if (Q_strcasecmp (host, "local") == 0)
392 for (n = 0; n < hostCacheCount; n++)
393 if (Q_strcasecmp (host, hostcache[n].name) == 0)
395 host = hostcache[n].cname;
398 if (n < hostCacheCount)
403 slistSilent = host ? true : false;
406 while(slistInProgress)
411 if (hostCacheCount != 1)
413 host = hostcache[0].cname;
414 Con_Printf("Connecting to...\n%s @ %s\n\n", hostcache[0].name, host);
418 for (n = 0; n < hostCacheCount; n++)
419 if (Q_strcasecmp (host, hostcache[n].name) == 0)
421 host = hostcache[n].cname;
426 for (net_driverlevel=0 ; net_driverlevel<numdrivers; net_driverlevel++)
428 if (net_drivers[net_driverlevel].initialized == false)
430 ret = dfunc.Connect (host);
449 NET_CheckNewConnections
460 qsocket_t *NET_CheckNewConnections (void)
466 for (net_driverlevel=0 ; net_driverlevel<net_numdrivers; net_driverlevel++)
468 if (net_drivers[net_driverlevel].initialized == false)
470 if (net_driverlevel && listening == false)
472 ret = dfunc.CheckNewConnections ();
477 vcrConnect.time = host_time;
478 vcrConnect.op = VCR_OP_CONNECT;
479 vcrConnect.session = (long)ret;
480 Sys_FileWrite (vcrFile, &vcrConnect, sizeof(vcrConnect));
481 Sys_FileWrite (vcrFile, ret->address, NET_NAMELEN);
489 vcrConnect.time = host_time;
490 vcrConnect.op = VCR_OP_CONNECT;
491 vcrConnect.session = 0;
492 Sys_FileWrite (vcrFile, &vcrConnect, sizeof(vcrConnect));
503 void NET_Close (qsocket_t *sock)
508 if (sock->disconnected)
513 // call the driver_Close function
516 NET_FreeQSocket(sock);
524 If there is a complete message, return it in net_message
526 returns 0 if no data is waiting
527 returns 1 if a message was received
528 returns -1 if connection is invalid
541 extern void PrintStats(qsocket_t *s);
543 int NET_GetMessage (qsocket_t *sock)
550 if (sock->disconnected)
552 Con_Printf("NET_GetMessage: disconnected socket\n");
558 ret = sfunc.QGetMessage(sock);
560 // see if this connection has timed out
561 if (ret == 0 && sock->driver)
563 if (net_time - sock->lastMessageTime > net_messagetimeout.value)
575 sock->lastMessageTime = net_time;
579 unreliableMessagesReceived++;
584 vcrGetMessage.time = host_time;
585 vcrGetMessage.op = VCR_OP_GETMESSAGE;
586 vcrGetMessage.session = (long)sock;
587 vcrGetMessage.ret = ret;
588 vcrGetMessage.len = net_message.cursize;
589 Sys_FileWrite (vcrFile, &vcrGetMessage, 24);
590 Sys_FileWrite (vcrFile, net_message.data, net_message.cursize);
597 vcrGetMessage.time = host_time;
598 vcrGetMessage.op = VCR_OP_GETMESSAGE;
599 vcrGetMessage.session = (long)sock;
600 vcrGetMessage.ret = ret;
601 Sys_FileWrite (vcrFile, &vcrGetMessage, 20);
613 Try to send a complete length+message unit over the reliable stream.
614 returns 0 if the message cannot be delivered reliably, but the connection
615 is still considered valid
616 returns 1 if the message was sent properly
617 returns -1 if the connection died
628 int NET_SendMessage (qsocket_t *sock, sizebuf_t *data)
635 if (sock->disconnected)
637 Con_Printf("NET_SendMessage: disconnected socket\n");
642 r = sfunc.QSendMessage(sock, data);
643 if (r == 1 && sock->driver)
648 vcrSendMessage.time = host_time;
649 vcrSendMessage.op = VCR_OP_SENDMESSAGE;
650 vcrSendMessage.session = (long)sock;
651 vcrSendMessage.r = r;
652 Sys_FileWrite (vcrFile, &vcrSendMessage, 20);
659 int NET_SendUnreliableMessage (qsocket_t *sock, sizebuf_t *data)
666 if (sock->disconnected)
668 Con_Printf("NET_SendMessage: disconnected socket\n");
673 r = sfunc.SendUnreliableMessage(sock, data);
674 if (r == 1 && sock->driver)
675 unreliableMessagesSent++;
679 vcrSendMessage.time = host_time;
680 vcrSendMessage.op = VCR_OP_SENDMESSAGE;
681 vcrSendMessage.session = (long)sock;
682 vcrSendMessage.r = r;
683 Sys_FileWrite (vcrFile, &vcrSendMessage, 20);
694 Returns true or false if the given qsocket can currently accept a
695 message to be transmitted.
698 qboolean NET_CanSendMessage (qsocket_t *sock)
705 if (sock->disconnected)
710 r = sfunc.CanSendMessage(sock);
714 vcrSendMessage.time = host_time;
715 vcrSendMessage.op = VCR_OP_CANSENDMESSAGE;
716 vcrSendMessage.session = (long)sock;
717 vcrSendMessage.r = r;
718 Sys_FileWrite (vcrFile, &vcrSendMessage, 20);
725 int NET_SendToAll(sizebuf_t *data, int blocktime)
730 qboolean state1 [MAX_SCOREBOARD];
731 qboolean state2 [MAX_SCOREBOARD];
733 for (i=0, host_client = svs.clients ; i<svs.maxclients ; i++, host_client++)
735 if (!host_client->netconnection)
737 if (host_client->active)
739 if (host_client->netconnection->driver == 0)
741 NET_SendMessage(host_client->netconnection, data);
757 start = Sys_FloatTime();
761 for (i=0, host_client = svs.clients ; i<svs.maxclients ; i++, host_client++)
765 if (NET_CanSendMessage (host_client->netconnection))
768 NET_SendMessage(host_client->netconnection, data);
772 NET_GetMessage (host_client->netconnection);
780 if (NET_CanSendMessage (host_client->netconnection))
786 NET_GetMessage (host_client->netconnection);
792 if ((Sys_FloatTime() - start) > blocktime)
799 //=============================================================================
813 if (COM_CheckParm("-playback"))
816 net_drivers[0].Init = VCR_Init;
819 if (COM_CheckParm("-record"))
822 i = COM_CheckParm ("-port");
824 i = COM_CheckParm ("-udpport");
826 i = COM_CheckParm ("-ipxport");
831 DEFAULTnet_hostport = atoi (com_argv[i+1]);
833 Sys_Error ("NET_Init: you must specify a number after -port");
835 net_hostport = DEFAULTnet_hostport;
837 if (COM_CheckParm("-listen") || cls.state == ca_dedicated)
839 net_numsockets = svs.maxclientslimit;
840 if (cls.state != ca_dedicated)
845 for (i = 0; i < net_numsockets; i++)
847 s = (qsocket_t *)Hunk_AllocName(sizeof(qsocket_t), "qsocket");
848 s->next = net_freeSockets;
850 s->disconnected = true;
853 // allocate space for network message buffer
854 SZ_Alloc (&net_message, NET_MAXMESSAGE);
856 Cvar_RegisterVariable (&net_messagetimeout);
857 Cvar_RegisterVariable (&hostname);
858 Cvar_RegisterVariable (&config_com_port);
859 Cvar_RegisterVariable (&config_com_irq);
860 Cvar_RegisterVariable (&config_com_baud);
861 Cvar_RegisterVariable (&config_com_modem);
862 Cvar_RegisterVariable (&config_modem_dialtype);
863 Cvar_RegisterVariable (&config_modem_clear);
864 Cvar_RegisterVariable (&config_modem_init);
865 Cvar_RegisterVariable (&config_modem_hangup);
867 Cvar_RegisterVariable (&idgods);
870 Cmd_AddCommand ("slist", NET_Slist_f);
871 Cmd_AddCommand ("listen", NET_Listen_f);
872 Cmd_AddCommand ("maxplayers", MaxPlayers_f);
873 Cmd_AddCommand ("port", NET_Port_f);
875 // initialize all the drivers
876 for (net_driverlevel=0 ; net_driverlevel<net_numdrivers ; net_driverlevel++)
878 controlSocket = net_drivers[net_driverlevel].Init();
879 if (controlSocket == -1)
881 net_drivers[net_driverlevel].initialized = true;
882 net_drivers[net_driverlevel].controlSock = controlSocket;
884 net_drivers[net_driverlevel].Listen (true);
888 Con_DPrintf("IPX address %s\n", my_ipx_address);
889 if (*my_tcpip_address)
890 Con_DPrintf("TCP/IP address %s\n", my_tcpip_address);
899 void NET_Shutdown (void)
905 for (sock = net_activeSockets; sock; sock = sock->next)
909 // shutdown the drivers
911 for (net_driverlevel = 0; net_driverlevel < net_numdrivers; net_driverlevel++)
913 if (net_drivers[net_driverlevel].initialized == true)
915 net_drivers[net_driverlevel].Shutdown ();
916 net_drivers[net_driverlevel].initialized = false;
922 Con_Printf ("Closing vcrfile.\n");
923 Sys_FileClose(vcrFile);
928 static PollProcedure *pollProcedureList = NULL;
939 if (config_com_modem.value == 1.0)
943 SetComPortConfig (0, (int)config_com_port.value, (int)config_com_irq.value, (int)config_com_baud.value, useModem);
944 SetModemConfig (0, config_modem_dialtype.string, config_modem_clear.string, config_modem_init.string, config_modem_hangup.string);
946 configRestored = true;
951 for (pp = pollProcedureList; pp; pp = pp->next)
953 if (pp->nextTime > net_time)
955 pollProcedureList = pp->next;
956 pp->procedure(pp->arg);
961 void SchedulePollProcedure(PollProcedure *proc, double timeOffset)
963 PollProcedure *pp, *prev;
965 proc->nextTime = Sys_FloatTime() + timeOffset;
966 for (pp = pollProcedureList, prev = NULL; pp; pp = pp->next)
968 if (pp->nextTime >= proc->nextTime)
975 proc->next = pollProcedureList;
976 pollProcedureList = proc;
986 #define IDNET 0xc0f62800
988 qboolean IsID(struct qsockaddr *addr)
990 if (idgods.value == 0.0)
993 if (addr->sa_family != 2)
996 if ((BigLong(*(int *)&addr->sa_data[2]) & 0xffffff00) == IDNET)