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 qboolean recording = false;
82 // these two macros are to make the code more readable
83 #define sfunc net_drivers[sock->driver]
84 #define dfunc net_drivers[net_driverlevel]
91 double SetNetTime(void)
93 net_time = Sys_FloatTime();
102 Called by drivers when a new communications endpoint is required
103 The sequence and buffer fields will be filled in properly
106 qsocket_t *NET_NewQSocket (void)
110 if (net_freeSockets == NULL)
113 if (net_activeconnections >= svs.maxclients)
116 // get one from free list
117 sock = net_freeSockets;
118 net_freeSockets = sock->next;
120 // add it to active list
121 sock->next = net_activeSockets;
122 net_activeSockets = sock;
124 sock->disconnected = false;
125 sock->connecttime = net_time;
126 strcpy (sock->address,"UNSET ADDRESS");
127 sock->driver = net_driverlevel;
129 sock->driverdata = NULL;
130 sock->canSend = true;
131 sock->sendNext = false;
132 sock->lastMessageTime = net_time;
133 sock->ackSequence = 0;
134 sock->sendSequence = 0;
135 sock->unreliableSendSequence = 0;
136 sock->sendMessageLength = 0;
137 sock->receiveSequence = 0;
138 sock->unreliableReceiveSequence = 0;
139 sock->receiveMessageLength = 0;
145 void NET_FreeQSocket(qsocket_t *sock)
149 // remove it from active list
150 if (sock == net_activeSockets)
151 net_activeSockets = net_activeSockets->next;
154 for (s = net_activeSockets; s; s = s->next)
157 s->next = sock->next;
161 Sys_Error ("NET_FreeQSocket: not active\n");
164 // add it to free list
165 sock->next = net_freeSockets;
166 net_freeSockets = sock;
167 sock->disconnected = true;
171 static void NET_Listen_f (void)
173 if (Cmd_Argc () != 2)
175 Con_Printf ("\"listen\" is \"%u\"\n", listening ? 1 : 0);
179 listening = atoi(Cmd_Argv(1)) ? true : false;
181 for (net_driverlevel=0 ; net_driverlevel<net_numdrivers; net_driverlevel++)
183 if (net_drivers[net_driverlevel].initialized == false)
185 dfunc.Listen (listening);
190 static void MaxPlayers_f (void)
194 if (Cmd_Argc () != 2)
196 Con_Printf ("\"maxplayers\" is \"%u\"\n", svs.maxclients);
202 Con_Printf ("maxplayers can not be changed while a server is running.\n");
206 n = atoi(Cmd_Argv(1));
209 if (n > svs.maxclientslimit)
211 n = svs.maxclientslimit;
212 Con_Printf ("\"maxplayers\" set to \"%u\"\n", n);
215 if ((n == 1) && listening)
216 Cbuf_AddText ("listen 0\n");
218 if ((n > 1) && (!listening))
219 Cbuf_AddText ("listen 1\n");
222 // LordHavoc: resetting deathmatch and coop was silly
225 Cvar_Set ("deathmatch", "0");
227 Cvar_Set ("deathmatch", "1");
232 static void NET_Port_f (void)
236 if (Cmd_Argc () != 2)
238 Con_Printf ("\"port\" is \"%u\"\n", net_hostport);
242 n = atoi(Cmd_Argv(1));
243 if (n < 1 || n > 65534)
245 Con_Printf ("Bad value, must be between 1 and 65534\n");
249 DEFAULTnet_hostport = n;
254 // force a change to the new port
255 Cbuf_AddText ("listen 0\n");
256 Cbuf_AddText ("listen 1\n");
261 static void PrintSlistHeader(void)
263 Con_Printf("Server Map Users\n");
264 Con_Printf("--------------- --------------- -----\n");
269 static void PrintSlist(void)
273 for (n = slistLastShown; n < hostCacheCount; n++)
275 if (hostcache[n].maxusers)
276 Con_Printf("%-15.15s %-15.15s %2u/%2u\n", hostcache[n].name, hostcache[n].map, hostcache[n].users, hostcache[n].maxusers);
278 Con_Printf("%-15.15s %-15.15s\n", hostcache[n].name, hostcache[n].map);
284 static void PrintSlistTrailer(void)
287 Con_Printf("== end list ==\n\n");
289 Con_Printf("No Quake servers found.\n\n");
293 void NET_Slist_f (void)
300 Con_Printf("Looking for Quake servers...\n");
304 slistInProgress = true;
305 slistStartTime = Sys_FloatTime();
307 SchedulePollProcedure(&slistSendProcedure, 0.0);
308 SchedulePollProcedure(&slistPollProcedure, 0.1);
314 static void Slist_Send(void)
316 for (net_driverlevel=0; net_driverlevel < net_numdrivers; net_driverlevel++)
318 if (!slistLocal && net_driverlevel == 0)
320 if (net_drivers[net_driverlevel].initialized == false)
322 dfunc.SearchForHosts (true);
325 if ((Sys_FloatTime() - slistStartTime) < 0.5)
326 SchedulePollProcedure(&slistSendProcedure, 0.75);
330 static void Slist_Poll(void)
332 for (net_driverlevel=0; net_driverlevel < net_numdrivers; net_driverlevel++)
334 if (!slistLocal && net_driverlevel == 0)
336 if (net_drivers[net_driverlevel].initialized == false)
338 dfunc.SearchForHosts (false);
344 if ((Sys_FloatTime() - slistStartTime) < 1.5)
346 SchedulePollProcedure(&slistPollProcedure, 0.1);
352 slistInProgress = false;
364 int hostCacheCount = 0;
365 hostcache_t hostcache[HOSTCACHESIZE];
367 qsocket_t *NET_Connect (char *host)
371 int numdrivers = net_numdrivers;
375 if (host && *host == 0)
380 if (Q_strcasecmp (host, "local") == 0)
388 for (n = 0; n < hostCacheCount; n++)
389 if (Q_strcasecmp (host, hostcache[n].name) == 0)
391 host = hostcache[n].cname;
394 if (n < hostCacheCount)
399 slistSilent = host ? true : false;
402 while(slistInProgress)
407 if (hostCacheCount != 1)
409 host = hostcache[0].cname;
410 Con_Printf("Connecting to...\n%s @ %s\n\n", hostcache[0].name, host);
414 for (n = 0; n < hostCacheCount; n++)
415 if (Q_strcasecmp (host, hostcache[n].name) == 0)
417 host = hostcache[n].cname;
422 for (net_driverlevel=0 ; net_driverlevel<numdrivers; net_driverlevel++)
424 if (net_drivers[net_driverlevel].initialized == false)
426 ret = dfunc.Connect (host);
445 NET_CheckNewConnections
456 qsocket_t *NET_CheckNewConnections (void)
462 for (net_driverlevel=0 ; net_driverlevel<net_numdrivers; net_driverlevel++)
464 if (net_drivers[net_driverlevel].initialized == false)
466 if (net_driverlevel && listening == false)
468 ret = dfunc.CheckNewConnections ();
473 vcrConnect.time = host_time;
474 vcrConnect.op = VCR_OP_CONNECT;
475 vcrConnect.session = (long)ret;
476 Sys_FileWrite (vcrFile, &vcrConnect, sizeof(vcrConnect));
477 Sys_FileWrite (vcrFile, ret->address, NET_NAMELEN);
485 vcrConnect.time = host_time;
486 vcrConnect.op = VCR_OP_CONNECT;
487 vcrConnect.session = 0;
488 Sys_FileWrite (vcrFile, &vcrConnect, sizeof(vcrConnect));
499 void NET_Close (qsocket_t *sock)
504 if (sock->disconnected)
509 // call the driver_Close function
512 NET_FreeQSocket(sock);
520 If there is a complete message, return it in net_message
522 returns 0 if no data is waiting
523 returns 1 if a message was received
524 returns -1 if connection is invalid
537 extern void PrintStats(qsocket_t *s);
539 int NET_GetMessage (qsocket_t *sock)
546 if (sock->disconnected)
548 Con_Printf("NET_GetMessage: disconnected socket\n");
554 ret = sfunc.QGetMessage(sock);
556 // see if this connection has timed out
557 if (ret == 0 && sock->driver)
559 if (net_time - sock->lastMessageTime > net_messagetimeout.value)
571 sock->lastMessageTime = net_time;
575 unreliableMessagesReceived++;
580 vcrGetMessage.time = host_time;
581 vcrGetMessage.op = VCR_OP_GETMESSAGE;
582 vcrGetMessage.session = (long)sock;
583 vcrGetMessage.ret = ret;
584 vcrGetMessage.len = net_message.cursize;
585 Sys_FileWrite (vcrFile, &vcrGetMessage, 24);
586 Sys_FileWrite (vcrFile, net_message.data, net_message.cursize);
593 vcrGetMessage.time = host_time;
594 vcrGetMessage.op = VCR_OP_GETMESSAGE;
595 vcrGetMessage.session = (long)sock;
596 vcrGetMessage.ret = ret;
597 Sys_FileWrite (vcrFile, &vcrGetMessage, 20);
609 Try to send a complete length+message unit over the reliable stream.
610 returns 0 if the message cannot be delivered reliably, but the connection
611 is still considered valid
612 returns 1 if the message was sent properly
613 returns -1 if the connection died
624 int NET_SendMessage (qsocket_t *sock, sizebuf_t *data)
631 if (sock->disconnected)
633 Con_Printf("NET_SendMessage: disconnected socket\n");
638 r = sfunc.QSendMessage(sock, data);
639 if (r == 1 && sock->driver)
644 vcrSendMessage.time = host_time;
645 vcrSendMessage.op = VCR_OP_SENDMESSAGE;
646 vcrSendMessage.session = (long)sock;
647 vcrSendMessage.r = r;
648 Sys_FileWrite (vcrFile, &vcrSendMessage, 20);
655 int NET_SendUnreliableMessage (qsocket_t *sock, sizebuf_t *data)
662 if (sock->disconnected)
664 Con_Printf("NET_SendMessage: disconnected socket\n");
669 r = sfunc.SendUnreliableMessage(sock, data);
670 if (r == 1 && sock->driver)
671 unreliableMessagesSent++;
675 vcrSendMessage.time = host_time;
676 vcrSendMessage.op = VCR_OP_SENDMESSAGE;
677 vcrSendMessage.session = (long)sock;
678 vcrSendMessage.r = r;
679 Sys_FileWrite (vcrFile, &vcrSendMessage, 20);
690 Returns true or false if the given qsocket can currently accept a
691 message to be transmitted.
694 qboolean NET_CanSendMessage (qsocket_t *sock)
701 if (sock->disconnected)
706 r = sfunc.CanSendMessage(sock);
710 vcrSendMessage.time = host_time;
711 vcrSendMessage.op = VCR_OP_CANSENDMESSAGE;
712 vcrSendMessage.session = (long)sock;
713 vcrSendMessage.r = r;
714 Sys_FileWrite (vcrFile, &vcrSendMessage, 20);
721 int NET_SendToAll(sizebuf_t *data, int blocktime)
726 qboolean state1 [MAX_SCOREBOARD];
727 qboolean state2 [MAX_SCOREBOARD];
729 for (i=0, host_client = svs.clients ; i<svs.maxclients ; i++, host_client++)
731 if (!host_client->netconnection)
733 if (host_client->active)
735 if (host_client->netconnection->driver == 0)
737 NET_SendMessage(host_client->netconnection, data);
753 start = Sys_FloatTime();
757 for (i=0, host_client = svs.clients ; i<svs.maxclients ; i++, host_client++)
761 if (NET_CanSendMessage (host_client->netconnection))
764 NET_SendMessage(host_client->netconnection, data);
768 NET_GetMessage (host_client->netconnection);
776 if (NET_CanSendMessage (host_client->netconnection))
782 NET_GetMessage (host_client->netconnection);
788 if ((Sys_FloatTime() - start) > blocktime)
795 //=============================================================================
809 if (COM_CheckParm("-playback"))
812 net_drivers[0].Init = VCR_Init;
815 if (COM_CheckParm("-record"))
818 i = COM_CheckParm ("-port");
820 i = COM_CheckParm ("-udpport");
822 i = COM_CheckParm ("-ipxport");
827 DEFAULTnet_hostport = atoi (com_argv[i+1]);
829 Sys_Error ("NET_Init: you must specify a number after -port");
831 net_hostport = DEFAULTnet_hostport;
833 if (COM_CheckParm("-listen") || cls.state == ca_dedicated)
835 net_numsockets = svs.maxclientslimit;
836 if (cls.state != ca_dedicated)
841 for (i = 0; i < net_numsockets; i++)
843 s = (qsocket_t *)Hunk_AllocName(sizeof(qsocket_t), "qsocket");
844 s->next = net_freeSockets;
846 s->disconnected = true;
849 // allocate space for network message buffer
850 SZ_Alloc (&net_message, NET_MAXMESSAGE);
852 Cvar_RegisterVariable (&net_messagetimeout);
853 Cvar_RegisterVariable (&hostname);
854 Cvar_RegisterVariable (&config_com_port);
855 Cvar_RegisterVariable (&config_com_irq);
856 Cvar_RegisterVariable (&config_com_baud);
857 Cvar_RegisterVariable (&config_com_modem);
858 Cvar_RegisterVariable (&config_modem_dialtype);
859 Cvar_RegisterVariable (&config_modem_clear);
860 Cvar_RegisterVariable (&config_modem_init);
861 Cvar_RegisterVariable (&config_modem_hangup);
863 Cmd_AddCommand ("slist", NET_Slist_f);
864 Cmd_AddCommand ("listen", NET_Listen_f);
865 Cmd_AddCommand ("maxplayers", MaxPlayers_f);
866 Cmd_AddCommand ("port", NET_Port_f);
868 // initialize all the drivers
869 for (net_driverlevel=0 ; net_driverlevel<net_numdrivers ; net_driverlevel++)
871 controlSocket = net_drivers[net_driverlevel].Init();
872 if (controlSocket == -1)
874 net_drivers[net_driverlevel].initialized = true;
875 net_drivers[net_driverlevel].controlSock = controlSocket;
877 net_drivers[net_driverlevel].Listen (true);
881 Con_DPrintf("IPX address %s\n", my_ipx_address);
882 if (*my_tcpip_address)
883 Con_DPrintf("TCP/IP address %s\n", my_tcpip_address);
892 void NET_Shutdown (void)
898 for (sock = net_activeSockets; sock; sock = sock->next)
902 // shutdown the drivers
904 for (net_driverlevel = 0; net_driverlevel < net_numdrivers; net_driverlevel++)
906 if (net_drivers[net_driverlevel].initialized == true)
908 net_drivers[net_driverlevel].Shutdown ();
909 net_drivers[net_driverlevel].initialized = false;
915 Con_Printf ("Closing vcrfile.\n");
916 Sys_FileClose(vcrFile);
921 static PollProcedure *pollProcedureList = NULL;
932 if (config_com_modem.value == 1.0)
936 SetComPortConfig (0, (int)config_com_port.value, (int)config_com_irq.value, (int)config_com_baud.value, useModem);
937 SetModemConfig (0, config_modem_dialtype.string, config_modem_clear.string, config_modem_init.string, config_modem_hangup.string);
939 configRestored = true;
944 for (pp = pollProcedureList; pp; pp = pp->next)
946 if (pp->nextTime > net_time)
948 pollProcedureList = pp->next;
949 pp->procedure(pp->arg);
954 void SchedulePollProcedure(PollProcedure *proc, double timeOffset)
956 PollProcedure *pp, *prev;
958 proc->nextTime = Sys_FloatTime() + timeOffset;
959 for (pp = pollProcedureList, prev = NULL; pp; pp = pp->next)
961 if (pp->nextTime >= proc->nextTime)
968 proc->next = pollProcedureList;
969 pollProcedureList = proc;