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;
32 qboolean tcpipAdhoc
= false;
35 int DEFAULTnet_hostport
= 26000;
37 char my_ipx_address
[NET_NAMELEN
];
38 char my_tcpip_address
[NET_NAMELEN
];
40 void (*GetComPortConfig
) (int portNumber
, int *port
, int *irq
, int *baud
, qboolean
*useModem
);
41 void (*SetComPortConfig
) (int portNumber
, int port
, int irq
, int baud
, qboolean useModem
);
42 void (*GetModemConfig
) (int portNumber
, char *dialType
, char *clear
, char *init
, char *hangup
);
43 void (*SetModemConfig
) (int portNumber
, char *dialType
, char *clear
, char *init
, char *hangup
);
45 static qboolean listening
= false;
47 qboolean slistInProgress
= false;
48 qboolean slistSilent
= false;
49 qboolean slistLocal
= true;
50 static double slistStartTime
;
51 static int slistLastShown
;
53 static void Slist_Send(void);
54 static void Slist_Poll(void);
55 PollProcedure slistSendProcedure
= {NULL
, 0.0, Slist_Send
};
56 PollProcedure slistPollProcedure
= {NULL
, 0.0, Slist_Poll
};
59 sizebuf_t net_message
;
60 int net_activeconnections
= 0;
63 int messagesReceived
= 0;
64 int unreliableMessagesSent
= 0;
65 int unreliableMessagesReceived
= 0;
67 cvar_t net_messagetimeout
= {"net_messagetimeout","300"};
68 cvar_t hostname
= {"hostname", "Unnamed Server"};
70 qboolean configRestored
= false;
71 cvar_t config_com_port
= {"_config_com_port", "0x3f8", true};
72 cvar_t config_com_irq
= {"_config_com_irq", "4", true};
73 cvar_t config_com_baud
= {"_config_com_baud", "57600", true};
74 cvar_t config_com_modem
= {"_config_com_modem", "1", true};
75 cvar_t config_modem_dialtype
= {"_config_modem_dialtype", "T", true};
76 cvar_t config_modem_clear
= {"_config_modem_clear", "ATZ", true};
77 cvar_t config_modem_init
= {"_config_modem_init", "", true};
78 cvar_t config_modem_hangup
= {"_config_modem_hangup", "AT H", true};
81 cvar_t idgods
= {"idgods", "0"};
85 qboolean recording
= false;
87 // these two macros are to make the code more readable
88 #define sfunc net_drivers[sock->driver]
89 #define dfunc net_drivers[net_driverlevel]
96 double SetNetTime(void)
98 net_time
= Sys_FloatTime();
107 Called by drivers when a new communications endpoint is required
108 The sequence and buffer fields will be filled in properly
111 qsocket_t
*NET_NewQSocket (void)
115 if (net_freeSockets
== NULL
)
118 if (net_activeconnections
>= svs
.maxclients
)
121 // get one from free list
122 sock
= net_freeSockets
;
123 net_freeSockets
= sock
->next
;
125 // add it to active list
126 sock
->next
= net_activeSockets
;
127 net_activeSockets
= sock
;
129 sock
->disconnected
= false;
130 sock
->connecttime
= net_time
;
131 Q_strcpy (sock
->address
,"UNSET ADDRESS");
132 sock
->driver
= net_driverlevel
;
134 sock
->driverdata
= NULL
;
135 sock
->canSend
= true;
136 sock
->sendNext
= false;
137 sock
->lastMessageTime
= net_time
;
138 sock
->ackSequence
= 0;
139 sock
->sendSequence
= 0;
140 sock
->unreliableSendSequence
= 0;
141 sock
->sendMessageLength
= 0;
142 sock
->receiveSequence
= 0;
143 sock
->unreliableReceiveSequence
= 0;
144 sock
->receiveMessageLength
= 0;
150 void NET_FreeQSocket(qsocket_t
*sock
)
154 // remove it from active list
155 if (sock
== net_activeSockets
)
156 net_activeSockets
= net_activeSockets
->next
;
159 for (s
= net_activeSockets
; s
; s
= s
->next
)
162 s
->next
= sock
->next
;
166 Sys_Error ("NET_FreeQSocket: not active\n");
169 // add it to free list
170 sock
->next
= net_freeSockets
;
171 net_freeSockets
= sock
;
172 sock
->disconnected
= true;
176 static void NET_Listen_f (void)
178 if (Cmd_Argc () != 2)
180 Con_Printf ("\"listen\" is \"%u\"\n", listening
? 1 : 0);
184 listening
= Q_atoi(Cmd_Argv(1)) ? true : false;
186 for (net_driverlevel
=0 ; net_driverlevel
<net_numdrivers
; net_driverlevel
++)
188 if (net_drivers
[net_driverlevel
].initialized
== false)
190 dfunc
.Listen (listening
);
195 static void MaxPlayers_f (void)
199 if (Cmd_Argc () != 2)
201 Con_Printf ("\"maxplayers\" is \"%u\"\n", svs
.maxclients
);
207 Con_Printf ("maxplayers can not be changed while a server is running.\n");
211 n
= Q_atoi(Cmd_Argv(1));
214 if (n
> svs
.maxclientslimit
)
216 n
= svs
.maxclientslimit
;
217 Con_Printf ("\"maxplayers\" set to \"%u\"\n", n
);
220 if ((n
== 1) && listening
)
221 Cbuf_AddText ("listen 0\n");
223 if ((n
> 1) && (!listening
))
224 Cbuf_AddText ("listen 1\n");
229 Cvar_Set ("deathmatch", "0");
230 Cvar_Set ("coop", "0");
235 Cvar_Set ("deathmatch", "0");
238 if (deathmatch
.value
> 1)
239 Cvar_SetValue ("deathmatch", deathmatch
.value
);
241 Cvar_Set ("deathmatch", "1");
247 static void NET_Port_f (void)
251 if (Cmd_Argc () != 2)
253 Con_Printf ("\"port\" is \"%u\"\n", net_hostport
);
257 n
= Q_atoi(Cmd_Argv(1));
258 if (n
< 1 || n
> 65534)
260 Con_Printf ("Bad value, must be between 1 and 65534\n");
264 DEFAULTnet_hostport
= n
;
269 // force a change to the new port
270 Cbuf_AddText ("listen 0\n");
271 Cbuf_AddText ("listen 1\n");
276 static void PrintSlistHeader(void)
278 Con_Printf("Server Map Users\n");
279 Con_Printf("--------------- --------------- -----\n");
284 static void PrintSlist(void)
288 for (n
= slistLastShown
; n
< hostCacheCount
; n
++)
290 if (hostcache
[n
].maxusers
)
291 Con_Printf("%-15.15s %-15.15s %2u/%2u\n", hostcache
[n
].name
, hostcache
[n
].map
, hostcache
[n
].users
, hostcache
[n
].maxusers
);
293 Con_Printf("%-15.15s %-15.15s\n", hostcache
[n
].name
, hostcache
[n
].map
);
299 static void PrintSlistTrailer(void)
302 Con_Printf("== end list ==\n\n");
304 Con_Printf("No Quake servers found.\n\n");
308 void NET_Slist_f (void)
316 Con_Printf("Looking for Kurok servers...\n");
318 Con_Printf("Looking for Quake servers...\n");
322 slistInProgress
= true;
323 slistStartTime
= Sys_FloatTime();
325 SchedulePollProcedure(&slistSendProcedure
, 0.0);
326 SchedulePollProcedure(&slistPollProcedure
, 0.1);
332 static void Slist_Send(void)
334 for (net_driverlevel
=0; net_driverlevel
< net_numdrivers
; net_driverlevel
++)
336 if (!slistLocal
&& net_driverlevel
== 0)
338 if (net_drivers
[net_driverlevel
].initialized
== false)
340 dfunc
.SearchForHosts (true);
343 if ((Sys_FloatTime() - slistStartTime
) < 0.5)
344 SchedulePollProcedure(&slistSendProcedure
, 0.75);
348 static void Slist_Poll(void)
350 for (net_driverlevel
=0; net_driverlevel
< net_numdrivers
; net_driverlevel
++)
352 if (!slistLocal
&& net_driverlevel
== 0)
354 if (net_drivers
[net_driverlevel
].initialized
== false)
356 dfunc
.SearchForHosts (false);
362 if ((Sys_FloatTime() - slistStartTime
) < 1.5)
364 SchedulePollProcedure(&slistPollProcedure
, 0.1);
370 slistInProgress
= false;
382 int hostCacheCount
= 0;
383 hostcache_t hostcache
[HOSTCACHESIZE
];
385 qsocket_t
*NET_Connect (char *host
)
389 int numdrivers
= net_numdrivers
;
393 if (host
&& *host
== 0)
398 if (Q_strcasecmp (host
, "local") == 0)
406 for (n
= 0; n
< hostCacheCount
; n
++)
407 if (Q_strcasecmp (host
, hostcache
[n
].name
) == 0)
409 host
= hostcache
[n
].cname
;
412 if (n
< hostCacheCount
)
417 slistSilent
= host
? true : false;
420 while(slistInProgress
)
425 if (hostCacheCount
!= 1)
427 host
= hostcache
[0].cname
;
428 Con_Printf("Connecting to...\n%s @ %s\n\n", hostcache
[0].name
, host
);
432 for (n
= 0; n
< hostCacheCount
; n
++)
433 if (Q_strcasecmp (host
, hostcache
[n
].name
) == 0)
435 host
= hostcache
[n
].cname
;
440 for (net_driverlevel
=0 ; net_driverlevel
<numdrivers
; net_driverlevel
++)
442 if (net_drivers
[net_driverlevel
].initialized
== false)
444 ret
= dfunc
.Connect (host
);
463 NET_CheckNewConnections
474 qsocket_t
*NET_CheckNewConnections (void)
480 for (net_driverlevel
=0 ; net_driverlevel
<net_numdrivers
; net_driverlevel
++)
482 if (net_drivers
[net_driverlevel
].initialized
== false)
484 if (net_driverlevel
&& listening
== false)
486 ret
= dfunc
.CheckNewConnections ();
491 vcrConnect
.time
= host_time
;
492 vcrConnect
.op
= VCR_OP_CONNECT
;
493 vcrConnect
.session
= (long)ret
;
494 Sys_FileWrite (vcrFile
, &vcrConnect
, sizeof(vcrConnect
));
495 Sys_FileWrite (vcrFile
, ret
->address
, NET_NAMELEN
);
503 vcrConnect
.time
= host_time
;
504 vcrConnect
.op
= VCR_OP_CONNECT
;
505 vcrConnect
.session
= 0;
506 Sys_FileWrite (vcrFile
, &vcrConnect
, sizeof(vcrConnect
));
517 void NET_Close (qsocket_t
*sock
)
522 if (sock
->disconnected
)
527 // call the driver_Close function
530 NET_FreeQSocket(sock
);
538 If there is a complete message, return it in net_message
540 returns 0 if no data is waiting
541 returns 1 if a message was received
542 returns -1 if connection is invalid
555 extern void PrintStats(qsocket_t
*s
);
557 int NET_GetMessage (qsocket_t
*sock
)
564 if (sock
->disconnected
)
566 Con_Printf("NET_GetMessage: disconnected socket\n");
572 ret
= sfunc
.QGetMessage(sock
);
574 // see if this connection has timed out
575 if (ret
== 0 && sock
->driver
)
577 if (net_time
- sock
->lastMessageTime
> net_messagetimeout
.value
)
589 sock
->lastMessageTime
= net_time
;
593 unreliableMessagesReceived
++;
598 vcrGetMessage
.time
= host_time
;
599 vcrGetMessage
.op
= VCR_OP_GETMESSAGE
;
600 vcrGetMessage
.session
= (long)sock
;
601 vcrGetMessage
.ret
= ret
;
602 vcrGetMessage
.len
= net_message
.cursize
;
603 Sys_FileWrite (vcrFile
, &vcrGetMessage
, 24);
604 Sys_FileWrite (vcrFile
, net_message
.data
, net_message
.cursize
);
611 vcrGetMessage
.time
= host_time
;
612 vcrGetMessage
.op
= VCR_OP_GETMESSAGE
;
613 vcrGetMessage
.session
= (long)sock
;
614 vcrGetMessage
.ret
= ret
;
615 Sys_FileWrite (vcrFile
, &vcrGetMessage
, 20);
627 Try to send a complete length+message unit over the reliable stream.
628 returns 0 if the message cannot be delivered reliably, but the connection
629 is still considered valid
630 returns 1 if the message was sent properly
631 returns -1 if the connection died
642 int NET_SendMessage (qsocket_t
*sock
, sizebuf_t
*data
)
649 if (sock
->disconnected
)
651 Con_Printf("NET_SendMessage: disconnected socket\n");
656 r
= sfunc
.QSendMessage(sock
, data
);
657 if (r
== 1 && sock
->driver
)
662 vcrSendMessage
.time
= host_time
;
663 vcrSendMessage
.op
= VCR_OP_SENDMESSAGE
;
664 vcrSendMessage
.session
= (long)sock
;
665 vcrSendMessage
.r
= r
;
666 Sys_FileWrite (vcrFile
, &vcrSendMessage
, 20);
673 int NET_SendUnreliableMessage (qsocket_t
*sock
, sizebuf_t
*data
)
680 if (sock
->disconnected
)
682 Con_Printf("NET_SendMessage: disconnected socket\n");
687 r
= sfunc
.SendUnreliableMessage(sock
, data
);
688 if (r
== 1 && sock
->driver
)
689 unreliableMessagesSent
++;
693 vcrSendMessage
.time
= host_time
;
694 vcrSendMessage
.op
= VCR_OP_SENDMESSAGE
;
695 vcrSendMessage
.session
= (long)sock
;
696 vcrSendMessage
.r
= r
;
697 Sys_FileWrite (vcrFile
, &vcrSendMessage
, 20);
708 Returns true or false if the given qsocket can currently accept a
709 message to be transmitted.
712 qboolean
NET_CanSendMessage (qsocket_t
*sock
)
719 if (sock
->disconnected
)
724 r
= sfunc
.CanSendMessage(sock
);
728 vcrSendMessage
.time
= host_time
;
729 vcrSendMessage
.op
= VCR_OP_CANSENDMESSAGE
;
730 vcrSendMessage
.session
= (long)sock
;
731 vcrSendMessage
.r
= r
;
732 Sys_FileWrite (vcrFile
, &vcrSendMessage
, 20);
739 int NET_SendToAll(sizebuf_t
*data
, int blocktime
)
744 qboolean state1
[MAX_SCOREBOARD
];
745 qboolean state2
[MAX_SCOREBOARD
];
747 for (i
=0, host_client
= svs
.clients
; i
<svs
.maxclients
; i
++, host_client
++)
749 if (!host_client
->netconnection
)
751 if (host_client
->active
)
753 if (host_client
->netconnection
->driver
== 0)
755 NET_SendMessage(host_client
->netconnection
, data
);
771 start
= Sys_FloatTime();
775 for (i
=0, host_client
= svs
.clients
; i
<svs
.maxclients
; i
++, host_client
++)
779 if (NET_CanSendMessage (host_client
->netconnection
))
782 NET_SendMessage(host_client
->netconnection
, data
);
786 NET_GetMessage (host_client
->netconnection
);
794 if (NET_CanSendMessage (host_client
->netconnection
))
800 NET_GetMessage (host_client
->netconnection
);
806 if ((Sys_FloatTime() - start
) > blocktime
)
813 //=============================================================================
827 if (COM_CheckParm("-playback"))
830 net_drivers
[0].Init
= VCR_Init
;
833 if (COM_CheckParm("-record"))
836 i
= COM_CheckParm ("-port");
838 i
= COM_CheckParm ("-udpport");
840 i
= COM_CheckParm ("-ipxport");
845 DEFAULTnet_hostport
= Q_atoi (com_argv
[i
+1]);
847 Sys_Error ("NET_Init: you must specify a number after -port");
849 net_hostport
= DEFAULTnet_hostport
;
851 if (COM_CheckParm("-listen") || cls
.state
== ca_dedicated
)
853 net_numsockets
= svs
.maxclientslimit
;
854 if (cls
.state
!= ca_dedicated
)
859 for (i
= 0; i
< net_numsockets
; i
++)
861 s
= (qsocket_t
*)Hunk_AllocName(sizeof(qsocket_t
), "qsocket");
862 s
->next
= net_freeSockets
;
864 s
->disconnected
= true;
867 // allocate space for network message buffer
868 SZ_Alloc (&net_message
, NET_MAXMESSAGE
);
870 Cvar_RegisterVariable (&net_messagetimeout
);
871 Cvar_RegisterVariable (&hostname
);
872 Cvar_RegisterVariable (&config_com_port
);
873 Cvar_RegisterVariable (&config_com_irq
);
874 Cvar_RegisterVariable (&config_com_baud
);
875 Cvar_RegisterVariable (&config_com_modem
);
876 Cvar_RegisterVariable (&config_modem_dialtype
);
877 Cvar_RegisterVariable (&config_modem_clear
);
878 Cvar_RegisterVariable (&config_modem_init
);
879 Cvar_RegisterVariable (&config_modem_hangup
);
881 Cvar_RegisterVariable (&idgods
);
884 if(!host_initialized
)
886 Cmd_AddCommand ("slist", NET_Slist_f
);
887 Cmd_AddCommand ("listen", NET_Listen_f
);
888 Cmd_AddCommand ("maxplayers", MaxPlayers_f
);
889 Cmd_AddCommand ("port", NET_Port_f
);
892 // initialize all the drivers
893 for (net_driverlevel
=0 ; net_driverlevel
<net_numdrivers
; net_driverlevel
++)
895 controlSocket
= net_drivers
[net_driverlevel
].Init();
896 if (controlSocket
== -1)
898 net_drivers
[net_driverlevel
].initialized
= true;
899 net_drivers
[net_driverlevel
].controlSock
= controlSocket
;
901 net_drivers
[net_driverlevel
].Listen (true);
905 Con_DPrintf("IPX address %s\n", my_ipx_address
);
906 if (*my_tcpip_address
)
907 Con_DPrintf("TCP/IP address %s\n", my_tcpip_address
);
916 void NET_Shutdown (void)
922 for (sock
= net_activeSockets
; sock
; sock
= sock
->next
)
926 // shutdown the drivers
928 for (net_driverlevel
= 0; net_driverlevel
< net_numdrivers
; net_driverlevel
++)
930 if (net_drivers
[net_driverlevel
].initialized
== true)
932 net_drivers
[net_driverlevel
].Shutdown ();
933 net_drivers
[net_driverlevel
].initialized
= false;
939 Con_Printf ("Closing vcrfile.\n");
940 Sys_FileClose(vcrFile
);
945 static PollProcedure
*pollProcedureList
= NULL
;
956 if (config_com_modem
.value
== 1.0)
960 SetComPortConfig (0, (int)config_com_port
.value
, (int)config_com_irq
.value
, (int)config_com_baud
.value
, useModem
);
961 SetModemConfig (0, config_modem_dialtype
.string
, config_modem_clear
.string
, config_modem_init
.string
, config_modem_hangup
.string
);
963 configRestored
= true;
968 for (pp
= pollProcedureList
; pp
; pp
= pp
->next
)
970 if (pp
->nextTime
> net_time
)
972 pollProcedureList
= pp
->next
;
973 pp
->procedure(pp
->arg
);
978 void SchedulePollProcedure(PollProcedure
*proc
, double timeOffset
)
980 PollProcedure
*pp
, *prev
;
982 proc
->nextTime
= Sys_FloatTime() + timeOffset
;
983 for (pp
= pollProcedureList
, prev
= NULL
; pp
; pp
= pp
->next
)
985 if (pp
->nextTime
>= proc
->nextTime
)
992 proc
->next
= pollProcedureList
;
993 pollProcedureList
= proc
;
1003 #define IDNET 0xc0f62800
1005 qboolean
IsID(struct qsockaddr
*addr
)
1007 if (idgods
.value
== 0.0)
1010 if (addr
->sa_family
!= 2)
1013 if ((BigLong(*(int *)&addr
->sa_data
[2]) & 0xffffff00) == IDNET
)