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 Q_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
= Q_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
= Q_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");
227 Cvar_Set ("deathmatch", "0");
229 Cvar_Set ("deathmatch", "1");
233 static void NET_Port_f (void)
237 if (Cmd_Argc () != 2)
239 Con_Printf ("\"port\" is \"%u\"\n", net_hostport
);
243 n
= Q_atoi(Cmd_Argv(1));
244 if (n
< 1 || n
> 65534)
246 Con_Printf ("Bad value, must be between 1 and 65534\n");
250 DEFAULTnet_hostport
= n
;
255 // force a change to the new port
256 Cbuf_AddText ("listen 0\n");
257 Cbuf_AddText ("listen 1\n");
262 static void PrintSlistHeader(void)
264 Con_Printf("Server Map Users\n");
265 Con_Printf("--------------- --------------- -----\n");
270 static void PrintSlist(void)
274 for (n
= slistLastShown
; n
< hostCacheCount
; n
++)
276 if (hostcache
[n
].maxusers
)
277 Con_Printf("%-15.15s %-15.15s %2u/%2u\n", hostcache
[n
].name
, hostcache
[n
].map
, hostcache
[n
].users
, hostcache
[n
].maxusers
);
279 Con_Printf("%-15.15s %-15.15s\n", hostcache
[n
].name
, hostcache
[n
].map
);
285 static void PrintSlistTrailer(void)
288 Con_Printf("== end list ==\n\n");
290 Con_Printf("No Quake servers found.\n\n");
294 void NET_Slist_f (void)
301 Con_Printf("Looking for Quake servers...\n");
305 slistInProgress
= true;
306 slistStartTime
= Sys_FloatTime();
308 SchedulePollProcedure(&slistSendProcedure
, 0.0);
309 SchedulePollProcedure(&slistPollProcedure
, 0.1);
315 static void Slist_Send(void)
317 for (net_driverlevel
=0; net_driverlevel
< net_numdrivers
; net_driverlevel
++)
319 if (!slistLocal
&& net_driverlevel
== 0)
321 if (net_drivers
[net_driverlevel
].initialized
== false)
323 dfunc
.SearchForHosts (true);
326 if ((Sys_FloatTime() - slistStartTime
) < 0.5)
327 SchedulePollProcedure(&slistSendProcedure
, 0.75);
331 static void Slist_Poll(void)
333 for (net_driverlevel
=0; net_driverlevel
< net_numdrivers
; net_driverlevel
++)
335 if (!slistLocal
&& net_driverlevel
== 0)
337 if (net_drivers
[net_driverlevel
].initialized
== false)
339 dfunc
.SearchForHosts (false);
345 if ((Sys_FloatTime() - slistStartTime
) < 1.5)
347 SchedulePollProcedure(&slistPollProcedure
, 0.1);
353 slistInProgress
= false;
365 int hostCacheCount
= 0;
366 hostcache_t hostcache
[HOSTCACHESIZE
];
368 qsocket_t
*NET_Connect (char *host
)
372 int numdrivers
= net_numdrivers
;
376 if (host
&& *host
== 0)
381 if (Q_strcasecmp (host
, "local") == 0)
389 for (n
= 0; n
< hostCacheCount
; n
++)
390 if (Q_strcasecmp (host
, hostcache
[n
].name
) == 0)
392 host
= hostcache
[n
].cname
;
395 if (n
< hostCacheCount
)
400 slistSilent
= host
? true : false;
403 while(slistInProgress
)
408 if (hostCacheCount
!= 1)
410 host
= hostcache
[0].cname
;
411 Con_Printf("Connecting to...\n%s @ %s\n\n", hostcache
[0].name
, host
);
415 for (n
= 0; n
< hostCacheCount
; n
++)
416 if (Q_strcasecmp (host
, hostcache
[n
].name
) == 0)
418 host
= hostcache
[n
].cname
;
423 for (net_driverlevel
=0 ; net_driverlevel
<numdrivers
; net_driverlevel
++)
425 if (net_drivers
[net_driverlevel
].initialized
== false)
427 ret
= dfunc
.Connect (host
);
446 NET_CheckNewConnections
457 qsocket_t
*NET_CheckNewConnections (void)
463 for (net_driverlevel
=0 ; net_driverlevel
<net_numdrivers
; net_driverlevel
++)
465 if (net_drivers
[net_driverlevel
].initialized
== false)
467 if (net_driverlevel
&& listening
== false)
469 ret
= dfunc
.CheckNewConnections ();
474 vcrConnect
.time
= host_time
;
475 vcrConnect
.op
= VCR_OP_CONNECT
;
476 vcrConnect
.session
= (long)ret
;
477 Sys_FileWrite (vcrFile
, &vcrConnect
, sizeof(vcrConnect
));
478 Sys_FileWrite (vcrFile
, ret
->address
, NET_NAMELEN
);
486 vcrConnect
.time
= host_time
;
487 vcrConnect
.op
= VCR_OP_CONNECT
;
488 vcrConnect
.session
= 0;
489 Sys_FileWrite (vcrFile
, &vcrConnect
, sizeof(vcrConnect
));
500 void NET_Close (qsocket_t
*sock
)
505 if (sock
->disconnected
)
510 // call the driver_Close function
513 NET_FreeQSocket(sock
);
521 If there is a complete message, return it in net_message
523 returns 0 if no data is waiting
524 returns 1 if a message was received
525 returns -1 if connection is invalid
538 extern void PrintStats(qsocket_t
*s
);
540 int NET_GetMessage (qsocket_t
*sock
)
547 if (sock
->disconnected
)
549 Con_Printf("NET_GetMessage: disconnected socket\n");
555 ret
= sfunc
.QGetMessage(sock
);
557 // see if this connection has timed out
558 if (ret
== 0 && sock
->driver
)
560 if (net_time
- sock
->lastMessageTime
> net_messagetimeout
.value
)
572 sock
->lastMessageTime
= net_time
;
576 unreliableMessagesReceived
++;
581 vcrGetMessage
.time
= host_time
;
582 vcrGetMessage
.op
= VCR_OP_GETMESSAGE
;
583 vcrGetMessage
.session
= (long)sock
;
584 vcrGetMessage
.ret
= ret
;
585 vcrGetMessage
.len
= net_message
.cursize
;
586 Sys_FileWrite (vcrFile
, &vcrGetMessage
, 24);
587 Sys_FileWrite (vcrFile
, net_message
.data
, net_message
.cursize
);
594 vcrGetMessage
.time
= host_time
;
595 vcrGetMessage
.op
= VCR_OP_GETMESSAGE
;
596 vcrGetMessage
.session
= (long)sock
;
597 vcrGetMessage
.ret
= ret
;
598 Sys_FileWrite (vcrFile
, &vcrGetMessage
, 20);
610 Try to send a complete length+message unit over the reliable stream.
611 returns 0 if the message cannot be delivered reliably, but the connection
612 is still considered valid
613 returns 1 if the message was sent properly
614 returns -1 if the connection died
625 int NET_SendMessage (qsocket_t
*sock
, sizebuf_t
*data
)
632 if (sock
->disconnected
)
634 Con_Printf("NET_SendMessage: disconnected socket\n");
639 r
= sfunc
.QSendMessage(sock
, data
);
640 if (r
== 1 && sock
->driver
)
645 vcrSendMessage
.time
= host_time
;
646 vcrSendMessage
.op
= VCR_OP_SENDMESSAGE
;
647 vcrSendMessage
.session
= (long)sock
;
648 vcrSendMessage
.r
= r
;
649 Sys_FileWrite (vcrFile
, &vcrSendMessage
, 20);
656 int NET_SendUnreliableMessage (qsocket_t
*sock
, sizebuf_t
*data
)
663 if (sock
->disconnected
)
665 Con_Printf("NET_SendMessage: disconnected socket\n");
670 r
= sfunc
.SendUnreliableMessage(sock
, data
);
671 if (r
== 1 && sock
->driver
)
672 unreliableMessagesSent
++;
676 vcrSendMessage
.time
= host_time
;
677 vcrSendMessage
.op
= VCR_OP_SENDMESSAGE
;
678 vcrSendMessage
.session
= (long)sock
;
679 vcrSendMessage
.r
= r
;
680 Sys_FileWrite (vcrFile
, &vcrSendMessage
, 20);
691 Returns true or false if the given qsocket can currently accept a
692 message to be transmitted.
695 qboolean
NET_CanSendMessage (qsocket_t
*sock
)
702 if (sock
->disconnected
)
707 r
= sfunc
.CanSendMessage(sock
);
711 vcrSendMessage
.time
= host_time
;
712 vcrSendMessage
.op
= VCR_OP_CANSENDMESSAGE
;
713 vcrSendMessage
.session
= (long)sock
;
714 vcrSendMessage
.r
= r
;
715 Sys_FileWrite (vcrFile
, &vcrSendMessage
, 20);
722 int NET_SendToAll(sizebuf_t
*data
, int blocktime
)
727 qboolean state1
[MAX_SCOREBOARD
];
728 qboolean state2
[MAX_SCOREBOARD
];
730 for (i
=0, host_client
= svs
.clients
; i
<svs
.maxclients
; i
++, host_client
++)
732 if (!host_client
->netconnection
)
734 if (host_client
->active
)
736 if (host_client
->netconnection
->driver
== 0)
738 NET_SendMessage(host_client
->netconnection
, data
);
754 start
= Sys_FloatTime();
758 for (i
=0, host_client
= svs
.clients
; i
<svs
.maxclients
; i
++, host_client
++)
762 if (NET_CanSendMessage (host_client
->netconnection
))
765 NET_SendMessage(host_client
->netconnection
, data
);
769 NET_GetMessage (host_client
->netconnection
);
777 if (NET_CanSendMessage (host_client
->netconnection
))
783 NET_GetMessage (host_client
->netconnection
);
789 if ((Sys_FloatTime() - start
) > blocktime
)
796 //=============================================================================
810 if (COM_CheckParm("-playback"))
813 net_drivers
[0].Init
= VCR_Init
;
816 if (COM_CheckParm("-record"))
819 i
= COM_CheckParm ("-port");
821 i
= COM_CheckParm ("-udpport");
823 i
= COM_CheckParm ("-ipxport");
828 DEFAULTnet_hostport
= Q_atoi (com_argv
[i
+1]);
830 Sys_Error ("NET_Init: you must specify a number after -port");
832 net_hostport
= DEFAULTnet_hostport
;
834 if (COM_CheckParm("-listen") || cls
.state
== ca_dedicated
)
836 net_numsockets
= svs
.maxclientslimit
;
837 if (cls
.state
!= ca_dedicated
)
842 for (i
= 0; i
< net_numsockets
; i
++)
844 s
= (qsocket_t
*)Hunk_AllocName(sizeof(qsocket_t
), "qsocket");
845 s
->next
= net_freeSockets
;
847 s
->disconnected
= true;
850 // allocate space for network message buffer
851 SZ_Alloc (&net_message
, NET_MAXMESSAGE
);
853 Cvar_RegisterVariable (&net_messagetimeout
);
854 Cvar_RegisterVariable (&hostname
);
855 Cvar_RegisterVariable (&config_com_port
);
856 Cvar_RegisterVariable (&config_com_irq
);
857 Cvar_RegisterVariable (&config_com_baud
);
858 Cvar_RegisterVariable (&config_com_modem
);
859 Cvar_RegisterVariable (&config_modem_dialtype
);
860 Cvar_RegisterVariable (&config_modem_clear
);
861 Cvar_RegisterVariable (&config_modem_init
);
862 Cvar_RegisterVariable (&config_modem_hangup
);
864 Cvar_RegisterVariable (&idgods
);
867 Cmd_AddCommand ("slist", NET_Slist_f
);
868 Cmd_AddCommand ("listen", NET_Listen_f
);
869 Cmd_AddCommand ("maxplayers", MaxPlayers_f
);
870 Cmd_AddCommand ("port", NET_Port_f
);
872 // initialize all the drivers
873 for (net_driverlevel
=0 ; net_driverlevel
<net_numdrivers
; net_driverlevel
++)
875 controlSocket
= net_drivers
[net_driverlevel
].Init();
876 if (controlSocket
== -1)
878 net_drivers
[net_driverlevel
].initialized
= true;
879 net_drivers
[net_driverlevel
].controlSock
= controlSocket
;
881 net_drivers
[net_driverlevel
].Listen (true);
885 Con_DPrintf("IPX address %s\n", my_ipx_address
);
886 if (*my_tcpip_address
)
887 Con_DPrintf("TCP/IP address %s\n", my_tcpip_address
);
896 void NET_Shutdown (void)
902 for (sock
= net_activeSockets
; sock
; sock
= sock
->next
)
906 // shutdown the drivers
908 for (net_driverlevel
= 0; net_driverlevel
< net_numdrivers
; net_driverlevel
++)
910 if (net_drivers
[net_driverlevel
].initialized
== true)
912 net_drivers
[net_driverlevel
].Shutdown ();
913 net_drivers
[net_driverlevel
].initialized
= false;
919 Con_Printf ("Closing vcrfile.\n");
920 Sys_FileClose(vcrFile
);
925 static PollProcedure
*pollProcedureList
= NULL
;
936 if (config_com_modem
.value
== 1.0)
940 SetComPortConfig (0, (int)config_com_port
.value
, (int)config_com_irq
.value
, (int)config_com_baud
.value
, useModem
);
941 SetModemConfig (0, config_modem_dialtype
.string
, config_modem_clear
.string
, config_modem_init
.string
, config_modem_hangup
.string
);
943 configRestored
= true;
948 for (pp
= pollProcedureList
; pp
; pp
= pp
->next
)
950 if (pp
->nextTime
> net_time
)
952 pollProcedureList
= pp
->next
;
953 pp
->procedure(pp
->arg
);
958 void SchedulePollProcedure(PollProcedure
*proc
, double timeOffset
)
960 PollProcedure
*pp
, *prev
;
962 proc
->nextTime
= Sys_FloatTime() + timeOffset
;
963 for (pp
= pollProcedureList
, prev
= NULL
; pp
; pp
= pp
->next
)
965 if (pp
->nextTime
>= proc
->nextTime
)
972 proc
->next
= pollProcedureList
;
973 pollProcedureList
= proc
;
983 #define IDNET 0xc0f62800
985 qboolean
IsID(struct qsockaddr
*addr
)
987 if (idgods
.value
== 0.0)
990 if (addr
->sa_family
!= 2)
993 if ((BigLong(*(int *)&addr
->sa_data
[2]) & 0xffffff00) == IDNET
)